diff --git a/scm-ui-components/packages/ui-components/src/Image.js b/scm-ui-components/packages/ui-components/src/Image.js index d46a32217f..f5760277e4 100644 --- a/scm-ui-components/packages/ui-components/src/Image.js +++ b/scm-ui-components/packages/ui-components/src/Image.js @@ -1,6 +1,6 @@ //@flow import React from "react"; -import { withContextPath } from "./urls"; +import {withContextPath} from "./urls"; type Props = { src: string, @@ -9,9 +9,18 @@ type Props = { }; class Image extends React.Component { + + createImageSrc = () => { + const { src } = this.props; + if (src.startsWith("http")) { + return src; + } + return withContextPath(src); + }; + render() { - const { src, alt, className } = this.props; - return {alt}; + const { alt, className } = this.props; + return {alt}; } } diff --git a/scm-ui-components/packages/ui-components/src/navigation/NavLink.js b/scm-ui-components/packages/ui-components/src/navigation/NavLink.js index 20a7f2469f..9a7c72adb1 100644 --- a/scm-ui-components/packages/ui-components/src/navigation/NavLink.js +++ b/scm-ui-components/packages/ui-components/src/navigation/NavLink.js @@ -1,6 +1,6 @@ //@flow import * as React from "react"; -import { Route, Link } from "react-router-dom"; +import {Link, Route} from "react-router-dom"; // TODO mostly copy of PrimaryNavigationLink diff --git a/scm-ui-components/packages/ui-components/src/urls.js b/scm-ui-components/packages/ui-components/src/urls.js index 543519f952..dd8888d7a3 100644 --- a/scm-ui-components/packages/ui-components/src/urls.js +++ b/scm-ui-components/packages/ui-components/src/urls.js @@ -5,6 +5,21 @@ export function withContextPath(path: string) { return contextPath + path; } +export function withEndingSlash(url: string) { + if (url.endsWith("/")) { + return url; + } + return url + "/"; +} + +export function concat(base: string, ...parts: string[]) { + let url = base; + for ( let p of parts) { + url = withEndingSlash(url) + p; + } + return url; +} + export function getPageFromMatch(match: any) { let page = parseInt(match.params.page, 10); if (isNaN(page) || !page) { diff --git a/scm-ui-components/packages/ui-components/src/urls.test.js b/scm-ui-components/packages/ui-components/src/urls.test.js index 61803f213f..60f27510b8 100644 --- a/scm-ui-components/packages/ui-components/src/urls.test.js +++ b/scm-ui-components/packages/ui-components/src/urls.test.js @@ -1,5 +1,27 @@ // @flow -import { getPageFromMatch } from "./urls"; +import {concat, getPageFromMatch, withEndingSlash} from "./urls"; + +describe("tests for withEndingSlash", () => { + + it("should append missing slash", () => { + expect(withEndingSlash("abc")).toBe("abc/"); + }); + + it("should not append a second slash", () => { + expect(withEndingSlash("abc/")).toBe("abc/"); + }); + +}); + +describe("concat tests", () => { + + it("should concat the parts to a single url", () => { + expect(concat("a")).toBe("a"); + expect(concat("a", "b")).toBe("a/b"); + expect(concat("a", "b", "c")).toBe("a/b/c"); + }); + +}); describe("tests for getPageFromMatch", () => { function createMatch(page: string) { diff --git a/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js b/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js index ceb5fe135e..4352c21da6 100644 --- a/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js +++ b/scm-ui-components/packages/ui-types/src/RepositoryPermissions.js @@ -1,14 +1,11 @@ //@flow -import type { Links } from "./hal"; +import type {Links} from "./hal"; -export type Permission = { - name: string, - type: string, - groupPermission: boolean, - _links?: Links +export type Permission = PermissionCreateEntry & { + _links: Links }; -export type PermissionEntry = { +export type PermissionCreateEntry = { name: string, type: string, groupPermission: boolean diff --git a/scm-ui-components/packages/ui-types/src/index.js b/scm-ui-components/packages/ui-types/src/index.js index ccad0e8597..98a6ead283 100644 --- a/scm-ui-components/packages/ui-types/src/index.js +++ b/scm-ui-components/packages/ui-types/src/index.js @@ -17,4 +17,4 @@ export type { Tag } from "./Tags"; export type { Config } from "./Config"; -export type { Permission, PermissionEntry, PermissionCollection } from "./RepositoryPermissions"; +export type { Permission, PermissionCreateEntry, PermissionCollection } from "./RepositoryPermissions"; diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index 28c94f63e3..c9dcc84815 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -53,7 +53,7 @@ "description": "Description", "contact": "Contact", "date": "Date", - "summary": "Changeset {{id}} committed {{time}}" + "summary": "Changeset {{id}} was committed {{time}}" }, "author": { "name": "Author", diff --git a/scm-ui/src/repos/components/changesets/AvatarImage.js b/scm-ui/src/repos/components/changesets/AvatarImage.js new file mode 100644 index 0000000000..6d730e87cd --- /dev/null +++ b/scm-ui/src/repos/components/changesets/AvatarImage.js @@ -0,0 +1,32 @@ +//@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 { + render() { + const { changeset } = this.props; + + const avatarFactory = binder.getExtension("changeset.avatar-factory"); + if (avatarFactory) { + const avatar = avatarFactory(changeset); + + return ( + {changeset.author.name} + ); + } + + return null; + } +} + +export default AvatarImage; diff --git a/scm-ui/src/repos/components/changesets/AvatarWrapper.js b/scm-ui/src/repos/components/changesets/AvatarWrapper.js new file mode 100644 index 0000000000..c014b33281 --- /dev/null +++ b/scm-ui/src/repos/components/changesets/AvatarWrapper.js @@ -0,0 +1,18 @@ +//@flow +import * as React from "react"; +import {binder} from "@scm-manager/ui-extensions"; + +type Props = { + children: React.Node +}; + +class AvatarWrapper extends React.Component { + render() { + if (binder.hasExtension("changeset.avatar-factory")) { + return <>{this.props.children}; + } + return null; + } +} + +export default AvatarWrapper; diff --git a/scm-ui/src/repos/components/changesets/ChangesetAvatar.js b/scm-ui/src/repos/components/changesets/ChangesetAvatar.js deleted file mode 100644 index 90f116daed..0000000000 --- a/scm-ui/src/repos/components/changesets/ChangesetAvatar.js +++ /dev/null @@ -1,30 +0,0 @@ -//@flow -import React from "react"; -import { ExtensionPoint } from "@scm-manager/ui-extensions"; -import type { Changeset } from "@scm-manager/ui-types"; - -type Props = { - changeset: Changeset -}; - -class ChangesetAvatar extends React.Component { - render() { - const { changeset } = this.props; - return ( - - {/* extension should render something like this: */} - {/*
*/} - {/*
*/} - {/* Logo */} - {/*
*/} - {/*
*/} -
- ); - } -} - -export default ChangesetAvatar; diff --git a/scm-ui/src/repos/components/changesets/ChangesetDetails.js b/scm-ui/src/repos/components/changesets/ChangesetDetails.js new file mode 100644 index 0000000000..b93c72805b --- /dev/null +++ b/scm-ui/src/repos/components/changesets/ChangesetDetails.js @@ -0,0 +1,97 @@ +//@flow +import React from "react"; +import type {Changeset, Repository} from "../../../../../scm-ui-components/packages/ui-types/src/index"; +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-ui-components/packages/ui-components/src/index"; +import AvatarWrapper from "./AvatarWrapper"; +import AvatarImage from "./AvatarImage"; +import classNames from "classnames"; +import ChangesetId from "./ChangesetId"; +import type {Tag} from "@scm-manager/ui-types"; + +const styles = { + spacing: { + marginRight: "1em" + } +}; + +type Props = { + changeset: Changeset, + repository: Repository, + t: string => string, + classes: any +}; + +class ChangesetDetails extends React.Component { + render() { + const { changeset, repository, classes } = this.props; + + const description = parseDescription(changeset.description); + + const id = ( + + ); + const date = ; + + return ( +
+

