move changesets and avatar components to ui-components

This commit is contained in:
Sebastian Sdorra
2018-12-10 08:45:59 +01:00
parent 8d622f548d
commit 97c4b0998b
18 changed files with 74 additions and 47 deletions

View File

@@ -1,32 +0,0 @@
//@flow
import React from "react";
import {binder} from "@scm-manager/ui-extensions";
import type {Changeset} from "@scm-manager/ui-types";
import {Image} from "@scm-manager/ui-components";
type Props = {
changeset: Changeset
};
class AvatarImage extends React.Component<Props> {
render() {
const { changeset } = this.props;
const avatarFactory = binder.getExtension("changeset.avatar-factory");
if (avatarFactory) {
const avatar = avatarFactory(changeset);
return (
<Image
className="has-rounded-border"
src={avatar}
alt={changeset.author.name}
/>
);
}
return null;
}
}
export default AvatarImage;

View File

@@ -1,18 +0,0 @@
//@flow
import * as React from "react";
import {binder} from "@scm-manager/ui-extensions";
type Props = {
children: React.Node
};
class AvatarWrapper extends React.Component<Props> {
render() {
if (binder.hasExtension("changeset.avatar-factory")) {
return <>{this.props.children}</>;
}
return null;
}
}
export default AvatarWrapper;

View File

@@ -1,37 +0,0 @@
//@flow
import React from "react";
import type { Changeset } from "@scm-manager/ui-types";
type Props = {
changeset: Changeset
};
export default class ChangesetAuthor extends React.Component<Props> {
render() {
const { changeset } = this.props;
if (!changeset.author) {
return null;
}
const { name } = changeset.author;
return (
<>
{name} {this.renderMail()}
</>
);
}
renderMail() {
const { mail } = this.props.changeset.author;
if (mail) {
return (
<a className="is-hidden-mobile" href={"mailto:" + mail}>
&lt;
{mail}
&gt;
</a>
);
}
}
}

View File

