Introduce new extension point for changeset description

This new extension point will only be rendered when the old extension
point is not bound.
This commit is contained in:
René Pfeuffer
2020-06-30 18:11:23 +02:00
parent f62683e528
commit 53993cfee7
8 changed files with 141 additions and 30 deletions

View File

@@ -24,10 +24,10 @@
import React, { FC, ReactNode } from "react";
import textSplitAndReplace from "./textSplitAndReplace";
type Replacement = {
export type Replacement = {
textToReplace: string;
replacement: ReactNode;
replaceAll: boolean;
replaceAll?: boolean;
};
type Props = {

View File

@@ -218,6 +218,54 @@ const four: Changeset = {
}
};
const five: Changeset = {
id: "d21cc6c359270aef2196796f4d96af65f51866dc",
author: { mail: "scm-admin@scm-manager.org", name: "SCM Administrator" },
date: new Date("2020-06-09T05:39:50Z"),
description: "HOG-42 Change mail to arthur@guide.galaxy\n\n",
_links: {
self: {
href:
"http://localhost:8081/scm/api/v2/repositories/hitchhiker/heart-of-gold/changesets/d21cc6c359270aef2196796f4d96af65f51866dc"
},
diff: {
href:
"http://localhost:8081/scm/api/v2/repositories/hitchhiker/heart-of-gold/diff/d21cc6c359270aef2196796f4d96af65f51866dc"
},
sources: {
href:
"http://localhost:8081/scm/api/v2/repositories/hitchhiker/heart-of-gold/sources/d21cc6c359270aef2196796f4d96af65f51866dc"
},
modifications: {
href:
"http://localhost:8081/scm/api/v2/repositories/hitchhiker/heart-of-gold/modifications/d21cc6c359270aef2196796f4d96af65f51866dc"
},
diffParsed: {
href:
"http://localhost:8081/scm/api/v2/repositories/hitchhiker/heart-of-gold/diff/d21cc6c359270aef2196796f4d96af65f51866dc/parsed"
}
},
_embedded: {
tags: [],
branches: [],
parents: [
{
id: "e163c8f632db571c9aa51a8eb440e37cf550b825",
_links: {
self: {
href:
"http://localhost:8081/scm/api/v2/repositories/hitchhiker/heart-of-gold/changesets/e163c8f632db571c9aa51a8eb440e37cf550b825"
},
diff: {
href:
"http://localhost:8081/scm/api/v2/repositories/hitchhiker/heart-of-gold/diff/e163c8f632db571c9aa51a8eb440e37cf550b825"
}
}
}
]
}
};
const changesets: PagedCollection = {
page: 0,
pageTotal: 1,
@@ -246,5 +294,5 @@ const changesets: PagedCollection = {
}
};
export { one, two, three, four };
export { one, two, three, four, five };
export default changesets;

View File

@@ -78,6 +78,7 @@ export { default as CardColumnGroup } from "./CardColumnGroup";
export { default as CardColumn } from "./CardColumn";
export { default as CardColumnSmall } from "./CardColumnSmall";
export { default as CommaSeparatedList } from "./CommaSeparatedList";
export { default as SplitAndReplace, Replacement } from "./SplitAndReplace";
export { default as comparators } from "./comparators";

View File

@@ -0,0 +1,45 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import React, { FC } from "react";
import { Changeset } from "@scm-manager/ui-types";
import { useBinder } from "@scm-manager/ui-extensions";
import { SplitAndReplace, Replacement } from "@scm-manager/ui-components";
type Props = {
changeset: Changeset;
value: string;
};
const ChangesetDescription: FC<Props> = ({ changeset, value }) => {
const binder = useBinder();
const replacements: Replacement[][] = binder.getExtensions("changeset.description.tokens", {
changeset,
value
});
return <SplitAndReplace text={value} replacements={replacements.flatMap(r => r)} />;
};
export default ChangesetDescription;

View File

@@ -34,6 +34,7 @@ import ChangesetId from "./ChangesetId";
import ChangesetAuthor from "./ChangesetAuthor";
import ChangesetTags from "./ChangesetTags";
import ChangesetButtonGroup from "./ChangesetButtonGroup";
import ChangesetDescription from "./ChangesetDescription";
type Props = WithTranslation & {
repository: Repository;
@@ -100,7 +101,7 @@ class ChangesetRow extends React.Component<Props> {
<AvatarWrapper>
<AvatarFigure className="media-left">
<FixedSizedAvatar className="image">
<AvatarImage person={changeset.author} />
<AvatarImage person={changeset.author}/>
</FixedSizedAvatar>
</AvatarFigure>
</AvatarWrapper>
@@ -114,28 +115,28 @@ class ChangesetRow extends React.Component<Props> {
}}
renderAll={false}
>
{description.title}
<ChangesetDescription changeset={changeset} value={description.title} />
</ExtensionPoint>
</h4>
<p className="is-hidden-touch">
<Trans i18nKey="repos:changeset.summary" components={[changesetId, dateFromNow]} />
<Trans i18nKey="repos:changeset.summary" components={[changesetId, dateFromNow]}/>
</p>
<p className="is-hidden-desktop">
<Trans i18nKey="repos:changeset.shortSummary" components={[changesetId, dateFromNow]} />
<Trans i18nKey="repos:changeset.shortSummary" components={[changesetId, dateFromNow]}/>
</p>
<AuthorWrapper className="is-size-7 is-ellipsis-overflow">
<ChangesetAuthor changeset={changeset} />
<ChangesetAuthor changeset={changeset}/>
</AuthorWrapper>
</Metadata>
</div>
</div>
<VCenteredColumn className="column">
<ChangesetTags changeset={changeset} />
<ChangesetTags changeset={changeset}/>
</VCenteredColumn>
</div>
</div>
<VCenteredChildColumn className={classNames("column", "is-flex")}>
<ChangesetButtonGroup repository={repository} changeset={changeset} />
<ChangesetButtonGroup repository={repository} changeset={changeset}/>
<ExtensionPoint
name="changeset.right"
props={{

View File

@@ -28,12 +28,13 @@ import styled from "styled-components";
import { MemoryRouter } from "react-router-dom";
import repository from "../../__resources__/repository";
import ChangesetRow from "./ChangesetRow";
import {one, two, three, four} from "../../__resources__/changesets";
import {Binder, BinderContext} from "@scm-manager/ui-extensions";
import { one, two, three, four, five } from "../../__resources__/changesets";
import { Binder, BinderContext } from "@scm-manager/ui-extensions";
// @ts-ignore
import hitchhiker from "../../__resources__/hitchhiker.png";
import {Person} from "../../avatar/Avatar";
import {Changeset} from "@scm-manager/ui-types/src";
import { Person } from "../../avatar/Avatar";
import { Changeset } from "@scm-manager/ui-types";
import { Replacement } from "../../SplitAndReplace";
const Wrapper = styled.div`
margin: 2rem;
@@ -41,7 +42,7 @@ const Wrapper = styled.div`
const robohash = (person: Person) => {
return `https://robohash.org/${person.mail}`;
}
};
const withAvatarFactory = (factory: (person: Person) => string, changeset: Changeset) => {
const binder = new Binder("changeset stories");
@@ -53,21 +54,23 @@ const withAvatarFactory = (factory: (person: Person) => string, changeset: Chang
);
};
const withReplacements = (replacements: Replacement[][], changeset: Changeset) => {
const binder = new Binder("changeset stories");
replacements.forEach(replacement => binder.bind("changeset.description.tokens", replacement));
return (
<BinderContext.Provider value={binder}>
<ChangesetRow repository={repository} changeset={changeset} />
</BinderContext.Provider>
);
};
storiesOf("Changesets", module)
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
.addDecorator(storyFn => <Wrapper className="box box-link-shadow">{storyFn()}</Wrapper>)
.add("Default", () => (
<ChangesetRow repository={repository} changeset={three} />
))
.add("With Committer", () => (
<ChangesetRow repository={repository} changeset={two} />
))
.add("With Committer and Co-Author", () => (
<ChangesetRow repository={repository} changeset={one} />
))
.add("With multiple Co-Authors", () => (
<ChangesetRow repository={repository} changeset={four} />
))
.add("Default", () => <ChangesetRow repository={repository} changeset={three} />)
.add("With Committer", () => <ChangesetRow repository={repository} changeset={two} />)
.add("With Committer and Co-Author", () => <ChangesetRow repository={repository} changeset={one} />)
.add("With multiple Co-Authors", () => <ChangesetRow repository={repository} changeset={four} />)
.add("With avatar", () => {
return withAvatarFactory(person => hitchhiker, three);
})
@@ -76,4 +79,15 @@ storiesOf("Changesets", module)
})
.add("Co-Authors with avatar", () => {
return withAvatarFactory(robohash, four);
})
.add("Replacements", () => {
const link = <a href={"http://example.com/hog"}>HOG-42</a>;
const mail = <a href={"mailto:hog@example.com"}>Arthur</a>;
return withReplacements(
[
[{ textToReplace: "HOG-42", replacement: link }],
[{ textToReplace: "arthur@guide.galaxy", replacement: mail }]
],
five
);
});

View File

@@ -27,6 +27,7 @@ export { changesets };
export { default as ChangesetAuthor, SingleContributor } from "./ChangesetAuthor";
export { default as ChangesetButtonGroup } from "./ChangesetButtonGroup";
export { default as ChangesetDescription } from "./ChangesetDescription";
export { default as ChangesetDiff } from "./ChangesetDiff";
export { default as ChangesetId } from "./ChangesetId";
export { default as ChangesetList } from "./ChangesetList";