{description.title}

+
+ +

+ +

+
+
+

+ +

+

+ +

+
+
{this.renderTags()}
+
+

+ {description.message.split("\n").map((item, key) => { + return ( + + {item} +
+
+ ); + })} +

+
+ ); + } + + getTags = () => { + const { changeset } = this.props; + return changeset._embedded.tags || []; + }; + + renderTags = () => { + const tags = this.getTags(); + if (tags.length > 0) { + return ( +
+ {tags.map((tag: Tag) => { + return ; + })} +
+ ); + } + return null; + }; +} + +export default injectSheet(styles)(translate("repos")(ChangesetDetails)); diff --git a/scm-ui/src/repos/components/changesets/ChangesetId.js b/scm-ui/src/repos/components/changesets/ChangesetId.js index 7669cd606e..aec1029427 100644 --- a/scm-ui/src/repos/components/changesets/ChangesetId.js +++ b/scm-ui/src/repos/components/changesets/ChangesetId.js @@ -1,25 +1,47 @@ //@flow -import { Link } from "react-router-dom"; +import {Link} from "react-router-dom"; import React from "react"; -import type { Repository, Changeset } from "@scm-manager/ui-types"; +import type {Changeset, Repository} from "@scm-manager/ui-types"; type Props = { repository: Repository, - changeset: Changeset + changeset: Changeset, + link: boolean }; export default class ChangesetId extends React.Component { - render() { - const { repository, changeset } = this.props; + static defaultProps = { + link: true + }; + + shortId = (changeset: Changeset) => { + return changeset.id.substr(0, 7); + }; + + renderLink = () => { + const { changeset, repository } = this.props; return ( - {changeset.id.substr(0, 7)} + {this.shortId(changeset)} ); + }; + + renderText = () => { + const { changeset } = this.props; + return this.shortId(changeset); + }; + + render() { + const { link } = this.props; + if (link) { + return this.renderLink(); + } + return this.renderText(); } } diff --git a/scm-ui/src/repos/components/changesets/ChangesetRow.js b/scm-ui/src/repos/components/changesets/ChangesetRow.js index a1a497ad67..0215abedd1 100644 --- a/scm-ui/src/repos/components/changesets/ChangesetRow.js +++ b/scm-ui/src/repos/components/changesets/ChangesetRow.js @@ -1,15 +1,17 @@ //@flow import React from "react"; -import type { Changeset, Repository, Tag } from "@scm-manager/ui-types"; +import type {Changeset, Repository, Tag} from "@scm-manager/ui-types"; import classNames from "classnames"; -import { translate, Interpolate } from "react-i18next"; -import ChangesetAvatar from "./ChangesetAvatar"; +import {Interpolate, translate} from "react-i18next"; import ChangesetId from "./ChangesetId"; import injectSheet from "react-jss"; -import { DateFromNow } from "@scm-manager/ui-components"; +import {DateFromNow} from "@scm-manager/ui-components"; import ChangesetAuthor from "./ChangesetAuthor"; import ChangesetTag from "./ChangesetTag"; -import { compose } from "redux"; +import {compose} from "redux"; +import {parseDescription} from "./changesets"; +import AvatarWrapper from "./AvatarWrapper"; +import AvatarImage from "./AvatarImage"; const styles = { pointer: { @@ -46,14 +48,23 @@ class ChangesetRow extends React.Component { const changesetLink = this.createLink(changeset); const dateFromNow = ; const authorLine = ; + const description = parseDescription(changeset.description); return (
- + +
+
+

+ +

+
+
+

