diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/HalAppender.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/HalAppender.java index a7beaf1f6e..6afb542646 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/HalAppender.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/HalAppender.java @@ -27,7 +27,7 @@ public interface HalAppender { LinkArrayBuilder linkArrayBuilder(String rel); /** - * Appends one embedded to the json response. + * Appends one embedded object to the json response. * * @param rel name of relation * @param embeddedItem embedded object @@ -40,7 +40,7 @@ public interface HalAppender { interface LinkArrayBuilder { /** - * Append an link to the array. + * Append a link to the array. * * @param name name of link * @param href link target diff --git a/scm-ui-components/packages/ui-components/src/DateFromNow.js b/scm-ui-components/packages/ui-components/src/DateFromNow.js index b47de49a3d..be15bcdad2 100644 --- a/scm-ui-components/packages/ui-components/src/DateFromNow.js +++ b/scm-ui-components/packages/ui-components/src/DateFromNow.js @@ -2,31 +2,40 @@ import React from "react"; import moment from "moment"; import { translate } from "react-i18next"; +import injectSheet from "react-jss"; + +const styles = { + date: { + borderBottom: "1px dotted rgba(219, 219, 219)", + cursor: "help" + } +}; type Props = { date?: string, // context props + classes: any, i18n: any }; class DateFromNow extends React.Component { - static format(locale: string, date?: string) { - let fromNow = ""; - if (date) { - fromNow = moment(date) - .locale(locale) - .fromNow(); - } - return fromNow; - } render() { - const { i18n, date } = this.props; + const { i18n, date, classes } = this.props; - const fromNow = DateFromNow.format(i18n.language, date); - return {fromNow}; + if (date) { + const dateWithLocale = moment(date).locale(i18n.language); + + return ( + + ); + } + + return null; } } -export default translate()(DateFromNow); +export default injectSheet(styles)(translate()(DateFromNow)); diff --git a/scm-ui-components/packages/ui-components/src/Tooltip.js b/scm-ui-components/packages/ui-components/src/Tooltip.js index d935b323c7..cecb8d349b 100644 --- a/scm-ui-components/packages/ui-components/src/Tooltip.js +++ b/scm-ui-components/packages/ui-components/src/Tooltip.js @@ -4,21 +4,27 @@ import classNames from "classnames"; type Props = { message: string, - className: string, + className?: string, + location: string, children: React.Node }; class Tooltip extends React.Component { + + static defaultProps = { + location: "right" + }; + render() { - const { className, message, children } = this.props; + const { className, message, location, children } = this.props; const multiline = message.length > 60 ? "is-tooltip-multiline" : ""; return ( -
{children} -
+ ); } } diff --git a/scm-ui-components/packages/ui-components/src/buttons/Button.js b/scm-ui-components/packages/ui-components/src/buttons/Button.js index 4ad88f4eac..2102bb540a 100644 --- a/scm-ui-components/packages/ui-components/src/buttons/Button.js +++ b/scm-ui-components/packages/ui-components/src/buttons/Button.js @@ -1,16 +1,17 @@ //@flow -import React from "react"; +import * as React from "react"; import classNames from "classnames"; import { withRouter } from "react-router-dom"; export type ButtonProps = { - label: string, + label?: string, loading?: boolean, disabled?: boolean, action?: (event: Event) => void, link?: string, fullWidth?: boolean, className?: string, + children?: React.Node, classes: any }; @@ -45,6 +46,7 @@ class Button extends React.Component { type, color, fullWidth, + children, className } = this.props; const loadingClass = loading ? "is-loading" : ""; @@ -62,7 +64,7 @@ class Button extends React.Component { className )} > - {label} + {label} {children} ); }; diff --git a/scm-ui-components/packages/ui-components/src/buttons/ButtonGroup.js b/scm-ui-components/packages/ui-components/src/buttons/ButtonGroup.js index 56ef66522a..fb48a3ba4f 100644 --- a/scm-ui-components/packages/ui-components/src/buttons/ButtonGroup.js +++ b/scm-ui-components/packages/ui-components/src/buttons/ButtonGroup.js @@ -1,41 +1,30 @@ // @flow -import React from "react"; -import Button from "./Button"; +import * as React from "react"; type Props = { - firstlabel: string, - secondlabel: string, - firstAction?: (event: Event) => void, - secondAction?: (event: Event) => void, - firstIsSelected: boolean + addons?: boolean, + className?: string, + children: React.Node }; class ButtonGroup extends React.Component { + static defaultProps = { + addons: true + }; + render() { - const { firstlabel, secondlabel, firstAction, secondAction, firstIsSelected } = this.props; - - let showFirstColor = ""; - let showSecondColor = ""; - - if (firstIsSelected) { - showFirstColor += "link is-selected"; - } else { - showSecondColor += "link is-selected"; + const { addons, className, children } = this.props; + let styleClasses = "buttons"; + if (addons) { + styleClasses += " has-addons"; + } + if (className) { + styleClasses += " " + className; } - return ( -
- + + + ); + } + +} + +export default translate("repos")(ChangesetButtonGroup); diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetDiff.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetDiff.js index 232b0e3577..d5d3c4e665 100644 --- a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetDiff.js +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetDiff.js @@ -25,7 +25,7 @@ class ChangesetDiff extends React.Component { render() { const { changeset, t } = this.props; if (!this.isDiffSupported(changeset)) { - return {t("changesets.changeset.diffNotSupported")}; + return {t("changeset.diffNotSupported")}; } else { const url = this.createUrl(changeset); return ; diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetId.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetId.js index aec1029427..a3cc3c73b7 100644 --- a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetId.js +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetId.js @@ -3,6 +3,7 @@ import {Link} from "react-router-dom"; import React from "react"; import type {Changeset, Repository} from "@scm-manager/ui-types"; +import { createChangesetLink } from "./changesets"; type Props = { repository: Repository, @@ -20,13 +21,11 @@ export default class ChangesetId extends React.Component { }; renderLink = () => { - const { changeset, repository } = this.props; + const { repository, changeset } = this.props; + const link = createChangesetLink(repository, changeset); + return ( - + {this.shortId(changeset)} ); diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetRow.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetRow.js index 7609bc2171..90a568f615 100644 --- a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetRow.js +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetRow.js @@ -8,21 +8,39 @@ import ChangesetId from "./ChangesetId"; import injectSheet from "react-jss"; import { DateFromNow } from "../.."; import ChangesetAuthor from "./ChangesetAuthor"; -import ChangesetTag from "./ChangesetTag"; - import { parseDescription } from "./changesets"; import { AvatarWrapper, AvatarImage } from "../../avatar"; import { ExtensionPoint } from "@scm-manager/ui-extensions"; +import ChangesetTags from "./ChangesetTags"; +import ChangesetButtonGroup from "./ChangesetButtonGroup"; const styles = { - pointer: { - cursor: "pointer" + changeset: { + // & references parent rule + // have a look at https://cssinjs.org/jss-plugin-nested?v=v10.0.0-alpha.9 + "& + &": { + borderTop: "1px solid rgba(219, 219, 219, 0.5)", + marginTop: "1rem", + paddingTop: "1rem" + } }, - changesetGroup: { - marginBottom: "1em" + avatarFigure: { + marginTop: ".25rem", + marginRight: ".5rem", }, - withOverflow: { - overflow: "auto" + avatarImage: { + height: "35px", + width: "35px" + }, + isVcentered: { + marginTop: "auto", + marginBottom: "auto" + }, + metadata: { + marginLeft: 0 + }, + tag: { + marginTop: ".5rem" } }; @@ -34,74 +52,70 @@ type Props = { }; class ChangesetRow extends React.Component { - createLink = (changeset: Changeset) => { + createChangesetId = (changeset: Changeset) => { const { repository } = this.props; return ; }; - getTags = () => { - const { changeset } = this.props; - return changeset._embedded.tags || []; - }; - render() { - const { changeset, classes } = this.props; - const changesetLink = this.createLink(changeset); - const dateFromNow = ; - const authorLine = ; + const { repository, changeset, classes } = this.props; const description = parseDescription(changeset.description); + const changesetId = this.createChangesetId(changeset); + const dateFromNow = ; return ( -
- -
-
-

- -

-
+
+
+
+ +

+ + {description.title} + +

+ +
+ +
+
+ +
+
+
+
+

+ +

+

+ +

+

+ +

+
+
+
- -
-
-

- - - {description.title} - - -
- -

{" "} -
{authorLine}
+
+ +
- {this.renderTags()} -
+
); } - - renderTags = () => { - const tags = this.getTags(); - if (tags.length > 0) { - return ( -
- {tags.map((tag: Tag) => { - return ; - })} -
- ); - } - return null; - }; } export default injectSheet(styles)(translate("repos")(ChangesetRow)); diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTag.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTag.js index 6a87400d2e..03c73a8e9f 100644 --- a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTag.js +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTag.js @@ -1,32 +1,17 @@ //@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" - } -}; +import ChangesetTagBase from "./ChangesetTagBase"; type Props = { - tag: Tag, - - // context props - classes: Object + tag: Tag }; class ChangesetTag extends React.Component { render() { - const { tag, classes } = this.props; - return ( - - {" "} - {tag.name} - - ); + const { tag } = this.props; + return ; } } -export default injectSheet(styles)(ChangesetTag); +export default ChangesetTag; diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTagBase.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTagBase.js new file mode 100644 index 0000000000..7fc8dabcd2 --- /dev/null +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTagBase.js @@ -0,0 +1,34 @@ +//@flow +import React from "react"; +import injectSheet from "react-jss"; +import classNames from "classnames"; + +const styles = { + tag: { + marginTop: ".5rem" + }, + spacing: { + marginRight: ".25rem" + } +}; + +type Props = { + icon: string, + label: string, + + // context props + classes: Object +}; + +class ChangesetTagBase extends React.Component { + render() { + const { icon, label, classes } = this.props; + return ( + + {label} + + ); + } +} + +export default injectSheet(styles)(ChangesetTagBase); diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTags.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTags.js new file mode 100644 index 0000000000..b8bff8ddd2 --- /dev/null +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTags.js @@ -0,0 +1,31 @@ +//@flow +import React from "react"; +import type { Changeset} from "@scm-manager/ui-types"; +import ChangesetTag from "./ChangesetTag"; +import ChangesetTagsCollapsed from "./ChangesetTagsCollapsed"; + +type Props = { + changeset: Changeset +}; + +class ChangesetTags extends React.Component { + + getTags = () => { + const { changeset } = this.props; + return changeset._embedded.tags || []; + }; + + render() { + const tags = this.getTags(); + + if (tags.length === 1) { + return ; + } else if (tags.length > 1) { + return ; + } else { + return null; + } + } +} + +export default ChangesetTags; diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTagsCollapsed.js b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTagsCollapsed.js new file mode 100644 index 0000000000..50b09d4d65 --- /dev/null +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/ChangesetTagsCollapsed.js @@ -0,0 +1,27 @@ +//@flow +import React from "react"; +import type { Tag } from "@scm-manager/ui-types"; +import ChangesetTagBase from "./ChangesetTagBase"; +import { translate } from "react-i18next"; +import Tooltip from "../../Tooltip"; + +type Props = { + tags: Tag[], + + // context props + t: (string) => string +}; + +class ChangesetTagsCollapsed extends React.Component { + render() { + const { tags, t } = this.props; + const message = tags.map((tag) => tag.name).join(", "); + return ( + + + + ); + } +} + +export default translate("repos")(ChangesetTagsCollapsed); diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/changesets.js b/scm-ui-components/packages/ui-components/src/repos/changesets/changesets.js index f61a89c74b..69227ad75d 100644 --- a/scm-ui-components/packages/ui-components/src/repos/changesets/changesets.js +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/changesets.js @@ -1,9 +1,19 @@ // @flow +import type { Changeset, Repository } from "@scm-manager/ui-types"; + export type Description = { title: string, message: string }; +export function createChangesetLink(repository: Repository, changeset: Changeset) { + return `/repo/${repository.namespace}/${repository.name}/changeset/${changeset.id}`; +} + +export function createSourcesLink(repository: Repository, changeset: Changeset) { + return `/repo/${repository.namespace}/${repository.name}/sources/${changeset.id}`; +} + export function parseDescription(description?: string): Description { const desc = description ? description : ""; const lineBreak = desc.indexOf("\n"); diff --git a/scm-ui-components/packages/ui-components/src/repos/changesets/index.js b/scm-ui-components/packages/ui-components/src/repos/changesets/index.js index 0e7a5e533d..7a07ad8f42 100644 --- a/scm-ui-components/packages/ui-components/src/repos/changesets/index.js +++ b/scm-ui-components/packages/ui-components/src/repos/changesets/index.js @@ -3,8 +3,11 @@ import * as changesets from "./changesets"; export { changesets }; export { default as ChangesetAuthor } from "./ChangesetAuthor"; +export { default as ChangesetButtonGroup } from "./ChangesetButtonGroup"; +export { default as ChangesetDiff } from "./ChangesetDiff"; export { default as ChangesetId } from "./ChangesetId"; export { default as ChangesetList } from "./ChangesetList"; export { default as ChangesetRow } from "./ChangesetRow"; export { default as ChangesetTag } from "./ChangesetTag"; -export { default as ChangesetDiff } from "./ChangesetDiff"; +export { default as ChangesetTags } from "./ChangesetTags"; +export { default as ChangesetTagsCollapsed } from "./ChangesetTagsCollapsed"; diff --git a/scm-ui/package.json b/scm-ui/package.json index bf4e272fb0..2144e50e6c 100644 --- a/scm-ui/package.json +++ b/scm-ui/package.json @@ -17,6 +17,7 @@ "i18next": "^11.4.0", "i18next-browser-languagedetector": "^2.2.2", "i18next-fetch-backend": "^0.1.0", + "jss-nested": "^6.0.1", "moment": "^2.22.2", "node-sass": "^4.9.3", "postcss-easy-import": "^3.0.0", diff --git a/scm-ui/public/locales/de/repos.json b/scm-ui/public/locales/de/repos.json index f10157b4de..922a2b270f 100644 --- a/scm-ui/public/locales/de/repos.json +++ b/scm-ui/public/locales/de/repos.json @@ -42,18 +42,21 @@ "changesets": { "errorTitle": "Fehler", "errorSubtitle": "Changesets konnten nicht abgerufen werden", - "branchSelectorLabel": "Branches", - "changeset": { - "description": "Beschreibung", - "summary": "Changeset {{id}} wurde committet {{time}}", - "diffNotSupported": "Diff des Changesets wird von diesem Repositorytyp nicht unterstützt", - "id": "ID", - "contact": "Kontakt", - "date": "Datum" - }, + "branchSelectorLabel": "Branches" + }, + "changeset": { + "description": "Beschreibung", + "summary": "Changeset {{id}} wurde committet {{time}}", + "shortSummary": "Committet {{id}} {{time}}", + "tags": "Tags", + "diffNotSupported": "Diff des Changesets wird von diesem Repositorytyp nicht unterstützt", "author": { - "name": "Autor", - "mail": "Mail" + "prefix": "Verfasst von", + "mailto": "Mail senden an" + }, + "buttons": { + "details": "Details", + "sources": "Sources" } }, "repositoryForm": { diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index c30eade1a9..bdb0491489 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -42,18 +42,21 @@ "changesets": { "errorTitle": "Error", "errorSubtitle": "Could not fetch changesets", - "branchSelectorLabel": "Branches", - "changeset": { - "description": "Description", - "summary": "Changeset {{id}} was committed {{time}}", - "diffNotSupported": "Diff of changesets is not supported by the type of repository", - "id": "ID", - "contact": "Contact", - "date": "Date" - }, + "branchSelectorLabel": "Branches" + }, + "changeset": { + "description": "Description", + "summary": "Changeset {{id}} was committed {{time}}", + "shortSummary": "Committed {{id}} {{time}}", + "tags": "Tags", + "diffNotSupported": "Diff of changesets is not supported by the type of repository", "author": { - "name": "Author", - "mail": "Mail" + "prefix": "Authored by", + "mailto": "Send mail to" + }, + "buttons": { + "details": "Details", + "sources": "Sources" } }, "repositoryForm": { diff --git a/scm-ui/src/index.js b/scm-ui/src/index.js index 08e3e8a58c..fd09a0b75f 100644 --- a/scm-ui/src/index.js +++ b/scm-ui/src/index.js @@ -17,6 +17,12 @@ import { ConnectedRouter } from "react-router-redux"; import { urls } from "@scm-manager/ui-components"; +import jss from "jss"; +import jssNested from "jss-nested"; + +// setup jss and install required plugins +jss.setup(jssNested()); + // Create a history of your choosing (we're using a browser history in this case) const history: BrowserHistory = createHistory({ basename: urls.contextPath diff --git a/scm-ui/src/repos/components/changesets/ChangesetDetails.js b/scm-ui/src/repos/components/changesets/ChangesetDetails.js index 217b236122..33d63a30d4 100644 --- a/scm-ui/src/repos/components/changesets/ChangesetDetails.js +++ b/scm-ui/src/repos/components/changesets/ChangesetDetails.js @@ -22,6 +22,11 @@ import { ExtensionPoint } from "@scm-manager/ui-extensions"; const styles = { spacing: { marginRight: "1em" + }, + tags: { + "& .tag": { + marginLeft: ".25rem" + } } }; @@ -48,7 +53,7 @@ class ChangesetDetails extends React.Component {

@@ -67,7 +72,7 @@ class ChangesetDetails extends React.Component {

@@ -81,7 +86,7 @@ class ChangesetDetails extends React.Component { return ( @@ -106,10 +111,11 @@ class ChangesetDetails extends React.Component { }; renderTags = () => { + const { classes } = this.props; const tags = this.getTags(); if (tags.length > 0) { return ( -

+
{tags.map((tag: Tag) => { return ; })} diff --git a/scm-ui/src/repos/sources/components/content/FileButtonGroup.js b/scm-ui/src/repos/sources/components/content/FileButtonGroup.js index c56df2e5a1..6318425711 100644 --- a/scm-ui/src/repos/sources/components/content/FileButtonGroup.js +++ b/scm-ui/src/repos/sources/components/content/FileButtonGroup.js @@ -1,7 +1,7 @@ // @flow import React from "react"; import { translate } from "react-i18next"; -import { ButtonGroup } from "@scm-manager/ui-components"; +import { ButtonGroup, Button } from "@scm-manager/ui-components"; type Props = { t: string => string, @@ -18,39 +18,32 @@ class FileButtonGroup extends React.Component { this.props.showHistory(false); }; + color = (selected: boolean) => { + return selected ? "link is-selected" : null; + }; + render() { const { t, historyIsSelected } = this.props; - const sourcesLabel = ( - <> - - - - - {t("sources.content.sourcesButton")} - - - ); - - const historyLabel = ( - <> - - - - - {t("sources.content.historyButton")} - - - ); - return ( - + + + + ); } }