@@ -3,14 +3,18 @@ import React from "react";
import type { Changeset, Repository } from "@scm-manager/ui-types";
import { Interpolate, translate } from "react-i18next";
import injectSheet from "react-jss";
import ChangesetTag from "./ChangesetTag";
import ChangesetAuthor from "./ChangesetAuthor";
import { parseDescription } from "./changesets";
import { DateFromNow } from "@scm-manager/ui-components";
import AvatarWrapper from "./AvatarWrapper";
import AvatarImage from "./AvatarImage";
import {
DateFromNow,
ChangesetId,
ChangesetTag,
ChangesetAuthor,
AvatarWrapper,
AvatarImage,
changesets
} from "@scm-manager/ui-components";
import classNames from "classnames";
import ChangesetId from "./ChangesetId";
import type { Tag } from "@scm-manager/ui-types";
import ScmDiff from "../../containers/ScmDiff";
@@ -31,12 +35,12 @@ class ChangesetDetails extends React.Component<Props> {
render() {
const { changeset, repository, classes } = this.props;
const description = parseDescription(changeset.description);
const description = changesets.parseDescription(changeset.description);
const id = (
<ChangesetId repository={repository} changeset={changeset} link={false} />
<ChangesetId repository={repository} changeset={changeset} link={false}/>
);
const date = <DateFromNow date={changeset.date} />;
const date = <DateFromNow date={changeset.date}/>;
return (
<div>
@@ -45,12 +49,12 @@ class ChangesetDetails extends React.Component<Props> {
<article className="media">
<AvatarWrapper>
<p className={classNames("image", "is-64x64", classes.spacing)}>
<AvatarImage changeset={changeset} />
<AvatarImage changeset={changeset}/>
</p>
</AvatarWrapper>
<div className="media-content">
<p>
<ChangesetAuthor changeset={changeset} />
<ChangesetAuthor changeset={changeset}/>
</p>
<p>
<Interpolate
@@ -67,14 +71,14 @@ class ChangesetDetails extends React.Component<Props> {
return (
<span key={key}>
{item}
<br />
<br/>
</span>
);
})}
</p>
</div>
<div>
<ScmDiff changeset={changeset} sideBySide={false} />
<ScmDiff changeset={changeset} sideBySide={false}/>
</div>
</div>
);
@@ -91,7 +95,7 @@ class ChangesetDetails extends React.Component<Props> {
return (
<div className="level-item">
{tags.map((tag: Tag) => {
return <ChangesetTag key={tag.name} tag={tag} />;
return <ChangesetTag key={tag.name} tag={tag}/>;
})}
</div>
);

View File

@@ -1,47 +0,0 @@
//@flow
import {Link} from "react-router-dom";
import React from "react";
import type {Changeset, Repository} from "@scm-manager/ui-types";
type Props = {
repository: Repository,
changeset: Changeset,
link: boolean
};
export default class ChangesetId extends React.Component<Props> {
static defaultProps = {
link: true
};
shortId = (changeset: Changeset) => {
return changeset.id.substr(0, 7);
};
renderLink = () => {
const { changeset, repository } = this.props;
return (
<Link
to={`/repo/${repository.namespace}/${repository.name}/changeset/${
changeset.id
}`}
>
{this.shortId(changeset)}
</Link>
);
};
renderText = () => {
const { changeset } = this.props;
return this.shortId(changeset);
};
render() {
const { link } = this.props;
if (link) {
return this.renderLink();
}
return this.renderText();
}
}

View File

@@ -1,28 +0,0 @@
// @flow
import ChangesetRow from "./ChangesetRow";
import React from "react";
import type { Changeset, Repository } from "@scm-manager/ui-types";
import classNames from "classnames";
type Props = {
repository: Repository,
changesets: Changeset[]
};
class ChangesetList extends React.Component<Props> {
render() {
const { repository, changesets } = this.props;
const content = changesets.map(changeset => {
return (
<ChangesetRow
key={changeset.id}
repository={repository}
changeset={changeset}
/>
);
});
return <div className={classNames("box")}>{content}</div>;
}
}
export default ChangesetList;

View File

@@ -1,101 +0,0 @@
//@flow
import React from "react";
import type {Changeset, Repository, Tag} from "@scm-manager/ui-types";
import classNames from "classnames";
import {Interpolate, translate} from "react-i18next";
import ChangesetId from "./ChangesetId";
import injectSheet from "react-jss";
import {DateFromNow} from "@scm-manager/ui-components";
import ChangesetAuthor from "./ChangesetAuthor";
import ChangesetTag from "./ChangesetTag";
import {compose} from "redux";
import {parseDescription} from "./changesets";
import AvatarWrapper from "./AvatarWrapper";
import AvatarImage from "./AvatarImage";
const styles = {
pointer: {
cursor: "pointer"
},
changesetGroup: {
marginBottom: "1em"
},
withOverflow: {
overflow: "auto"
}
};
type Props = {
repository: Repository,
changeset: Changeset,
t: any,
classes: any
};
class ChangesetRow extends React.Component<Props> {
createLink = (changeset: Changeset) => {
const { repository } = this.props;
return <ChangesetId changeset={changeset} repository={repository} />;
};
getTags = () => {
const { changeset } = this.props;
return changeset._embedded.tags || [];
};
render() {
const { changeset, classes } = this.props;
const changesetLink = this.createLink(changeset);
const dateFromNow = <DateFromNow date={changeset.date} />;
const authorLine = <ChangesetAuthor changeset={changeset} />;
const description = parseDescription(changeset.description);
return (
<article className={classNames("media", classes.inner)}>
<AvatarWrapper>
<div>
<figure className="media-left">
<p className="image is-64x64">
<AvatarImage changeset={changeset} />
</p>
</figure>
</div>
</AvatarWrapper>
<div className={classNames("media-content", classes.withOverflow)}>
<div className="content">
<p className="is-ellipsis-overflow">
<strong>{description.title}</strong>
<br />
<Interpolate
i18nKey="changesets.changeset.summary"
id={changesetLink}
time={dateFromNow}
/>
</p>{" "}
<div className="is-size-7">{authorLine}</div>
</div>
</div>
{this.renderTags()}
</article>
);
}
renderTags = () => {
const tags = this.getTags();
if (tags.length > 0) {
return (
<div className="media-right">
{tags.map((tag: Tag) => {
return <ChangesetTag key={tag.name} tag={tag} />;
})}
</div>
);
}
return null;
};
}
export default compose(
injectSheet(styles),
translate("repos")
)(ChangesetRow);

View File

@@ -1,32 +0,0 @@
//@flow
import React from "react";
import type { Tag } from "@scm-manager/ui-types";
import injectSheet from "react-jss";
import classNames from "classnames";
const styles = {
spacing: {
marginRight: "4px"
}
};
type Props = {
tag: Tag,
// context props
classes: Object
};
class ChangesetTag extends React.Component<Props> {
render() {
const { tag, classes } = this.props;
return (
<span className="tag is-info">
<span className={classNames("fa", "fa-tag", classes.spacing)} />{" "}
{tag.name}
</span>
);
}
}
export default injectSheet(styles)(ChangesetTag);

View File

@@ -1,25 +0,0 @@
// @flow
export type Description = {
title: string,
message: string
};
export function parseDescription(description?: string): Description {
const desc = description ? description : "";
const lineBreak = desc.indexOf("\n");
let title;
let message = "";
if (lineBreak > 0) {
title = desc.substring(0, lineBreak);
message = desc.substring(lineBreak + 1);
} else {
title = desc;
}
return {
title,
message
};
}

View File

@@ -1,22 +0,0 @@
// @flow
import {parseDescription} from "./changesets";
describe("parseDescription tests", () => {
it("should return a description with title and message", () => {
const desc = parseDescription("Hello\nTrillian");
expect(desc.title).toBe("Hello");
expect(desc.message).toBe("Trillian");
});
it("should return a description with title and without message", () => {
const desc = parseDescription("Hello Trillian");
expect(desc.title).toBe("Hello Trillian");
});
it("should return an empty description for undefined", () => {
const desc = parseDescription();
expect(desc.title).toBe("");
expect(desc.message).toBe("");
});
});