- {changeset.description} + {description.title}
0) { + title = description.substring(0, lineBreak); + message = description.substring(lineBreak + 1); + } else { + title = description; + } + + return { + title, + message + }; +} diff --git a/scm-ui/src/repos/components/changesets/changesets.test.js b/scm-ui/src/repos/components/changesets/changesets.test.js new file mode 100644 index 0000000000..0c2350af82 --- /dev/null +++ b/scm-ui/src/repos/components/changesets/changesets.test.js @@ -0,0 +1,16 @@ +// @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"); + }); +}); diff --git a/scm-ui/src/repos/containers/ChangesetView.js b/scm-ui/src/repos/containers/ChangesetView.js new file mode 100644 index 0000000000..80ab0b71d6 --- /dev/null +++ b/scm-ui/src/repos/containers/ChangesetView.js @@ -0,0 +1,75 @@ +//@flow +import React from "react"; +import { connect } from "react-redux"; +import { withRouter } from "react-router-dom"; +import type { Changeset, Repository } from "@scm-manager/ui-types"; +import { + fetchChangesetIfNeeded, + getChangeset, + getFetchChangesetFailure, + isFetchChangesetPending +} from "../modules/changesets"; +import ChangesetDetails from "../components/changesets/ChangesetDetails"; +import { translate } from "react-i18next"; +import { ErrorPage, Loading } from "@scm-manager/ui-components"; + +type Props = { + id: string, + changeset: Changeset, + repository: Repository, + loading: boolean, + error: Error, + fetchChangesetIfNeeded: (repository: Repository, id: string) => void, + match: any, + t: string => string +}; + +class ChangesetView extends React.Component { + componentDidMount() { + const { fetchChangesetIfNeeded, repository } = this.props; + const id = this.props.match.params.id; + fetchChangesetIfNeeded(repository, id); + } + + render() { + const { changeset, loading, error, t, repository } = this.props; + + if (error) { + return ( + + ); + } + + if (!changeset || loading) return ; + + return ; + } +} + +const mapStateToProps = (state, ownProps: Props) => { + const repository = ownProps.repository; + const id = ownProps.match.params.id; + const changeset = getChangeset(state, repository, id); + const loading = isFetchChangesetPending(state, repository, id); + const error = getFetchChangesetFailure(state, repository, id); + return { changeset, error, loading }; +}; + +const mapDispatchToProps = dispatch => { + return { + fetchChangesetIfNeeded: (repository: Repository, id: string) => { + dispatch(fetchChangesetIfNeeded(repository, id)); + } + }; +}; + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps + )(translate("changesets")(ChangesetView)) +); diff --git a/scm-ui/src/repos/containers/Changesets.js b/scm-ui/src/repos/containers/Changesets.js index 224df5042a..3d30e9f8be 100644 --- a/scm-ui/src/repos/containers/Changesets.js +++ b/scm-ui/src/repos/containers/Changesets.js @@ -1,13 +1,8 @@ // @flow import React from "react"; -import { withRouter } from "react-router-dom"; -import type { - Branch, - Changeset, - PagedCollection, - Repository -} from "@scm-manager/ui-types"; +import {withRouter} from "react-router-dom"; +import type {Branch, Changeset, PagedCollection, Repository} from "@scm-manager/ui-types"; import { fetchChangesets, getChangesets, @@ -16,15 +11,10 @@ import { selectListAsCollection } from "../modules/changesets"; -import { connect } from "react-redux"; +import {connect} from "react-redux"; import ChangesetList from "../components/changesets/ChangesetList"; -import { - ErrorNotification, - LinkPaginator, - Loading, - getPageFromMatch -} from "@scm-manager/ui-components"; -import { compose } from "redux"; +import {ErrorNotification, getPageFromMatch, LinkPaginator, Loading} from "@scm-manager/ui-components"; +import {compose} from "redux"; type Props = { repository: Repository, diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index 8a5e157c53..99ab55441a 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -1,32 +1,23 @@ //@flow import React from "react"; -import { - deleteRepo, - fetchRepo, - getFetchRepoFailure, - getRepository, - isFetchRepoPending -} from "../modules/repos"; -import { connect } from "react-redux"; -import { Route, Switch } from "react-router-dom"; -import type { Repository } from "@scm-manager/ui-types"; -import { - ErrorPage, - Loading, - Navigation, - NavLink, - Page, - Section -} from "@scm-manager/ui-components"; -import { translate } from "react-i18next"; +import {deleteRepo, fetchRepo, getFetchRepoFailure, getRepository, isFetchRepoPending} from "../modules/repos"; + +import {connect} from "react-redux"; +import {Route, Switch} from "react-router-dom"; +import type {Repository} from "@scm-manager/ui-types"; + +import {ErrorPage, Loading, Navigation, NavLink, Page, Section} from "@scm-manager/ui-components"; +import {translate} from "react-i18next"; import RepositoryDetails from "../components/RepositoryDetails"; import DeleteNavAction from "../components/DeleteNavAction"; import Edit from "../containers/Edit"; import Permissions from "../permissions/containers/Permissions"; -import type { History } from "history"; +import type {History} from "history"; import EditNavLink from "../components/EditNavLink"; + import BranchRoot from "./BranchRoot"; +import ChangesetView from "./ChangesetView"; import PermissionsNavLink from "../components/PermissionsNavLink"; import ScmDiff from "./ScmDiff"; @@ -73,6 +64,11 @@ class RepositoryRoot extends React.Component { this.props.deleteRepo(repository, this.deleted); }; + matchChangeset = (route: any) => { + const url = this.matchedUrl(); + return route.location.pathname.match(`${url}/changeset/`); + }; + matches = (route: any) => { const url = this.matchedUrl(); const regex = new RegExp(`${url}(/branches)?/?[^/]*/changesets?.*`); @@ -120,6 +116,11 @@ class RepositoryRoot extends React.Component { /> )} /> + } + /> ( @@ -145,7 +146,7 @@ class RepositoryRoot extends React.Component { component={() => ( )} diff --git a/scm-ui/src/repos/modules/changesets.js b/scm-ui/src/repos/modules/changesets.js index 1ac83aba0a..80c405f5de 100644 --- a/scm-ui/src/repos/modules/changesets.js +++ b/scm-ui/src/repos/modules/changesets.js @@ -1,27 +1,86 @@ // @flow -import { - FAILURE_SUFFIX, - PENDING_SUFFIX, - SUCCESS_SUFFIX -} from "../../modules/types"; -import { apiClient } from "@scm-manager/ui-components"; -import { isPending } from "../../modules/pending"; -import { getFailure } from "../../modules/failure"; -import type { - Action, - Branch, - PagedCollection, - Repository -} from "@scm-manager/ui-types"; +import {FAILURE_SUFFIX, PENDING_SUFFIX, SUCCESS_SUFFIX} from "../../modules/types"; +import {apiClient, urls} from "@scm-manager/ui-components"; +import {isPending} from "../../modules/pending"; +import {getFailure} from "../../modules/failure"; +import type {Action, Branch, PagedCollection, Repository} from "@scm-manager/ui-types"; export const FETCH_CHANGESETS = "scm/repos/FETCH_CHANGESETS"; export const FETCH_CHANGESETS_PENDING = `${FETCH_CHANGESETS}_${PENDING_SUFFIX}`; export const FETCH_CHANGESETS_SUCCESS = `${FETCH_CHANGESETS}_${SUCCESS_SUFFIX}`; export const FETCH_CHANGESETS_FAILURE = `${FETCH_CHANGESETS}_${FAILURE_SUFFIX}`; -//TODO: Content type +export const FETCH_CHANGESET = "scm/repos/FETCH_CHANGESET"; +export const FETCH_CHANGESET_PENDING = `${FETCH_CHANGESET}_${PENDING_SUFFIX}`; +export const FETCH_CHANGESET_SUCCESS = `${FETCH_CHANGESET}_${SUCCESS_SUFFIX}`; +export const FETCH_CHANGESET_FAILURE = `${FETCH_CHANGESET}_${FAILURE_SUFFIX}`; + // actions +//TODO: Content type + +export function fetchChangesetIfNeeded(repository: Repository, id: string) { + return (dispatch: any, getState: any) => { + if (shouldFetchChangeset(getState(), repository, id)) { + return dispatch(fetchChangeset(repository, id)); + } + }; +} + +export function fetchChangeset(repository: Repository, id: string) { + return function(dispatch: any) { + dispatch(fetchChangesetPending(repository, id)); + return apiClient + .get(createChangesetUrl(repository, id)) + .then(response => response.json()) + .then(data => dispatch(fetchChangesetSuccess(data, repository, id))) + .catch(err => { + dispatch(fetchChangesetFailure(repository, id, err)); + }); + }; +} + +function createChangesetUrl(repository: Repository, id: string) { + return urls.concat(repository._links.changesets.href, id); +} + +export function fetchChangesetPending( + repository: Repository, + id: string +): Action { + return { + type: FETCH_CHANGESET_PENDING, + itemId: createChangesetItemId(repository, id) + }; +} + +export function fetchChangesetSuccess( + changeset: any, + repository: Repository, + id: string +): Action { + return { + type: FETCH_CHANGESET_SUCCESS, + payload: { changeset, repository, id }, + itemId: createChangesetItemId(repository, id) + }; +} + +function fetchChangesetFailure( + repository: Repository, + id: string, + error: Error +): Action { + return { + type: FETCH_CHANGESET_FAILURE, + payload: { + repository, + id, + error + }, + itemId: createChangesetItemId(repository, id) + }; +} export function fetchChangesets( repository: Repository, @@ -80,7 +139,11 @@ export function fetchChangesetsSuccess( ): Action { return { type: FETCH_CHANGESETS_SUCCESS, - payload: changesets, + payload: { + repository, + branch, + changesets + }, itemId: createItemId(repository, branch) }; } @@ -101,6 +164,11 @@ function fetchChangesetsFailure( }; } +function createChangesetItemId(repository: Repository, id: string) { + const { namespace, name } = repository; + return namespace + "/" + name + "/" + id; +} + function createItemId(repository: Repository, branch?: Branch): string { const { namespace, name } = repository; let itemId = namespace + "/" + name; @@ -118,10 +186,32 @@ export default function reducer( if (!action.payload) { return state; } + const payload = action.payload; switch (action.type) { + case FETCH_CHANGESET_SUCCESS: + const _key = createItemId(payload.repository); + + let _oldByIds = {}; + if (state[_key] && state[_key].byId) { + _oldByIds = state[_key].byId; + } + + const changeset = payload.changeset; + + return { + ...state, + [_key]: { + ...state[_key], + byId: { + ..._oldByIds, + [changeset.id]: changeset + } + } + }; + case FETCH_CHANGESETS_SUCCESS: - const changesets = payload._embedded.changesets; + const changesets = payload.changesets._embedded.changesets; const changesetIds = changesets.map(c => c.id); const key = action.itemId; @@ -129,26 +219,32 @@ export default function reducer( return state; } - let oldByIds = {}; - if (state[key] && state[key].byId) { - oldByIds = state[key].byId; + const repoId = createItemId(payload.repository); + + let oldState = {}; + if (state[repoId]) { + oldState = state[repoId]; } + const branchName = payload.branch ? payload.branch.name : ""; const byIds = extractChangesetsByIds(changesets); return { ...state, - [key]: { + [repoId]: { byId: { - ...oldByIds, + ...oldState.byId, ...byIds }, - list: { - entries: changesetIds, - entry: { - page: payload.page, - pageTotal: payload.pageTotal, - _links: payload._links + byBranch: { + ...oldState.byBranch, + [branchName]: { + entries: changesetIds, + entry: { + page: payload.changesets.page, + pageTotal: payload.changesets.pageTotal, + _links: payload.changesets._links + } } } } @@ -174,17 +270,76 @@ export function getChangesets( repository: Repository, branch?: Branch ) { - const key = createItemId(repository, branch); + const repoKey = createItemId(repository); - const changesets = state.changesets[key]; + const stateRoot = state.changesets[repoKey]; + if (!stateRoot || !stateRoot.byBranch) { + return null; + } + + const branchName = branch ? branch.name : ""; + + const changesets = stateRoot.byBranch[branchName]; if (!changesets) { return null; } - return changesets.list.entries.map((id: string) => { - return changesets.byId[id]; + + return changesets.entries.map((id: string) => { + return stateRoot.byId[id]; }); } +export function getChangeset( + state: Object, + repository: Repository, + id: string +) { + const key = createItemId(repository); + const changesets = + state.changesets && state.changesets[key] + ? state.changesets[key].byId + : null; + if (changesets != null && changesets[id]) { + return changesets[id]; + } + return null; +} + +export function shouldFetchChangeset( + state: Object, + repository: Repository, + id: string +) { + if (getChangeset(state, repository, id)) { + return false; + } + return true; +} + +export function isFetchChangesetPending( + state: Object, + repository: Repository, + id: string +) { + return isPending( + state, + FETCH_CHANGESET, + createChangesetItemId(repository, id) + ); +} + +export function getFetchChangesetFailure( + state: Object, + repository: Repository, + id: string +) { + return getFailure( + state, + FETCH_CHANGESET, + createChangesetItemId(repository, id) + ); +} + export function isFetchChangesetsPending( state: Object, repository: Repository, @@ -202,9 +357,15 @@ export function getFetchChangesetsFailure( } const selectList = (state: Object, repository: Repository, branch?: Branch) => { - const itemId = createItemId(repository, branch); - if (state.changesets[itemId] && state.changesets[itemId].list) { - return state.changesets[itemId].list; + const repoId = createItemId(repository); + + const branchName = branch ? branch.name : ""; + if (state.changesets[repoId]) { + const repoState = state.changesets[repoId]; + + if (repoState.byBranch && repoState.byBranch[branchName]) { + return repoState.byBranch[branchName]; + } } return {}; }; diff --git a/scm-ui/src/repos/modules/changesets.test.js b/scm-ui/src/repos/modules/changesets.test.js index 3b0410b635..b903981c80 100644 --- a/scm-ui/src/repos/modules/changesets.test.js +++ b/scm-ui/src/repos/modules/changesets.test.js @@ -4,15 +4,27 @@ import configureMockStore from "redux-mock-store"; import thunk from "redux-thunk"; import fetchMock from "fetch-mock"; import reducer, { + FETCH_CHANGESET, + FETCH_CHANGESET_FAILURE, + FETCH_CHANGESET_PENDING, + FETCH_CHANGESET_SUCCESS, FETCH_CHANGESETS, FETCH_CHANGESETS_FAILURE, FETCH_CHANGESETS_PENDING, FETCH_CHANGESETS_SUCCESS, + fetchChangeset, + fetchChangesetIfNeeded, fetchChangesets, fetchChangesetsSuccess, + fetchChangesetSuccess, + getChangeset, getChangesets, + getFetchChangesetFailure, getFetchChangesetsFailure, - isFetchChangesetsPending + isFetchChangesetPending, + isFetchChangesetsPending, + selectListAsCollection, + shouldFetchChangeset } from "./changesets"; const branch = { @@ -21,7 +33,7 @@ const branch = { _links: { history: { href: - "http://scm/api/rest/v2/repositories/foo/bar/branches/specific/changesets" + "http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets" } } }; @@ -32,14 +44,14 @@ const repository = { type: "GIT", _links: { self: { - href: "http://scm/api/rest/v2/repositories/foo/bar" + href: "http://scm.hitchhicker.com/api/v2/repositories/foo/bar" }, changesets: { - href: "http://scm/api/rest/v2/repositories/foo/bar/changesets" + href: "http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets" }, branches: { href: - "http://scm/api/rest/v2/repositories/foo/bar/branches/specific/branches" + "http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/branches" } } }; @@ -49,9 +61,10 @@ const changesets = {}; describe("changesets", () => { describe("fetching of changesets", () => { const DEFAULT_BRANCH_URL = - "http://scm/api/rest/v2/repositories/foo/bar/changesets"; + "http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets"; const SPECIFIC_BRANCH_URL = - "http://scm/api/rest/v2/repositories/foo/bar/branches/specific/changesets"; + "http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets"; + const mockStore = configureMockStore([thunk]); afterEach(() => { @@ -59,6 +72,102 @@ describe("changesets", () => { fetchMock.restore(); }); + const changesetId = "aba876c0625d90a6aff1494f3d161aaa7008b958"; + + it("should fetch changeset", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, "{}"); + + const expectedActions = [ + { + type: FETCH_CHANGESET_PENDING, + itemId: "foo/bar/" + changesetId + }, + { + type: FETCH_CHANGESET_SUCCESS, + payload: { + changeset: {}, + id: changesetId, + repository: repository + }, + itemId: "foo/bar/" + changesetId + } + ]; + + const store = mockStore({}); + return store + .dispatch(fetchChangeset(repository, changesetId)) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it("should fail fetching changeset on error", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, 500); + + const expectedActions = [ + { + type: FETCH_CHANGESET_PENDING, + itemId: "foo/bar/" + changesetId + } + ]; + + const store = mockStore({}); + return store + .dispatch(fetchChangeset(repository, changesetId)) + .then(() => { + expect(store.getActions()[0]).toEqual(expectedActions[0]); + expect(store.getActions()[1].type).toEqual(FETCH_CHANGESET_FAILURE); + expect(store.getActions()[1].payload).toBeDefined(); + }); + }); + + it("should fetch changeset if needed", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/id3", "{}"); + + const expectedActions = [ + { + type: FETCH_CHANGESET_PENDING, + itemId: "foo/bar/id3" + }, + { + type: FETCH_CHANGESET_SUCCESS, + payload: { + changeset: {}, + id: "id3", + repository: repository + }, + itemId: "foo/bar/id3" + } + ]; + + const store = mockStore({}); + return store + .dispatch(fetchChangesetIfNeeded(repository, "id3")) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it("should not fetch changeset if not needed", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/id1", 500); + + const state = { + changesets: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + }; + + const store = mockStore(state); + return expect( + store.dispatch(fetchChangesetIfNeeded(repository, "id1")) + ).toEqual(undefined); + }); + it("should fetch changesets for default branch", () => { fetchMock.getOnce(DEFAULT_BRANCH_URL, "{}"); @@ -69,7 +178,11 @@ describe("changesets", () => { }, { type: FETCH_CHANGESETS_SUCCESS, - payload: changesets, + payload: { + repository, + undefined, + changesets + }, itemId: "foo/bar" } ]; @@ -91,7 +204,11 @@ describe("changesets", () => { }, { type: FETCH_CHANGESETS_SUCCESS, - payload: changesets, + payload: { + repository, + branch, + changesets + }, itemId } ]; @@ -150,7 +267,11 @@ describe("changesets", () => { }, { type: FETCH_CHANGESETS_SUCCESS, - payload: changesets, + payload: { + repository, + undefined, + changesets + }, itemId: "foo/bar" } ]; @@ -173,7 +294,11 @@ describe("changesets", () => { }, { type: FETCH_CHANGESETS_SUCCESS, - payload: changesets, + payload: { + repository, + branch, + changesets + }, itemId: "foo/bar/specific" } ]; @@ -215,7 +340,7 @@ describe("changesets", () => { ); expect(newState["foo/bar"].byId["changeset2"].description).toEqual("foo"); expect(newState["foo/bar"].byId["changeset3"].description).toEqual("bar"); - expect(newState["foo/bar"].list).toEqual({ + expect(newState["foo/bar"].byBranch[""]).toEqual({ entry: { page: 1, pageTotal: 10, @@ -225,6 +350,20 @@ describe("changesets", () => { }); }); + it("should store the changeset list to branch", () => { + const newState = reducer( + {}, + fetchChangesetsSuccess(repository, branch, responseBody) + ); + + expect(newState["foo/bar"].byId["changeset1"]).toBeDefined(); + expect(newState["foo/bar"].byBranch["specific"].entries).toEqual([ + "changeset1", + "changeset2", + "changeset3" + ]); + }); + it("should not remove existing changesets", () => { const state = { "foo/bar": { @@ -232,8 +371,10 @@ describe("changesets", () => { id2: { id: "id2" }, id1: { id: "id1" } }, - list: { - entries: ["id1", "id2"] + byBranch: { + "": { + entries: ["id1", "id2"] + } } } }; @@ -245,7 +386,7 @@ describe("changesets", () => { const fooBar = newState["foo/bar"]; - expect(fooBar.list.entries).toEqual([ + expect(fooBar.byBranch[""].entries).toEqual([ "changeset1", "changeset2", "changeset3" @@ -253,11 +394,154 @@ describe("changesets", () => { expect(fooBar.byId["id2"]).toEqual({ id: "id2" }); expect(fooBar.byId["id1"]).toEqual({ id: "id1" }); }); + + const responseBodySingleChangeset = { + id: "id3", + author: { + mail: "z@phod.com", + name: "zaphod" + }, + date: "2018-09-13T08:46:22Z", + description: "added testChangeset", + _links: {}, + _embedded: { + tags: [], + branches: [] + } + }; + + it("should add changeset to state", () => { + const newState = reducer( + { + "foo/bar": { + byId: { + "id2": { + id: "id2", + author: { mail: "mail@author.com", name: "author" } + } + }, + list: { + entry: { + page: 1, + pageTotal: 10, + _links: {} + }, + entries: ["id2"] + } + } + }, + fetchChangesetSuccess(responseBodySingleChangeset, repository, "id3") + ); + + expect(newState).toBeDefined(); + expect(newState["foo/bar"].byId["id3"].description).toEqual( + "added testChangeset" + ); + expect(newState["foo/bar"].byId["id3"].author.mail).toEqual("z@phod.com"); + expect(newState["foo/bar"].byId["id2"]).toBeDefined(); + expect(newState["foo/bar"].byId["id3"]).toBeDefined(); + expect(newState["foo/bar"].list).toEqual({ + entry: { + page: 1, + pageTotal: 10, + _links: {} + }, + entries: ["id2"] + }); + }); }); describe("changeset selectors", () => { const error = new Error("Something went wrong"); + it("should return changeset", () => { + const state = { + changesets: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + }; + const result = getChangeset(state, repository, "id1"); + expect(result).toEqual({ id: "id1" }); + }); + + it("should return null if changeset does not exist", () => { + const state = { + changesets: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + }; + const result = getChangeset(state, repository, "id3"); + expect(result).toEqual(null); + }); + + it("should return true if changeset does not exist", () => { + const state = { + changesets: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + }; + const result = shouldFetchChangeset(state, repository, "id3"); + expect(result).toEqual(true); + }); + + it("should return false if changeset exists", () => { + const state = { + changesets: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + }; + const result = shouldFetchChangeset(state, repository, "id2"); + expect(result).toEqual(false); + }); + + it("should return true, when fetching changeset is pending", () => { + const state = { + pending: { + [FETCH_CHANGESET + "/foo/bar/id1"]: true + } + }; + + expect(isFetchChangesetPending(state, repository, "id1")).toBeTruthy(); + }); + + it("should return false, when fetching changeset is not pending", () => { + expect(isFetchChangesetPending({}, repository, "id1")).toEqual(false); + }); + + it("should return error if fetching changeset failed", () => { + const state = { + failure: { + [FETCH_CHANGESET + "/foo/bar/id1"]: error + } + }; + + expect(getFetchChangesetFailure(state, repository, "id1")).toEqual(error); + }); + + it("should return false if fetching changeset did not fail", () => { + expect(getFetchChangesetFailure({}, repository, "id1")).toBeUndefined(); + }); + it("should get all changesets for a given repository", () => { const state = { changesets: { @@ -266,8 +550,10 @@ describe("changesets", () => { id2: { id: "id2" }, id1: { id: "id1" } }, - list: { - entries: ["id1", "id2"] + byBranch: { + "": { + entries: ["id1", "id2"] + } } } } @@ -303,5 +589,32 @@ describe("changesets", () => { it("should return false if fetching changesets did not fail", () => { expect(getFetchChangesetsFailure({}, repository)).toBeUndefined(); }); + + it("should return list as collection for the default branch", () => { + const state = { + changesets: { + "foo/bar": { + byId: { + id2: { id: "id2" }, + id1: { id: "id1" } + }, + byBranch: { + "": { + entry: { + page: 1, + pageTotal: 10, + _links: {} + }, + entries: ["id1", "id2"] + } + } + } + } + }; + + const collection = selectListAsCollection(state, repository); + expect(collection.page).toBe(1); + expect(collection.pageTotal).toBe(10); + }); }); }); diff --git a/scm-ui/src/repos/permissions/components/CreatePermissionForm.js b/scm-ui/src/repos/permissions/components/CreatePermissionForm.js index 595c27d8ef..fac7466a45 100644 --- a/scm-ui/src/repos/permissions/components/CreatePermissionForm.js +++ b/scm-ui/src/repos/permissions/components/CreatePermissionForm.js @@ -1,17 +1,14 @@ // @flow import React from "react"; -import { translate } from "react-i18next"; -import { Checkbox, InputField, SubmitButton } from "@scm-manager/ui-components"; +import {translate} from "react-i18next"; +import {Checkbox, InputField, SubmitButton} from "@scm-manager/ui-components"; import TypeSelector from "./TypeSelector"; -import type { - PermissionCollection, - PermissionEntry -} from "@scm-manager/ui-types"; +import type {PermissionCollection, PermissionCreateEntry} from "@scm-manager/ui-types"; import * as validator from "./permissionValidation"; type Props = { t: string => string, - createPermission: (permission: PermissionEntry) => void, + createPermission: (permission: PermissionCreateEntry) => void, loading: boolean, currentPermissions: PermissionCollection }; @@ -65,7 +62,7 @@ class CreatePermissionForm extends React.Component {

diff --git a/scm-ui/src/repos/permissions/components/permissionValidation.js b/scm-ui/src/repos/permissions/components/permissionValidation.js index b74ae40988..6e581f2832 100644 --- a/scm-ui/src/repos/permissions/components/permissionValidation.js +++ b/scm-ui/src/repos/permissions/components/permissionValidation.js @@ -1,21 +1,31 @@ // @flow -import { validation } from "@scm-manager/ui-components"; -import type { - PermissionCollection, -} from "@scm-manager/ui-types"; +import {validation} from "@scm-manager/ui-components"; +import type {PermissionCollection} from "@scm-manager/ui-types"; + const isNameValid = validation.isNameValid; export { isNameValid }; -export const isPermissionValid = (name: string, groupPermission: boolean, permissions: PermissionCollection) => { - return isNameValid(name) && !currentPermissionIncludeName(name, groupPermission, permissions); +export const isPermissionValid = ( + name: string, + groupPermission: boolean, + permissions: PermissionCollection +) => { + return ( + isNameValid(name) && + !currentPermissionIncludeName(name, groupPermission, permissions) + ); }; -const currentPermissionIncludeName = (name: string, groupPermission: boolean, permissions: PermissionCollection) => { +const currentPermissionIncludeName = ( + name: string, + groupPermission: boolean, + permissions: PermissionCollection +) => { for (let i = 0; i < permissions.length; i++) { if ( permissions[i].name === name && - permissions[i].groupPermission == groupPermission + permissions[i].groupPermission === groupPermission ) return true; } diff --git a/scm-ui/src/repos/permissions/components/permissionValidation.test.js b/scm-ui/src/repos/permissions/components/permissionValidation.test.js index 036375a348..b2e7e8be68 100644 --- a/scm-ui/src/repos/permissions/components/permissionValidation.test.js +++ b/scm-ui/src/repos/permissions/components/permissionValidation.test.js @@ -17,7 +17,8 @@ describe("permission validation", () => { { name: "PermissionName", groupPermission: true, - type: "READ" + type: "READ", + _links: {} } ]; const name = "PermissionName"; @@ -33,7 +34,8 @@ describe("permission validation", () => { { name: "PermissionName", groupPermission: false, - type: "READ" + type: "READ", + _links: {} } ]; const name = "PermissionName"; diff --git a/scm-ui/src/repos/permissions/containers/Permissions.js b/scm-ui/src/repos/permissions/containers/Permissions.js index e70e02f443..1241ad0780 100644 --- a/scm-ui/src/repos/permissions/containers/Permissions.js +++ b/scm-ui/src/repos/permissions/containers/Permissions.js @@ -1,31 +1,27 @@ //@flow import React from "react"; -import { connect } from "react-redux"; -import { translate } from "react-i18next"; +import {connect} from "react-redux"; +import {translate} from "react-i18next"; import { + createPermission, + createPermissionReset, + deletePermissionReset, fetchPermissions, + getCreatePermissionFailure, + getDeletePermissionsFailure, getFetchPermissionsFailure, - isFetchPermissionsPending, + getModifyPermissionsFailure, getPermissionsOfRepo, hasCreatePermission, - createPermission, isCreatePermissionPending, - getCreatePermissionFailure, - createPermissionReset, - getDeletePermissionsFailure, - getModifyPermissionsFailure, - modifyPermissionReset, - deletePermissionReset + isFetchPermissionsPending, + modifyPermissionReset } from "../modules/permissions"; -import { Loading, ErrorPage } from "@scm-manager/ui-components"; -import type { - Permission, - PermissionCollection, - PermissionEntry -} from "@scm-manager/ui-types"; +import {ErrorPage, Loading} from "@scm-manager/ui-components"; +import type {Permission, PermissionCollection, PermissionCreateEntry} from "@scm-manager/ui-types"; import SinglePermission from "./SinglePermission"; import CreatePermissionForm from "../components/CreatePermissionForm"; -import type { History } from "history"; +import type {History} from "history"; type Props = { namespace: string, @@ -39,7 +35,7 @@ type Props = { //dispatch functions fetchPermissions: (namespace: string, repoName: string) => void, createPermission: ( - permission: PermissionEntry, + permission: PermissionCreateEntry, namespace: string, repoName: string, callback?: () => void @@ -176,7 +172,7 @@ const mapDispatchToProps = dispatch => { dispatch(fetchPermissions(namespace, repoName)); }, createPermission: ( - permission: PermissionEntry, + permission: PermissionCreateEntry, namespace: string, repoName: string, callback?: () => void diff --git a/scm-ui/src/repos/permissions/modules/permissions.js b/scm-ui/src/repos/permissions/modules/permissions.js index 86d78e7ae9..f07eb5b691 100644 --- a/scm-ui/src/repos/permissions/modules/permissions.js +++ b/scm-ui/src/repos/permissions/modules/permissions.js @@ -1,16 +1,12 @@ // @flow -import { apiClient } from "@scm-manager/ui-components"; +import type {Action} from "@scm-manager/ui-components"; +import {apiClient} from "@scm-manager/ui-components"; import * as types from "../../../modules/types"; -import type { Action } from "@scm-manager/ui-components"; -import type { - PermissionCollection, - Permission, - PermissionEntry -} from "@scm-manager/ui-types"; -import { isPending } from "../../../modules/pending"; -import { getFailure } from "../../../modules/failure"; -import { Dispatch } from "redux"; +import type {Permission, PermissionCollection, PermissionCreateEntry} from "@scm-manager/ui-types"; +import {isPending} from "../../../modules/pending"; +import {getFailure} from "../../../modules/failure"; +import {Dispatch} from "redux"; export const FETCH_PERMISSIONS = "scm/permissions/FETCH_PERMISSIONS"; export const FETCH_PERMISSIONS_PENDING = `${FETCH_PERMISSIONS}_${ @@ -219,7 +215,7 @@ export function modifyPermissionReset(namespace: string, repoName: string) { // create permission export function createPermission( - permission: PermissionEntry, + permission: PermissionCreateEntry, namespace: string, repoName: string, callback?: () => void @@ -260,7 +256,7 @@ export function createPermission( } export function createPermissionPending( - permission: PermissionEntry, + permission: PermissionCreateEntry, namespace: string, repoName: string ): Action { @@ -272,7 +268,7 @@ export function createPermissionPending( } export function createPermissionSuccess( - permission: PermissionEntry, + permission: PermissionCreateEntry, namespace: string, repoName: string ): Action { diff --git a/scm-ui/src/repos/permissions/modules/permissions.test.js b/scm-ui/src/repos/permissions/modules/permissions.test.js index e546f6cb00..d0605ae3c0 100644 --- a/scm-ui/src/repos/permissions/modules/permissions.test.js +++ b/scm-ui/src/repos/permissions/modules/permissions.test.js @@ -3,44 +3,44 @@ import configureMockStore from "redux-mock-store"; import thunk from "redux-thunk"; import fetchMock from "fetch-mock"; import reducer, { - fetchPermissions, - fetchPermissionsSuccess, - getPermissionsOfRepo, - isFetchPermissionsPending, - getFetchPermissionsFailure, - modifyPermission, - modifyPermissionSuccess, - getModifyPermissionFailure, - isModifyPermissionPending, - createPermission, - hasCreatePermission, - deletePermission, - deletePermissionSuccess, - getDeletePermissionFailure, - isDeletePermissionPending, - getModifyPermissionsFailure, - MODIFY_PERMISSION_FAILURE, - MODIFY_PERMISSION_PENDING, - FETCH_PERMISSIONS, - FETCH_PERMISSIONS_PENDING, - FETCH_PERMISSIONS_SUCCESS, - FETCH_PERMISSIONS_FAILURE, - MODIFY_PERMISSION_SUCCESS, - MODIFY_PERMISSION, + CREATE_PERMISSION, + CREATE_PERMISSION_FAILURE, CREATE_PERMISSION_PENDING, CREATE_PERMISSION_SUCCESS, - CREATE_PERMISSION_FAILURE, + createPermission, + createPermissionSuccess, DELETE_PERMISSION, + DELETE_PERMISSION_FAILURE, DELETE_PERMISSION_PENDING, DELETE_PERMISSION_SUCCESS, - DELETE_PERMISSION_FAILURE, - CREATE_PERMISSION, - createPermissionSuccess, + deletePermission, + deletePermissionSuccess, + FETCH_PERMISSIONS, + FETCH_PERMISSIONS_FAILURE, + FETCH_PERMISSIONS_PENDING, + FETCH_PERMISSIONS_SUCCESS, + fetchPermissions, + fetchPermissionsSuccess, getCreatePermissionFailure, + getDeletePermissionFailure, + getDeletePermissionsFailure, + getFetchPermissionsFailure, + getModifyPermissionFailure, + getModifyPermissionsFailure, + getPermissionsOfRepo, + hasCreatePermission, isCreatePermissionPending, - getDeletePermissionsFailure + isDeletePermissionPending, + isFetchPermissionsPending, + isModifyPermissionPending, + MODIFY_PERMISSION, + MODIFY_PERMISSION_FAILURE, + MODIFY_PERMISSION_PENDING, + MODIFY_PERMISSION_SUCCESS, + modifyPermission, + modifyPermissionSuccess } from "./permissions"; -import type { Permission, PermissionCollection } from "@scm-manager/ui-types"; +import type {Permission, PermissionCollection} from "@scm-manager/ui-types"; const hitchhiker_puzzle42Permission_user_eins: Permission = { name: "user_eins", @@ -640,7 +640,7 @@ describe("permissions selectors", () => { it("should return true, when createPermission is true", () => { const state = { permissions: { - ["hitchhiker/puzzle42"]: { + "hitchhiker/puzzle42": { createPermission: true } } @@ -651,7 +651,7 @@ describe("permissions selectors", () => { it("should return false, when createPermission is false", () => { const state = { permissions: { - ["hitchhiker/puzzle42"]: { + "hitchhiker/puzzle42": { createPermission: false } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java index 6b432e7237..947d8105dc 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java @@ -5,7 +5,6 @@ import com.webcohesion.enunciate.metadata.rs.StatusCodes; import sonia.scm.NotFoundException; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.RevisionNotFoundException; -import sonia.scm.repository.api.DiffFormat; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.util.HttpUtil; @@ -58,7 +57,7 @@ public class DiffRootResource { try { repositoryService.getDiffCommand() .setRevision(revision) - .setFormat(DiffFormat.GIT) // TODO: Configure this at request time. Maybe as a query param? +// .setFormat(DiffFormat.GIT) // TODO: Configure this at request time. Maybe as a query param? .retriveContent(output); } catch (RevisionNotFoundException e) { throw new WebApplicationException(Response.Status.NOT_FOUND);