apply prettier, removed flow related config and added tsconfig

This commit is contained in:
Sebastian Sdorra
2019-10-20 18:02:52 +02:00
parent 0e017dcadd
commit 490418d06e
231 changed files with 5771 additions and 30386 deletions

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Repository, Branch } from '@scm-manager/ui-types';
import { ButtonAddons, Button } from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
import React from "react";
import { Repository, Branch } from "@scm-manager/ui-types";
import { ButtonAddons, Button } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
type Props = {
repository: Repository;
@@ -27,13 +27,13 @@ class BranchButtonGroup extends React.Component<Props> {
<Button
link={changesetLink}
icon="exchange-alt"
label={t('branch.commits')}
label={t("branch.commits")}
reducedMobile={true}
/>
<Button
link={sourcesLink}
icon="code"
label={t('branch.sources')}
label={t("branch.sources")}
reducedMobile={true}
/>
</ButtonAddons>
@@ -41,4 +41,4 @@ class BranchButtonGroup extends React.Component<Props> {
}
}
export default translate('repos')(BranchButtonGroup);
export default translate("repos")(BranchButtonGroup);

View File

@@ -1,8 +1,8 @@
import React from 'react';
import { Repository, Branch } from '@scm-manager/ui-types';
import { translate } from 'react-i18next';
import BranchButtonGroup from './BranchButtonGroup';
import DefaultBranchTag from './DefaultBranchTag';
import React from "react";
import { Repository, Branch } from "@scm-manager/ui-types";
import { translate } from "react-i18next";
import BranchButtonGroup from "./BranchButtonGroup";
import DefaultBranchTag from "./DefaultBranchTag";
type Props = {
repository: Repository;
@@ -18,7 +18,7 @@ class BranchDetail extends React.Component<Props> {
return (
<div className="media">
<div className="media-content subtitle">
<strong>{t('branch.name')}</strong> {branch.name}{' '}
<strong>{t("branch.name")}</strong> {branch.name}{" "}
<DefaultBranchTag defaultBranch={branch.defaultBranch} />
</div>
<div className="media-right">
@@ -29,4 +29,4 @@ class BranchDetail extends React.Component<Props> {
}
}
export default translate('repos')(BranchDetail);
export default translate("repos")(BranchDetail);

View File

@@ -1,13 +1,13 @@
import React from 'react';
import { translate } from 'react-i18next';
import { Repository, Branch, BranchRequest } from '@scm-manager/ui-types';
import React from "react";
import { translate } from "react-i18next";
import { Repository, Branch, BranchRequest } from "@scm-manager/ui-types";
import {
Select,
InputField,
SubmitButton,
validation as validator,
} from '@scm-manager/ui-components';
import { orderBranches } from '../util/orderBranches';
validation as validator
} from "@scm-manager/ui-components";
import { orderBranches } from "../util/orderBranches";
type Props = {
submitForm: (p: BranchRequest) => void;
@@ -31,7 +31,7 @@ class BranchForm extends React.Component<Props, State> {
this.state = {
nameValidationError: false,
name: props.transmittedName,
name: props.transmittedName
};
}
@@ -53,7 +53,7 @@ class BranchForm extends React.Component<Props, State> {
if (this.isValid()) {
this.props.submitForm({
name: this.state.name,
parent: this.state.source,
parent: this.state.source
});
}
};
@@ -64,7 +64,7 @@ class BranchForm extends React.Component<Props, State> {
orderBranches(branches);
const options = branches.map(branch => ({
label: branch.name,
value: branch.name,
value: branch.name
}));
return (
@@ -74,7 +74,7 @@ class BranchForm extends React.Component<Props, State> {
<div className="column">
<Select
name="source"
label={t('branches.create.source')}
label={t("branches.create.source")}
options={options}
onChange={this.handleSourceChange}
loading={loading}
@@ -82,11 +82,11 @@ class BranchForm extends React.Component<Props, State> {
/>
<InputField
name="name"
label={t('branches.create.name')}
label={t("branches.create.name")}
onChange={this.handleNameChange}
value={name ? name : ''}
value={name ? name : ""}
validationError={this.state.nameValidationError}
errorMessage={t('validation.branch.nameInvalid')}
errorMessage={t("validation.branch.nameInvalid")}
disabled={!!transmittedName || disabled}
/>
</div>
@@ -96,7 +96,7 @@ class BranchForm extends React.Component<Props, State> {
<SubmitButton
disabled={disabled || !this.isValid()}
loading={loading}
label={t('branches.create.submit')}
label={t("branches.create.submit")}
/>
</div>
</div>
@@ -108,7 +108,7 @@ class BranchForm extends React.Component<Props, State> {
handleSourceChange = (source: string) => {
this.setState({
...this.state,
source,
source
});
};
@@ -116,9 +116,9 @@ class BranchForm extends React.Component<Props, State> {
this.setState({
nameValidationError: !validator.isNameValid(name),
...this.state,
name,
name
});
};
}
export default translate('repos')(BranchForm);
export default translate("repos")(BranchForm);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Branch } from '@scm-manager/ui-types';
import DefaultBranchTag from './DefaultBranchTag';
import React from "react";
import { Link } from "react-router-dom";
import { Branch } from "@scm-manager/ui-types";
import DefaultBranchTag from "./DefaultBranchTag";
type Props = {
baseUrl: string;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { translate } from 'react-i18next';
import BranchRow from './BranchRow';
import { Branch } from '@scm-manager/ui-types';
import React from "react";
import { translate } from "react-i18next";
import BranchRow from "./BranchRow";
import { Branch } from "@scm-manager/ui-types";
type Props = {
baseUrl: string;
@@ -16,7 +16,7 @@ class BranchTable extends React.Component<Props> {
<table className="card-table table is-hoverable is-fullwidth">
<thead>
<tr>
<th>{t('branches.table.branches')}</th>
<th>{t("branches.table.branches")}</th>
</tr>
</thead>
<tbody>{this.renderRow()}</tbody>
@@ -36,4 +36,4 @@ class BranchTable extends React.Component<Props> {
}
}
export default translate('repos')(BranchTable);
export default translate("repos")(BranchTable);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import BranchDetail from './BranchDetail';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
import { Repository, Branch } from '@scm-manager/ui-types';
import React from "react";
import BranchDetail from "./BranchDetail";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Repository, Branch } from "@scm-manager/ui-types";
type Props = {
repository: Repository;
@@ -22,7 +22,7 @@ class BranchView extends React.Component<Props> {
renderAll={true}
props={{
repository,
branch,
branch
}}
/>
</div>

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { translate } from 'react-i18next';
import styled from 'styled-components';
import { Tag } from '@scm-manager/ui-components';
import React from "react";
import { translate } from "react-i18next";
import styled from "styled-components";
import { Tag } from "@scm-manager/ui-components";
type Props = {
defaultBranch?: boolean;
@@ -20,10 +20,10 @@ class DefaultBranchTag extends React.Component<Props> {
const { defaultBranch, t } = this.props;
if (defaultBranch) {
return <LeftMarginTag color="dark" label={t('branch.defaultTag')} />;
return <LeftMarginTag color="dark" label={t("branch.defaultTag")} />;
}
return null;
}
}
export default translate('repos')(DefaultBranchTag);
export default translate("repos")(DefaultBranchTag);

View File

@@ -1,18 +1,18 @@
import React from 'react';
import BranchView from '../components/BranchView';
import { connect } from 'react-redux';
import { Redirect, Route, Switch, withRouter } from 'react-router-dom';
import { Repository, Branch } from '@scm-manager/ui-types';
import React from "react";
import BranchView from "../components/BranchView";
import { connect } from "react-redux";
import { Redirect, Route, Switch, withRouter } from "react-router-dom";
import { Repository, Branch } from "@scm-manager/ui-types";
import {
fetchBranch,
getBranch,
getFetchBranchFailure,
isFetchBranchPending,
} from '../modules/branches';
import { ErrorNotification, Loading } from '@scm-manager/ui-components';
import { History } from 'history';
import { NotFoundError } from '@scm-manager/ui-components';
import queryString from 'query-string';
isFetchBranchPending
} from "../modules/branches";
import { ErrorNotification, Loading } from "@scm-manager/ui-components";
import { History } from "history";
import { NotFoundError } from "@scm-manager/ui-components";
import queryString from "query-string";
type Props = {
repository: Repository;
@@ -38,7 +38,7 @@ class BranchRoot extends React.Component<Props> {
}
stripEndingSlash = (url: string) => {
if (url.endsWith('/')) {
if (url.endsWith("/")) {
return url.substring(0, url.length - 1);
}
return url;
@@ -56,7 +56,7 @@ class BranchRoot extends React.Component<Props> {
if (error) {
if (
error instanceof NotFoundError &&
queryString.parse(location.search).create === 'true'
queryString.parse(location.search).create === "true"
) {
return (
<Redirect
@@ -97,7 +97,7 @@ const mapStateToProps = (state, ownProps) => {
branchName,
branch,
loading,
error,
error
};
};
@@ -105,13 +105,13 @@ const mapDispatchToProps = dispatch => {
return {
fetchBranch: (repository: Repository, branchName: string) => {
dispatch(fetchBranch(repository, branchName));
},
}
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps,
)(BranchRoot),
mapDispatchToProps
)(BranchRoot)
);

View File

@@ -1,25 +1,25 @@
import React from 'react';
import React from "react";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending,
isPermittedToCreateBranches,
} from '../modules/branches';
import { orderBranches } from '../util/orderBranches';
import { connect } from 'react-redux';
import { Branch, Repository } from '@scm-manager/ui-types';
import { compose } from 'redux';
import { translate } from 'react-i18next';
import { withRouter } from 'react-router-dom';
isPermittedToCreateBranches
} from "../modules/branches";
import { orderBranches } from "../util/orderBranches";
import { connect } from "react-redux";
import { Branch, Repository } from "@scm-manager/ui-types";
import { compose } from "redux";
import { translate } from "react-i18next";
import { withRouter } from "react-router-dom";
import {
CreateButton,
ErrorNotification,
Loading,
Notification,
Subtitle,
} from '@scm-manager/ui-components';
import BranchTable from '../components/BranchTable';
Subtitle
} from "@scm-manager/ui-components";
import BranchTable from "../components/BranchTable";
type Props = {
repository: Repository;
@@ -57,7 +57,7 @@ class BranchesOverview extends React.Component<Props> {
return (
<>
<Subtitle subtitle={t('branches.overview.title')} />
<Subtitle subtitle={t("branches.overview.title")} />
{this.renderBranchesTable()}
{this.renderCreateButton()}
</>
@@ -72,7 +72,7 @@ class BranchesOverview extends React.Component<Props> {
}
return (
<Notification type="info">
{t('branches.overview.noBranches')}
{t("branches.overview.noBranches")}
</Notification>
);
}
@@ -82,7 +82,7 @@ class BranchesOverview extends React.Component<Props> {
if (showCreateButton) {
return (
<CreateButton
label={t('branches.overview.createButton')}
label={t("branches.overview.createButton")}
link="./create"
/>
);
@@ -103,7 +103,7 @@ const mapStateToProps = (state, ownProps) => {
loading,
error,
branches,
showCreateButton,
showCreateButton
};
};
@@ -111,15 +111,15 @@ const mapDispatchToProps = dispatch => {
return {
fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository));
},
}
};
};
export default compose(
translate('repos'),
translate("repos"),
withRouter,
connect(
mapStateToProps,
mapDispatchToProps,
),
mapDispatchToProps
)
)(BranchesOverview);

View File

@@ -1,12 +1,12 @@
import React from 'react';
import React from "react";
import {
ErrorNotification,
Loading,
Subtitle,
} from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
import BranchForm from '../components/BranchForm';
import { Repository, Branch, BranchRequest } from '@scm-manager/ui-types';
Subtitle
} from "@scm-manager/ui-components";
import { translate } from "react-i18next";
import BranchForm from "../components/BranchForm";
import { Repository, Branch, BranchRequest } from "@scm-manager/ui-types";
import {
fetchBranches,
getBranches,
@@ -16,12 +16,12 @@ import {
isCreateBranchPending,
getCreateBranchFailure,
isFetchBranchesPending,
getFetchBranchesFailure,
} from '../modules/branches';
import { History } from 'history';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import queryString from 'query-string';
getFetchBranchesFailure
} from "../modules/branches";
import { History } from "history";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import queryString from "query-string";
type Props = {
loading?: boolean;
@@ -37,7 +37,7 @@ type Props = {
createLink: string,
repository: Repository,
branch: BranchRequest,
callback?: (p: Branch) => void,
callback?: (p: Branch) => void
) => void;
resetForm: (p: Repository) => void;
@@ -59,7 +59,7 @@ class CreateBranch extends React.Component<Props> {
history.push(
`/repo/${repository.namespace}/${
repository.name
}/branch/${encodeURIComponent(branch.name)}/info`,
}/branch/${encodeURIComponent(branch.name)}/info`
);
};
@@ -68,7 +68,7 @@ class CreateBranch extends React.Component<Props> {
this.props.createBranchesLink,
this.props.repository,
branch,
newBranch => this.branchCreated(newBranch),
newBranch => this.branchCreated(newBranch)
);
};
@@ -85,7 +85,7 @@ class CreateBranch extends React.Component<Props> {
repository,
branches,
createBranchesLink,
location,
location
} = this.props;
if (error) {
@@ -98,7 +98,7 @@ class CreateBranch extends React.Component<Props> {
return (
<>
<Subtitle subtitle={t('branches.create.title')} />
<Subtitle subtitle={t("branches.create.title")} />
<BranchForm
submitForm={branchRequest => this.createBranch(branchRequest)}
loading={loading}
@@ -121,13 +121,13 @@ const mapDispatchToProps = dispatch => {
createLink: string,
repository: Repository,
branchRequest: BranchRequest,
callback?: (newBranch: Branch) => void,
callback?: (newBranch: Branch) => void
) => {
dispatch(createBranch(createLink, repository, branchRequest, callback));
},
resetForm: (repository: Repository) => {
dispatch(createBranchReset(repository));
},
}
};
};
@@ -145,13 +145,13 @@ const mapStateToProps = (state, ownProps) => {
loading,
error,
branches,
createBranchesLink,
createBranchesLink
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps,
)(translate('repos')(CreateBranch)),
mapDispatchToProps
)(translate("repos")(CreateBranch))
);

View File

@@ -1,6 +1,6 @@
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock from 'fetch-mock';
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
FETCH_BRANCHES,
FETCH_BRANCHES_FAILURE,
@@ -23,46 +23,46 @@ import reducer, {
createBranch,
isCreateBranchPending,
getCreateBranchFailure,
isPermittedToCreateBranches,
} from './branches';
isPermittedToCreateBranches
} from "./branches";
const namespace = 'foo';
const name = 'bar';
const key = namespace + '/' + name;
const namespace = "foo";
const name = "bar";
const key = namespace + "/" + name;
const repository = {
namespace: 'foo',
name: 'bar',
namespace: "foo",
name: "bar",
_links: {
branches: {
href: 'http://scm/api/rest/v2/repositories/foo/bar/branches',
},
},
href: "http://scm/api/rest/v2/repositories/foo/bar/branches"
}
}
};
const branch1 = {
name: 'branch1',
revision: 'revision1',
name: "branch1",
revision: "revision1"
};
const branch2 = {
name: 'branch2',
revision: 'revision2',
name: "branch2",
revision: "revision2"
};
const branch3 = {
name: 'branch3',
revision: 'revision3',
name: "branch3",
revision: "revision3"
};
const branchRequest = {
name: 'newBranch',
source: 'master',
name: "newBranch",
source: "master"
};
const newBranch = {
name: 'newBranch',
revision: 'rev3',
name: "newBranch",
revision: "rev3"
};
describe('branches', () => {
describe('fetch branches', () => {
const URL = 'http://scm/api/rest/v2/repositories/foo/bar/branches';
describe("branches", () => {
describe("fetch branches", () => {
const URL = "http://scm/api/rest/v2/repositories/foo/bar/branches";
const mockStore = configureMockStore([thunk]);
afterEach(() => {
@@ -70,27 +70,27 @@ describe('branches', () => {
fetchMock.restore();
});
it('should fetch branches', () => {
it("should fetch branches", () => {
const collection = {};
fetchMock.getOnce(URL, '{}');
fetchMock.getOnce(URL, "{}");
const expectedActions = [
{
type: FETCH_BRANCHES_PENDING,
payload: {
repository,
repository
},
itemId: key,
itemId: key
},
{
type: FETCH_BRANCHES_SUCCESS,
payload: {
data: collection,
repository,
repository
},
itemId: key,
},
itemId: key
}
];
const store = mockStore({});
@@ -99,7 +99,7 @@ describe('branches', () => {
});
});
it('should fail fetching branches on HTTP 500', () => {
it("should fail fetching branches on HTTP 500", () => {
const collection = {};
fetchMock.getOnce(URL, 500);
@@ -108,18 +108,18 @@ describe('branches', () => {
{
type: FETCH_BRANCHES_PENDING,
payload: {
repository,
repository
},
itemId: key,
itemId: key
},
{
type: FETCH_BRANCHES_FAILURE,
payload: {
error: collection,
repository,
repository
},
itemId: key,
},
itemId: key
}
];
const store = mockStore({});
@@ -129,11 +129,11 @@ describe('branches', () => {
});
});
it('should successfully fetch single branch', () => {
fetchMock.getOnce(URL + '/branch1', branch1);
it("should successfully fetch single branch", () => {
fetchMock.getOnce(URL + "/branch1", branch1);
const store = mockStore({});
return store.dispatch(fetchBranch(repository, 'branch1')).then(() => {
return store.dispatch(fetchBranch(repository, "branch1")).then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(FETCH_BRANCH_PENDING);
expect(actions[1].type).toEqual(FETCH_BRANCH_SUCCESS);
@@ -141,13 +141,13 @@ describe('branches', () => {
});
});
it('should fail fetching single branch on HTTP 500', () => {
fetchMock.getOnce(URL + '/branch2', {
status: 500,
it("should fail fetching single branch on HTTP 500", () => {
fetchMock.getOnce(URL + "/branch2", {
status: 500
});
const store = mockStore({});
return store.dispatch(fetchBranch(repository, 'branch2')).then(() => {
return store.dispatch(fetchBranch(repository, "branch2")).then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(FETCH_BRANCH_PENDING);
expect(actions[1].type).toEqual(FETCH_BRANCH_FAILURE);
@@ -155,17 +155,17 @@ describe('branches', () => {
});
});
it('should create a branch successfully', () => {
it("should create a branch successfully", () => {
//branchrequest answer
fetchMock.postOnce(URL, {
status: 201,
headers: {
location: URL + '/newBranch',
},
location: URL + "/newBranch"
}
});
//branch answer
fetchMock.getOnce(URL + '/newBranch', newBranch);
fetchMock.getOnce(URL + "/newBranch", newBranch);
const store = mockStore({});
return store
@@ -177,17 +177,17 @@ describe('branches', () => {
});
});
it('should call the callback with the branch from the location header', () => {
it("should call the callback with the branch from the location header", () => {
//branchrequest answer
fetchMock.postOnce(URL, {
status: 201,
headers: {
location: URL + '/newBranch',
},
location: URL + "/newBranch"
}
});
//branch answer
fetchMock.getOnce(URL + '/newBranch', newBranch);
fetchMock.getOnce(URL + "/newBranch", newBranch);
const store = mockStore({});
@@ -204,9 +204,9 @@ describe('branches', () => {
});
});
it('should fail creating a branch on HTTP 500', () => {
it("should fail creating a branch on HTTP 500", () => {
fetchMock.postOnce(URL, {
status: 500,
status: 500
});
const store = mockStore({});
@@ -220,179 +220,179 @@ describe('branches', () => {
});
});
describe('branches reducer', () => {
describe("branches reducer", () => {
const branches = {
_embedded: {
branches: [branch1, branch2],
branches: [branch1, branch2]
},
_links: {
self: {
href: '/self',
href: "/self"
},
create: {
href: '/create',
},
},
href: "/create"
}
}
};
const action = {
type: FETCH_BRANCHES_SUCCESS,
payload: {
repository,
data: branches,
},
data: branches
}
};
it('should store the branches', () => {
it("should store the branches", () => {
const newState = reducer({}, action);
const repoState = newState['foo/bar'];
const repoState = newState["foo/bar"];
expect(repoState.list._links.create.href).toEqual('/create');
expect(repoState.list._embedded.branches).toEqual(['branch1', 'branch2']);
expect(repoState.list._links.create.href).toEqual("/create");
expect(repoState.list._embedded.branches).toEqual(["branch1", "branch2"]);
expect(repoState.byName.branch1).toEqual(branch1);
expect(repoState.byName.branch2).toEqual(branch2);
});
it('should store a single branch', () => {
it("should store a single branch", () => {
const newState = reducer({}, fetchBranchSuccess(repository, branch1));
const repoState = newState['foo/bar'];
const repoState = newState["foo/bar"];
expect(repoState.list).toBeUndefined();
expect(repoState.byName.branch1).toEqual(branch1);
});
it('should add a single branch', () => {
it("should add a single branch", () => {
const state = {
'foo/bar': {
"foo/bar": {
list: {
_links: {},
_embedded: {
branches: ['branch1'],
},
branches: ["branch1"]
}
},
byName: {
branch1: branch1,
},
},
branch1: branch1
}
}
};
const newState = reducer(state, fetchBranchSuccess(repository, branch2));
const repoState = newState['foo/bar'];
const repoState = newState["foo/bar"];
const byName = repoState.byName;
expect(repoState.list._embedded.branches).toEqual(['branch1']);
expect(repoState.list._embedded.branches).toEqual(["branch1"]);
expect(byName.branch1).toEqual(branch1);
expect(byName.branch2).toEqual(branch2);
});
it('should not overwrite non related repositories', () => {
it("should not overwrite non related repositories", () => {
const state = {
'scm/core': {
"scm/core": {
byName: {
branch1: branch1,
},
},
branch1: branch1
}
}
};
const newState = reducer(state, fetchBranchSuccess(repository, branch1));
const byName = newState['scm/core'].byName;
const byName = newState["scm/core"].byName;
expect(byName.branch1).toEqual(branch1);
});
it('should overwrite existing branch', () => {
it("should overwrite existing branch", () => {
const state = {
'foo/bar': {
"foo/bar": {
byName: {
branch1: {
name: 'branch1',
revision: 'xyz',
},
},
},
name: "branch1",
revision: "xyz"
}
}
}
};
const newState = reducer(state, fetchBranchSuccess(repository, branch1));
const byName = newState['foo/bar'].byName;
const byName = newState["foo/bar"].byName;
expect(byName.branch1.revision).toEqual('revision1');
expect(byName.branch1.revision).toEqual("revision1");
});
it('should not overwrite existing branches', () => {
it("should not overwrite existing branches", () => {
const state = {
'foo/bar': {
"foo/bar": {
byName: {
branch1,
branch2,
branch3,
},
},
branch3
}
}
};
const newState = reducer(state, action);
expect(newState['foo/bar'].byName.branch1).toEqual(branch1);
expect(newState['foo/bar'].byName.branch2).toEqual(branch2);
expect(newState['foo/bar'].byName.branch3).toEqual(branch3);
expect(newState["foo/bar"].byName.branch1).toEqual(branch1);
expect(newState["foo/bar"].byName.branch2).toEqual(branch2);
expect(newState["foo/bar"].byName.branch3).toEqual(branch3);
});
});
describe('branch selectors', () => {
const error = new Error('Something went wrong');
describe("branch selectors", () => {
const error = new Error("Something went wrong");
const state = {
branches: {
'foo/bar': {
"foo/bar": {
list: {
_links: {},
_embedded: {
branches: ['branch1', 'branch2'],
},
branches: ["branch1", "branch2"]
}
},
byName: {
branch1: branch1,
branch2: branch2,
},
},
},
branch2: branch2
}
}
}
};
it('should return true, when fetching branches is pending', () => {
it("should return true, when fetching branches is pending", () => {
const state = {
pending: {
[FETCH_BRANCHES + '/foo/bar']: true,
},
[FETCH_BRANCHES + "/foo/bar"]: true
}
};
expect(isFetchBranchesPending(state, repository)).toBeTruthy();
});
it('should return branches', () => {
it("should return branches", () => {
const branches = getBranches(state, repository);
expect(branches.length).toEqual(2);
expect(branches).toContain(branch1);
expect(branches).toContain(branch2);
});
it('should return always the same reference for branches', () => {
it("should return always the same reference for branches", () => {
const one = getBranches(state, repository);
const two = getBranches(state, repository);
expect(one).toBe(two);
});
it('should not return cached reference, if branches have changed', () => {
it("should not return cached reference, if branches have changed", () => {
const one = getBranches(state, repository);
const newState = {
branches: {
'foo/bar': {
"foo/bar": {
list: {
_links: {},
_embedded: {
branches: ['branch2', 'branch3'],
},
branches: ["branch2", "branch3"]
}
},
byName: {
branch2,
branch3,
},
},
},
branch3
}
}
}
};
const two = getBranches(newState, repository);
expect(one).not.toBe(two);
@@ -401,100 +401,100 @@ describe('branches', () => {
expect(two).toContain(branch3);
});
it('should return undefined, if no branches for the repository available', () => {
it("should return undefined, if no branches for the repository available", () => {
const branches = getBranches(
{
branches: {},
branches: {}
},
repository,
repository
);
expect(branches).toBeUndefined();
});
it('should return single branch by name', () => {
const branch = getBranch(state, repository, 'branch1');
it("should return single branch by name", () => {
const branch = getBranch(state, repository, "branch1");
expect(branch).toEqual(branch1);
});
it('should return same reference for single branch by name', () => {
const one = getBranch(state, repository, 'branch1');
const two = getBranch(state, repository, 'branch1');
it("should return same reference for single branch by name", () => {
const one = getBranch(state, repository, "branch1");
const two = getBranch(state, repository, "branch1");
expect(one).toBe(two);
});
it('should return undefined if branch does not exist', () => {
const branch = getBranch(state, repository, 'branch42');
it("should return undefined if branch does not exist", () => {
const branch = getBranch(state, repository, "branch42");
expect(branch).toBeUndefined();
});
it('should return true if the branches list contains the create link', () => {
it("should return true if the branches list contains the create link", () => {
const stateWithLink = {
branches: {
'foo/bar': {
...state.branches['foo/bar'],
"foo/bar": {
...state.branches["foo/bar"],
list: {
...state.branches['foo/bar'].list,
...state.branches["foo/bar"].list,
_links: {
create: {
href: 'http://create-it',
},
},
},
},
},
href: "http://create-it"
}
}
}
}
}
};
const permitted = isPermittedToCreateBranches(stateWithLink, repository);
expect(permitted).toBe(true);
});
it('should return false if the create link is missing', () => {
it("should return false if the create link is missing", () => {
const permitted = isPermittedToCreateBranches(state, repository);
expect(permitted).toBe(false);
});
it('should return error if fetching branches failed', () => {
it("should return error if fetching branches failed", () => {
const state = {
failure: {
[FETCH_BRANCHES + '/foo/bar']: error,
},
[FETCH_BRANCHES + "/foo/bar"]: error
}
};
expect(getFetchBranchesFailure(state, repository)).toEqual(error);
});
it('should return false if fetching branches did not fail', () => {
it("should return false if fetching branches did not fail", () => {
expect(getFetchBranchesFailure({}, repository)).toBeUndefined();
});
it('should return true if create branch is pending', () => {
it("should return true if create branch is pending", () => {
const state = {
pending: {
[CREATE_BRANCH + '/foo/bar']: true,
},
[CREATE_BRANCH + "/foo/bar"]: true
}
};
expect(isCreateBranchPending(state, repository)).toBe(true);
});
it('should return false if create branch is not pending', () => {
it("should return false if create branch is not pending", () => {
const state = {
pending: {
[CREATE_BRANCH + '/foo/bar']: false,
},
[CREATE_BRANCH + "/foo/bar"]: false
}
};
expect(isCreateBranchPending(state, repository)).toBe(false);
});
it('should return error when create branch did fail', () => {
it("should return error when create branch did fail", () => {
const state = {
failure: {
[CREATE_BRANCH]: error,
},
[CREATE_BRANCH]: error
}
};
expect(getCreateBranchFailure(state)).toEqual(error);
});
it('should return undefined when create branch did not fail', () => {
it("should return undefined when create branch did not fail", () => {
expect(getCreateBranchFailure({})).toBe(undefined);
});
});

View File

@@ -2,38 +2,38 @@ import {
FAILURE_SUFFIX,
PENDING_SUFFIX,
SUCCESS_SUFFIX,
RESET_SUFFIX,
} from '../../../modules/types';
import { apiClient } from '@scm-manager/ui-components';
RESET_SUFFIX
} from "../../../modules/types";
import { apiClient } from "@scm-manager/ui-components";
import {
Action,
Branch,
BranchRequest,
Repository,
} from '@scm-manager/ui-types';
import { isPending } from '../../../modules/pending';
import { getFailure } from '../../../modules/failure';
Repository
} from "@scm-manager/ui-types";
import { isPending } from "../../../modules/pending";
import { getFailure } from "../../../modules/failure";
import memoizeOne from 'memoize-one';
import memoizeOne from "memoize-one";
export const FETCH_BRANCHES = 'scm/repos/FETCH_BRANCHES';
export const FETCH_BRANCHES = "scm/repos/FETCH_BRANCHES";
export const FETCH_BRANCHES_PENDING = `${FETCH_BRANCHES}_${PENDING_SUFFIX}`;
export const FETCH_BRANCHES_SUCCESS = `${FETCH_BRANCHES}_${SUCCESS_SUFFIX}`;
export const FETCH_BRANCHES_FAILURE = `${FETCH_BRANCHES}_${FAILURE_SUFFIX}`;
export const FETCH_BRANCH = 'scm/repos/FETCH_BRANCH';
export const FETCH_BRANCH = "scm/repos/FETCH_BRANCH";
export const FETCH_BRANCH_PENDING = `${FETCH_BRANCH}_${PENDING_SUFFIX}`;
export const FETCH_BRANCH_SUCCESS = `${FETCH_BRANCH}_${SUCCESS_SUFFIX}`;
export const FETCH_BRANCH_FAILURE = `${FETCH_BRANCH}_${FAILURE_SUFFIX}`;
export const CREATE_BRANCH = 'scm/repos/CREATE_BRANCH';
export const CREATE_BRANCH = "scm/repos/CREATE_BRANCH";
export const CREATE_BRANCH_PENDING = `${CREATE_BRANCH}_${PENDING_SUFFIX}`;
export const CREATE_BRANCH_SUCCESS = `${CREATE_BRANCH}_${SUCCESS_SUFFIX}`;
export const CREATE_BRANCH_FAILURE = `${CREATE_BRANCH}_${FAILURE_SUFFIX}`;
export const CREATE_BRANCH_RESET = `${CREATE_BRANCH}_${RESET_SUFFIX}`;
const CONTENT_TYPE_BRANCH_REQUEST =
'application/vnd.scmm-branchRequest+json;v=2';
"application/vnd.scmm-branchRequest+json;v=2";
// Fetching branches
@@ -43,9 +43,9 @@ export function fetchBranches(repository: Repository) {
type: FETCH_BRANCHES_SUCCESS,
payload: {
repository,
data: {},
data: {}
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
@@ -65,8 +65,8 @@ export function fetchBranches(repository: Repository) {
export function fetchBranch(repository: Repository, name: string) {
let link = repository._links.branches.href;
if (!link.endsWith('/')) {
link += '/';
if (!link.endsWith("/")) {
link += "/";
}
link += encodeURIComponent(name);
return function(dispatch: any) {
@@ -91,13 +91,13 @@ export function createBranch(
link: string,
repository: Repository,
branchRequest: BranchRequest,
callback?: (branch: Branch) => void,
callback?: (branch: Branch) => void
) {
return function(dispatch: any) {
dispatch(createBranchPending(repository));
return apiClient
.post(link, branchRequest, CONTENT_TYPE_BRANCH_REQUEST)
.then(response => response.headers.get('Location'))
.then(response => response.headers.get("Location"))
.then(location => apiClient.get(location))
.then(response => response.json())
.then(branch => {
@@ -147,7 +147,7 @@ function getRepoState(state: object, repository: Repository) {
export const isPermittedToCreateBranches = (
state: object,
repository: Repository,
repository: Repository
): boolean => {
const repoState = getRepoState(state, repository);
return !!(
@@ -161,7 +161,7 @@ export const isPermittedToCreateBranches = (
export function getBranch(
state: object,
repository: Repository,
name: string,
name: string
): Branch | null | undefined {
const repoState = getRepoState(state, repository);
if (repoState) {
@@ -172,7 +172,7 @@ export function getBranch(
// Action creators
export function isFetchBranchesPending(
state: object,
repository: Repository,
repository: Repository
): boolean {
return isPending(state, FETCH_BRANCHES, createKey(repository));
}
@@ -185,9 +185,9 @@ export function fetchBranchesPending(repository: Repository) {
return {
type: FETCH_BRANCHES_PENDING,
payload: {
repository,
repository
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
@@ -196,9 +196,9 @@ export function fetchBranchesSuccess(data: string, repository: Repository) {
type: FETCH_BRANCHES_SUCCESS,
payload: {
data,
repository,
repository
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
@@ -207,9 +207,9 @@ export function fetchBranchesFailure(repository: Repository, error: Error) {
type: FETCH_BRANCHES_FAILURE,
payload: {
error,
repository,
repository
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
@@ -225,9 +225,9 @@ export function createBranchPending(repository: Repository): Action {
return {
type: CREATE_BRANCH_PENDING,
payload: {
repository,
repository
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
@@ -235,23 +235,23 @@ export function createBranchSuccess(repository: Repository): Action {
return {
type: CREATE_BRANCH_SUCCESS,
payload: {
repository,
repository
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
export function createBranchFailure(
repository: Repository,
error: Error,
error: Error
): Action {
return {
type: CREATE_BRANCH_FAILURE,
payload: {
repository,
error,
error
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
@@ -259,69 +259,69 @@ export function createBranchReset(repository: Repository): Action {
return {
type: CREATE_BRANCH_RESET,
payload: {
repository,
repository
},
itemId: createKey(repository),
itemId: createKey(repository)
};
}
export function isFetchBranchPending(
state: object,
repository: Repository,
name: string,
name: string
) {
return isPending(state, FETCH_BRANCH, createKey(repository) + '/' + name);
return isPending(state, FETCH_BRANCH, createKey(repository) + "/" + name);
}
export function getFetchBranchFailure(
state: object,
repository: Repository,
name: string,
name: string
) {
return getFailure(state, FETCH_BRANCH, createKey(repository) + '/' + name);
return getFailure(state, FETCH_BRANCH, createKey(repository) + "/" + name);
}
export function fetchBranchPending(
repository: Repository,
name: string,
name: string
): Action {
return {
type: FETCH_BRANCH_PENDING,
payload: {
repository,
name,
name
},
itemId: createKey(repository) + '/' + name,
itemId: createKey(repository) + "/" + name
};
}
export function fetchBranchSuccess(
repository: Repository,
branch: Branch,
branch: Branch
): Action {
return {
type: FETCH_BRANCH_SUCCESS,
payload: {
repository,
branch,
branch
},
itemId: createKey(repository) + '/' + branch.name,
itemId: createKey(repository) + "/" + branch.name
};
}
export function fetchBranchFailure(
repository: Repository,
name: string,
error: Error,
error: Error
): Action {
return {
type: FETCH_BRANCH_FAILURE,
payload: {
error,
repository,
name,
name
},
itemId: createKey(repository) + '/' + name,
itemId: createKey(repository) + "/" + name
};
}
@@ -345,12 +345,12 @@ const reduceByBranchesSuccess = (state, payload) => {
return {
[key]: {
list: response,
byName,
},
byName
}
};
}
return {
[key]: [],
[key]: []
};
};
@@ -369,15 +369,15 @@ const reduceByBranchSuccess = (state, payload) => {
return {
...state,
[key]: repoState,
[key]: repoState
};
};
export default function reducer(
state: {} = {},
action: Action = {
type: 'UNKNOWN',
},
type: "UNKNOWN"
}
): object {
if (!action.payload) {
return state;

View File

@@ -1,61 +1,61 @@
import { orderBranches } from './orderBranches';
import { orderBranches } from "./orderBranches";
const branch1 = {
name: 'branch1',
revision: 'revision1',
name: "branch1",
revision: "revision1"
};
const branch2 = {
name: 'branch2',
revision: 'revision2',
name: "branch2",
revision: "revision2"
};
const branch3 = {
name: 'branch3',
revision: 'revision3',
defaultBranch: true,
name: "branch3",
revision: "revision3",
defaultBranch: true
};
const defaultBranch = {
name: 'default',
revision: 'revision4',
defaultBranch: false,
name: "default",
revision: "revision4",
defaultBranch: false
};
const developBranch = {
name: 'develop',
revision: 'revision5',
defaultBranch: false,
name: "develop",
revision: "revision5",
defaultBranch: false
};
const masterBranch = {
name: 'master',
revision: 'revision6',
defaultBranch: false,
name: "master",
revision: "revision6",
defaultBranch: false
};
describe('order branches', () => {
it('should return branches', () => {
describe("order branches", () => {
it("should return branches", () => {
let branches = [branch1, branch2];
orderBranches(branches);
expect(branches).toEqual([branch1, branch2]);
});
it('should return defaultBranch first', () => {
it("should return defaultBranch first", () => {
let branches = [branch1, branch2, branch3];
orderBranches(branches);
expect(branches).toEqual([branch3, branch1, branch2]);
});
it('should order special branches as follows: master > default > develop', () => {
it("should order special branches as follows: master > default > develop", () => {
let branches = [defaultBranch, developBranch, masterBranch];
orderBranches(branches);
expect(branches).toEqual([masterBranch, defaultBranch, developBranch]);
});
it('should order special branches but starting with defaultBranch', () => {
it("should order special branches but starting with defaultBranch", () => {
let branches = [masterBranch, developBranch, defaultBranch, branch3];
orderBranches(branches);
expect(branches).toEqual([
branch3,
masterBranch,
defaultBranch,
developBranch,
developBranch
]);
});
});

View File

@@ -1,6 +1,6 @@
// master, default should always be the first one,
// followed by develop the rest should be ordered by its name
import { Branch } from '@scm-manager/ui-types';
import { Branch } from "@scm-manager/ui-types";
export function orderBranches(branches: Branch[]) {
branches.sort((a, b) => {
@@ -8,17 +8,17 @@ export function orderBranches(branches: Branch[]) {
return -20;
} else if (!a.defaultBranch && b.defaultBranch) {
return 20;
} else if (a.name === 'master' && b.name !== 'master') {
} else if (a.name === "master" && b.name !== "master") {
return -10;
} else if (a.name !== 'master' && b.name === 'master') {
} else if (a.name !== "master" && b.name === "master") {
return 10;
} else if (a.name === 'default' && b.name !== 'default') {
} else if (a.name === "default" && b.name !== "default") {
return -10;
} else if (a.name !== 'default' && b.name === 'default') {
} else if (a.name !== "default" && b.name === "default") {
return 10;
} else if (a.name === 'develop' && b.name !== 'develop') {
} else if (a.name === "develop" && b.name !== "develop") {
return -5;
} else if (a.name !== 'develop' && b.name === 'develop') {
} else if (a.name !== "develop" && b.name === "develop") {
return 5;
} else if (a.name < b.name) {
return -1;

View File

@@ -1,34 +1,34 @@
import React from 'react';
import { shallow, mount } from '@scm-manager/ui-tests/enzyme-router';
import '@scm-manager/ui-tests/enzyme';
import '@scm-manager/ui-tests/i18n';
import React from "react";
import { shallow, mount } from "@scm-manager/ui-tests/enzyme-router";
import "@scm-manager/ui-tests/enzyme";
import "@scm-manager/ui-tests/i18n";
import EditRepoNavLink from './EditRepoNavLink';
import EditRepoNavLink from "./EditRepoNavLink";
describe('GeneralNavLink', () => {
it('should render nothing, if the modify link is missing', () => {
describe("GeneralNavLink", () => {
it("should render nothing, if the modify link is missing", () => {
const repository = {
_links: {},
_links: {}
};
const navLink = shallow(
<EditRepoNavLink repository={repository} editUrl="" />,
<EditRepoNavLink repository={repository} editUrl="" />
);
expect(navLink.text()).toBe('');
expect(navLink.text()).toBe("");
});
it('should render the navLink', () => {
it("should render the navLink", () => {
const repository = {
_links: {
update: {
href: '/repositories',
},
},
href: "/repositories"
}
}
};
const navLink = mount(
<EditRepoNavLink repository={repository} editUrl="" />,
<EditRepoNavLink repository={repository} editUrl="" />
);
expect(navLink.text()).toBe('repositoryRoot.menu.generalNavLink');
expect(navLink.text()).toBe("repositoryRoot.menu.generalNavLink");
});
});

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Repository } from '@scm-manager/ui-types';
import { NavLink } from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
import React from "react";
import { Repository } from "@scm-manager/ui-types";
import { NavLink } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
type Props = {
repository: Repository;
@@ -21,9 +21,9 @@ class EditRepoNavLink extends React.Component<Props> {
return null;
}
return (
<NavLink to={editUrl} label={t('repositoryRoot.menu.generalNavLink')} />
<NavLink to={editUrl} label={t("repositoryRoot.menu.generalNavLink")} />
);
}
}
export default translate('repos')(EditRepoNavLink);
export default translate("repos")(EditRepoNavLink);

View File

@@ -1,33 +1,33 @@
import React from 'react';
import { mount, shallow } from '@scm-manager/ui-tests/enzyme-router';
import '@scm-manager/ui-tests/enzyme';
import '@scm-manager/ui-tests/i18n';
import PermissionsNavLink from './PermissionsNavLink';
import React from "react";
import { mount, shallow } from "@scm-manager/ui-tests/enzyme-router";
import "@scm-manager/ui-tests/enzyme";
import "@scm-manager/ui-tests/i18n";
import PermissionsNavLink from "./PermissionsNavLink";
describe('PermissionsNavLink', () => {
it('should render nothing, if the modify link is missing', () => {
describe("PermissionsNavLink", () => {
it("should render nothing, if the modify link is missing", () => {
const repository = {
_links: {},
_links: {}
};
const navLink = shallow(
<PermissionsNavLink repository={repository} permissionUrl="" />,
<PermissionsNavLink repository={repository} permissionUrl="" />
);
expect(navLink.text()).toBe('');
expect(navLink.text()).toBe("");
});
it('should render the navLink', () => {
it("should render the navLink", () => {
const repository = {
_links: {
permissions: {
href: '/permissions',
},
},
href: "/permissions"
}
}
};
const navLink = mount(
<PermissionsNavLink repository={repository} permissionUrl="" />,
<PermissionsNavLink repository={repository} permissionUrl="" />
);
expect(navLink.text()).toBe('repositoryRoot.menu.permissionsNavLink');
expect(navLink.text()).toBe("repositoryRoot.menu.permissionsNavLink");
});
});

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { NavLink } from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
import { Repository } from '@scm-manager/ui-types';
import React from "react";
import { NavLink } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
import { Repository } from "@scm-manager/ui-types";
type Props = {
permissionUrl: string;
@@ -21,10 +21,10 @@ class PermissionsNavLink extends React.Component<Props> {
return (
<NavLink
to={permissionUrl}
label={t('repositoryRoot.menu.permissionsNavLink')}
label={t("repositoryRoot.menu.permissionsNavLink")}
/>
);
}
}
export default translate('repos')(PermissionsNavLink);
export default translate("repos")(PermissionsNavLink);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Repository } from '@scm-manager/ui-types';
import { MailLink, DateFromNow } from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
import React from "react";
import { Repository } from "@scm-manager/ui-types";
import { MailLink, DateFromNow } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
type Props = {
repository: Repository;
@@ -16,31 +16,31 @@ class RepositoryDetailTable extends React.Component<Props> {
<table className="table">
<tbody>
<tr>
<th>{t('repository.name')}</th>
<th>{t("repository.name")}</th>
<td>{repository.name}</td>
</tr>
<tr>
<th>{t('repository.type')}</th>
<th>{t("repository.type")}</th>
<td>{repository.type}</td>
</tr>
<tr>
<th>{t('repository.contact')}</th>
<th>{t("repository.contact")}</th>
<td>
<MailLink address={repository.contact} />
</td>
</tr>
<tr>
<th>{t('repository.description')}</th>
<th>{t("repository.description")}</th>
<td>{repository.description}</td>
</tr>
<tr>
<th>{t('repository.creationDate')}</th>
<th>{t("repository.creationDate")}</th>
<td>
<DateFromNow date={repository.creationDate} />
</td>
</tr>
<tr>
<th>{t('repository.lastModified')}</th>
<th>{t("repository.lastModified")}</th>
<td>
<DateFromNow date={repository.lastModified} />
</td>
@@ -51,4 +51,4 @@ class RepositoryDetailTable extends React.Component<Props> {
}
}
export default translate('repos')(RepositoryDetailTable);
export default translate("repos")(RepositoryDetailTable);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Repository } from '@scm-manager/ui-types';
import RepositoryDetailTable from './RepositoryDetailTable';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
import React from "react";
import { Repository } from "@scm-manager/ui-types";
import RepositoryDetailTable from "./RepositoryDetailTable";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
type Props = {
repository: Repository;
@@ -19,7 +19,7 @@ class RepositoryDetails extends React.Component<Props> {
name="repos.repository-details.information"
renderAll={true}
props={{
repository,
repository
}}
/>
</div>

View File

@@ -1,15 +1,15 @@
import React from 'react';
import { shallow, mount } from '@scm-manager/ui-tests/enzyme-router';
import '@scm-manager/ui-tests/i18n';
import RepositoryNavLink from './RepositoryNavLink';
import React from "react";
import { shallow, mount } from "@scm-manager/ui-tests/enzyme-router";
import "@scm-manager/ui-tests/i18n";
import RepositoryNavLink from "./RepositoryNavLink";
describe('RepositoryNavLink', () => {
it('should render nothing, if the sources link is missing', () => {
describe("RepositoryNavLink", () => {
it("should render nothing, if the sources link is missing", () => {
const repository = {
namespace: 'Namespace',
name: 'Repo',
type: 'GIT',
_links: {},
namespace: "Namespace",
name: "Repo",
type: "GIT",
_links: {}
};
const navLink = shallow(
@@ -19,21 +19,21 @@ describe('RepositoryNavLink', () => {
to="/sources"
label="Sources"
activeOnlyWhenExact={true}
/>,
/>
);
expect(navLink.text()).toBe('');
expect(navLink.text()).toBe("");
});
it('should render the navLink', () => {
it("should render the navLink", () => {
const repository = {
namespace: 'Namespace',
name: 'Repo',
type: 'GIT',
namespace: "Namespace",
name: "Repo",
type: "GIT",
_links: {
sources: {
href: '/sources',
},
},
href: "/sources"
}
}
};
const navLink = mount(
@@ -43,8 +43,8 @@ describe('RepositoryNavLink', () => {
to="/sources"
label="Sources"
activeOnlyWhenExact={true}
/>,
/>
);
expect(navLink.text()).toBe('Sources');
expect(navLink.text()).toBe("Sources");
});
});

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { Repository } from '@scm-manager/ui-types';
import { NavLink } from '@scm-manager/ui-components';
import React from "react";
import { Repository } from "@scm-manager/ui-types";
import { NavLink } from "@scm-manager/ui-components";
type Props = {
repository: Repository;

View File

@@ -1,9 +1,9 @@
import React from 'react';
import { Interpolate, translate } from 'react-i18next';
import classNames from 'classnames';
import styled from 'styled-components';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
import { Changeset, Repository, Tag } from '@scm-manager/ui-types';
import React from "react";
import { Interpolate, translate } from "react-i18next";
import classNames from "classnames";
import styled from "styled-components";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Changeset, Repository, Tag } from "@scm-manager/ui-types";
import {
DateFromNow,
ChangesetId,
@@ -14,8 +14,8 @@ import {
AvatarImage,
changesets,
Level,
Button,
} from '@scm-manager/ui-components';
Button
} from "@scm-manager/ui-components";
type Props = {
changeset: Changeset;
@@ -47,7 +47,7 @@ class ChangesetDetails extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
collapsed: false,
collapsed: false
};
}
@@ -63,13 +63,13 @@ class ChangesetDetails extends React.Component<Props, State> {
return (
<>
<div className={classNames('content', 'is-marginless')}>
<div className={classNames("content", "is-marginless")}>
<h4>
<ExtensionPoint
name="changeset.description"
props={{
changeset,
value: description.title,
value: description.title
}}
renderAll={false}
>
@@ -78,7 +78,7 @@ class ChangesetDetails extends React.Component<Props, State> {
</h4>
<article className="media">
<AvatarWrapper>
<RightMarginP className={classNames('image', 'is-64x64')}>
<RightMarginP className={classNames("image", "is-64x64")}>
<AvatarImage person={changeset.author} />
</RightMarginP>
</AvatarWrapper>
@@ -94,14 +94,14 @@ class ChangesetDetails extends React.Component<Props, State> {
</article>
<p>
{description.message.split('\n').map((item, key) => {
{description.message.split("\n").map((item, key) => {
return (
<span key={key}>
<ExtensionPoint
name="changeset.description"
props={{
changeset,
value: item,
value: item
}}
renderAll={false}
>
@@ -119,8 +119,8 @@ class ChangesetDetails extends React.Component<Props, State> {
<Button
action={this.collapseDiffs}
color="default"
icon={collapsed ? 'eye' : 'eye-slash'}
label={t('changesets.collapseDiffs')}
icon={collapsed ? "eye" : "eye-slash"}
label={t("changesets.collapseDiffs")}
reducedMobile={true}
/>
}
@@ -151,9 +151,9 @@ class ChangesetDetails extends React.Component<Props, State> {
collapseDiffs = () => {
this.setState(state => ({
collapsed: !state.collapsed,
collapsed: !state.collapsed
}));
};
}
export default translate('repos')(ChangesetDetails);
export default translate("repos")(ChangesetDetails);

View File

@@ -1,15 +1,15 @@
import React from 'react';
import { translate } from 'react-i18next';
import React from "react";
import { translate } from "react-i18next";
import {
Subtitle,
InputField,
Select,
SubmitButton,
Textarea,
} from '@scm-manager/ui-components';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
import { Repository, RepositoryType } from '@scm-manager/ui-types';
import * as validator from './repositoryValidation';
Textarea
} from "@scm-manager/ui-components";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Repository, RepositoryType } from "@scm-manager/ui-types";
import * as validator from "./repositoryValidation";
type Props = {
submitForm: (p: Repository) => void;
@@ -27,7 +27,7 @@ type State = {
contactValidationError: boolean;
};
const CUSTOM_NAMESPACE_STRATEGY = 'CustomNamespaceStrategy';
const CUSTOM_NAMESPACE_STRATEGY = "CustomNamespaceStrategy";
class RepositoryForm extends React.Component<Props, State> {
constructor(props: Props) {
@@ -35,16 +35,16 @@ class RepositoryForm extends React.Component<Props, State> {
this.state = {
repository: {
name: '',
namespace: '',
type: '',
contact: '',
description: '',
_links: {},
name: "",
namespace: "",
type: "",
contact: "",
description: "",
_links: {}
},
namespaceValidationError: false,
nameValidationError: false,
contactValidationError: false,
contactValidationError: false
};
}
@@ -53,8 +53,8 @@ class RepositoryForm extends React.Component<Props, State> {
if (repository) {
this.setState({
repository: {
...repository,
},
...repository
}
});
}
}
@@ -104,14 +104,14 @@ class RepositoryForm extends React.Component<Props, State> {
<SubmitButton
disabled={!this.isValid()}
loading={loading}
label={t('repositoryForm.submit')}
label={t("repositoryForm.submit")}
/>
);
let subtitle = null;
if (this.props.repository) {
// edit existing repo
subtitle = <Subtitle subtitle={t('repositoryForm.subtitle')} />;
subtitle = <Subtitle subtitle={t("repositoryForm.subtitle")} />;
}
return (
@@ -120,20 +120,20 @@ class RepositoryForm extends React.Component<Props, State> {
<form onSubmit={this.submit}>
{this.renderCreateOnlyFields()}
<InputField
label={t('repository.contact')}
label={t("repository.contact")}
onChange={this.handleContactChange}
value={repository ? repository.contact : ''}
value={repository ? repository.contact : ""}
validationError={this.state.contactValidationError}
errorMessage={t('validation.contact-invalid')}
helpText={t('help.contactHelpText')}
errorMessage={t("validation.contact-invalid")}
helpText={t("help.contactHelpText")}
disabled={disabled}
/>
<Textarea
label={t('repository.description')}
label={t("repository.description")}
onChange={this.handleDescriptionChange}
value={repository ? repository.description : ''}
helpText={t('help.descriptionHelpText')}
value={repository ? repository.description : ""}
helpText={t("help.descriptionHelpText")}
disabled={disabled}
/>
{submitButton}
@@ -146,7 +146,7 @@ class RepositoryForm extends React.Component<Props, State> {
return repositoryTypes.map(repositoryType => {
return {
label: repositoryType.displayName,
value: repositoryType.name,
value: repositoryType.name
};
});
}
@@ -155,12 +155,12 @@ class RepositoryForm extends React.Component<Props, State> {
const { namespaceStrategy, t } = this.props;
const repository = this.state.repository;
const props = {
label: t('repository.namespace'),
helpText: t('help.namespaceHelpText'),
value: repository ? repository.namespace : '',
label: t("repository.namespace"),
helpText: t("help.namespaceHelpText"),
value: repository ? repository.namespace : "",
onChange: this.handleNamespaceChange,
errorMessage: t('validation.namespace-invalid'),
validationError: this.state.namespaceValidationError,
errorMessage: t("validation.namespace-invalid"),
validationError: this.state.namespaceValidationError
};
if (namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY) {
@@ -186,19 +186,19 @@ class RepositoryForm extends React.Component<Props, State> {
<>
{this.renderNamespaceField()}
<InputField
label={t('repository.name')}
label={t("repository.name")}
onChange={this.handleNameChange}
value={repository ? repository.name : ''}
value={repository ? repository.name : ""}
validationError={this.state.nameValidationError}
errorMessage={t('validation.name-invalid')}
helpText={t('help.nameHelpText')}
errorMessage={t("validation.name-invalid")}
helpText={t("help.nameHelpText")}
/>
<Select
label={t('repository.type')}
label={t("repository.type")}
onChange={this.handleTypeChange}
value={repository ? repository.type : ''}
value={repository ? repository.type : ""}
options={this.createSelectOptions(repositoryTypes)}
helpText={t('help.typeHelpText')}
helpText={t("help.typeHelpText")}
/>
</>
);
@@ -209,8 +209,8 @@ class RepositoryForm extends React.Component<Props, State> {
namespaceValidationError: !validator.isNameValid(namespace),
repository: {
...this.state.repository,
namespace,
},
namespace
}
});
};
@@ -219,8 +219,8 @@ class RepositoryForm extends React.Component<Props, State> {
nameValidationError: !validator.isNameValid(name),
repository: {
...this.state.repository,
name,
},
name
}
});
};
@@ -228,8 +228,8 @@ class RepositoryForm extends React.Component<Props, State> {
this.setState({
repository: {
...this.state.repository,
type,
},
type
}
});
};
@@ -238,8 +238,8 @@ class RepositoryForm extends React.Component<Props, State> {
contactValidationError: !validator.isContactValid(contact),
repository: {
...this.state.repository,
contact,
},
contact
}
});
};
@@ -247,10 +247,10 @@ class RepositoryForm extends React.Component<Props, State> {
this.setState({
repository: {
...this.state.repository,
description,
},
description
}
});
};
}
export default translate('repos')(RepositoryForm);
export default translate("repos")(RepositoryForm);

View File

@@ -1,2 +1,2 @@
import RepositoryForm from './RepositoryForm';
import RepositoryForm from "./RepositoryForm";
export default RepositoryForm;

View File

@@ -1,104 +1,104 @@
import * as validator from './repositoryValidation';
import * as validator from "./repositoryValidation";
describe('repository name validation', () => {
describe("repository name validation", () => {
// we don't need rich tests, because they are in validation.test.js
it('should validate the name', () => {
expect(validator.isNameValid('scm-manager')).toBe(true);
it("should validate the name", () => {
expect(validator.isNameValid("scm-manager")).toBe(true);
});
it('should fail for old nested repository names', () => {
it("should fail for old nested repository names", () => {
// in v2 this is not allowed
expect(validator.isNameValid('scm/manager')).toBe(false);
expect(validator.isNameValid('scm/ma/nager')).toBe(false);
expect(validator.isNameValid("scm/manager")).toBe(false);
expect(validator.isNameValid("scm/ma/nager")).toBe(false);
});
it('should allow same names as the backend', () => {
it("should allow same names as the backend", () => {
const validPaths = [
'scm',
's',
'sc',
'.hiddenrepo',
'b.',
'...',
'..c',
'd..',
'a..c',
"scm",
"s",
"sc",
".hiddenrepo",
"b.",
"...",
"..c",
"d..",
"a..c"
];
validPaths.forEach(path => expect(validator.isNameValid(path)).toBe(true));
});
it('should deny same names as the backend', () => {
it("should deny same names as the backend", () => {
const invalidPaths = [
'.',
'/',
'//',
'..',
'/.',
'/..',
'./',
'../',
'/../',
'/./',
'/...',
'/abc',
'.../',
'/sdf/',
'asdf/',
'./b',
'scm/plugins/.',
'scm/../plugins',
'scm/main/',
'/scm/main/',
'scm/./main',
'scm//main',
'scm\\main',
'scm/main-$HOME',
'scm/main-${HOME}-home',
'scm/main-%HOME-home',
'scm/main-%HOME%-home',
'abc$abc',
'abc%abc',
'abc<abc',
'abc>abc',
'abc#abc',
'abc+abc',
'abc{abc',
'abc}abc',
'abc(abc',
'abc)abc',
'abc[abc',
'abc]abc',
'abc|abc',
'scm/main',
'scm/plugins/git-plugin',
'.scm/plugins',
'a/b..',
'a/..b',
'scm/main',
'scm/plugins/git-plugin',
'scm/plugins/git-plugin',
".",
"/",
"//",
"..",
"/.",
"/..",
"./",
"../",
"/../",
"/./",
"/...",
"/abc",
".../",
"/sdf/",
"asdf/",
"./b",
"scm/plugins/.",
"scm/../plugins",
"scm/main/",
"/scm/main/",
"scm/./main",
"scm//main",
"scm\\main",
"scm/main-$HOME",
"scm/main-${HOME}-home",
"scm/main-%HOME-home",
"scm/main-%HOME%-home",
"abc$abc",
"abc%abc",
"abc<abc",
"abc>abc",
"abc#abc",
"abc+abc",
"abc{abc",
"abc}abc",
"abc(abc",
"abc)abc",
"abc[abc",
"abc]abc",
"abc|abc",
"scm/main",
"scm/plugins/git-plugin",
".scm/plugins",
"a/b..",
"a/..b",
"scm/main",
"scm/plugins/git-plugin",
"scm/plugins/git-plugin"
];
invalidPaths.forEach(path =>
expect(validator.isNameValid(path)).toBe(false),
expect(validator.isNameValid(path)).toBe(false)
);
});
});
describe('repository contact validation', () => {
it('should allow empty contact', () => {
expect(validator.isContactValid('')).toBe(true);
describe("repository contact validation", () => {
it("should allow empty contact", () => {
expect(validator.isContactValid("")).toBe(true);
});
// we don't need rich tests, because they are in validation.test.js
it('should allow real mail addresses', () => {
expect(validator.isContactValid('trici.mcmillian@hitchhiker.com')).toBe(
true,
it("should allow real mail addresses", () => {
expect(validator.isContactValid("trici.mcmillian@hitchhiker.com")).toBe(
true
);
});
it('should fail on invalid mail addresses', () => {
expect(validator.isContactValid('tricia')).toBe(false);
it("should fail on invalid mail addresses", () => {
expect(validator.isContactValid("tricia")).toBe(false);
});
});

View File

@@ -1,4 +1,4 @@
import { validation } from '@scm-manager/ui-components';
import { validation } from "@scm-manager/ui-components";
const nameRegex = /(?!^\.\.$)(?!^\.$)(?!.*[\\\[\]])^[A-Za-z0-9\.][A-Za-z0-9\.\-_]*$/;
@@ -7,5 +7,5 @@ export const isNameValid = (name: string) => {
};
export function isContactValid(mail: string) {
return '' === mail || validation.isMailValid(mail);
return "" === mail || validation.isMailValid(mail);
}

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
import { Repository } from '@scm-manager/ui-types';
import { Image } from '@scm-manager/ui-components';
import React from "react";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { Repository } from "@scm-manager/ui-types";
import { Image } from "@scm-manager/ui-components";
type Props = {
repository: Repository;
@@ -15,7 +15,7 @@ class RepositoryAvatar extends React.Component<Props> {
<ExtensionPoint
name="repos.repository-avatar"
props={{
repository,
repository
}}
>
<Image src="/images/blib.jpg" alt="Logo" />

View File

@@ -1,8 +1,8 @@
import React from 'react';
import { Repository } from '@scm-manager/ui-types';
import { CardColumn, DateFromNow } from '@scm-manager/ui-components';
import RepositoryEntryLink from './RepositoryEntryLink';
import RepositoryAvatar from './RepositoryAvatar';
import React from "react";
import { Repository } from "@scm-manager/ui-types";
import { CardColumn, DateFromNow } from "@scm-manager/ui-components";
import RepositoryEntryLink from "./RepositoryEntryLink";
import RepositoryAvatar from "./RepositoryAvatar";
type Props = {
repository: Repository;
@@ -14,11 +14,11 @@ class RepositoryEntry extends React.Component<Props> {
};
renderBranchesLink = (repository: Repository, repositoryLink: string) => {
if (repository._links['branches']) {
if (repository._links["branches"]) {
return (
<RepositoryEntryLink
icon="code-branch"
to={repositoryLink + '/branches'}
to={repositoryLink + "/branches"}
/>
);
}
@@ -26,11 +26,11 @@ class RepositoryEntry extends React.Component<Props> {
};
renderChangesetsLink = (repository: Repository, repositoryLink: string) => {
if (repository._links['changesets']) {
if (repository._links["changesets"]) {
return (
<RepositoryEntryLink
icon="exchange-alt"
to={repositoryLink + '/changesets'}
to={repositoryLink + "/changesets"}
/>
);
}
@@ -38,20 +38,20 @@ class RepositoryEntry extends React.Component<Props> {
};
renderSourcesLink = (repository: Repository, repositoryLink: string) => {
if (repository._links['sources']) {
if (repository._links["sources"]) {
return (
<RepositoryEntryLink icon="code" to={repositoryLink + '/sources'} />
<RepositoryEntryLink icon="code" to={repositoryLink + "/sources"} />
);
}
return null;
};
renderModifyLink = (repository: Repository, repositoryLink: string) => {
if (repository._links['update']) {
if (repository._links["update"]) {
return (
<RepositoryEntryLink
icon="cog"
to={repositoryLink + '/settings/general'}
to={repositoryLink + "/settings/general"}
/>
);
}

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { Icon } from '@scm-manager/ui-components';
import React from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";
import { Icon } from "@scm-manager/ui-components";
type Props = {
to: string;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { CardColumnGroup } from '@scm-manager/ui-components';
import { RepositoryGroup } from '@scm-manager/ui-types';
import RepositoryEntry from './RepositoryEntry';
import React from "react";
import { CardColumnGroup } from "@scm-manager/ui-components";
import { RepositoryGroup } from "@scm-manager/ui-types";
import RepositoryEntry from "./RepositoryEntry";
type Props = {
group: RepositoryGroup;

View File

@@ -1,9 +1,9 @@
import React from 'react';
import React from "react";
import { Repository } from '@scm-manager/ui-types';
import { Repository } from "@scm-manager/ui-types";
import groupByNamespace from './groupByNamespace';
import RepositoryGroupEntry from './RepositoryGroupEntry';
import groupByNamespace from "./groupByNamespace";
import RepositoryGroupEntry from "./RepositoryGroupEntry";
type Props = {
repositories: Repository[];

View File

@@ -1,72 +1,72 @@
import groupByNamespace from './groupByNamespace';
import groupByNamespace from "./groupByNamespace";
const base = {
type: 'git',
_links: {},
type: "git",
_links: {}
};
const slartiBlueprintsFjords = {
...base,
namespace: 'slarti',
name: 'fjords-blueprints',
namespace: "slarti",
name: "fjords-blueprints"
};
const slartiFjords = {
...base,
namespace: 'slarti',
name: 'fjords',
namespace: "slarti",
name: "fjords"
};
const hitchhikerRestand = {
...base,
namespace: 'hitchhiker',
name: 'restand',
namespace: "hitchhiker",
name: "restand"
};
const hitchhikerPuzzle42 = {
...base,
namespace: 'hitchhiker',
name: 'puzzle42',
namespace: "hitchhiker",
name: "puzzle42"
};
const hitchhikerHeartOfGold = {
...base,
namespace: 'hitchhiker',
name: 'heartOfGold',
namespace: "hitchhiker",
name: "heartOfGold"
};
const zaphodMarvinFirmware = {
...base,
namespace: 'zaphod',
name: 'marvin-firmware',
namespace: "zaphod",
name: "marvin-firmware"
};
it('should group the repositories by their namespace', () => {
it("should group the repositories by their namespace", () => {
const repositories = [
zaphodMarvinFirmware,
slartiBlueprintsFjords,
hitchhikerRestand,
slartiFjords,
hitchhikerHeartOfGold,
hitchhikerPuzzle42,
hitchhikerPuzzle42
];
const expected = [
{
name: 'hitchhiker',
name: "hitchhiker",
repositories: [
hitchhikerHeartOfGold,
hitchhikerPuzzle42,
hitchhikerRestand,
],
hitchhikerRestand
]
},
{
name: 'slarti',
repositories: [slartiFjords, slartiBlueprintsFjords],
name: "slarti",
repositories: [slartiFjords, slartiBlueprintsFjords]
},
{
name: 'zaphod',
repositories: [zaphodMarvinFirmware],
},
name: "zaphod",
repositories: [zaphodMarvinFirmware]
}
];
expect(groupByNamespace(repositories)).toEqual(expected);

View File

@@ -1,7 +1,7 @@
import { Repository, RepositoryGroup } from '@scm-manager/ui-types';
import { Repository, RepositoryGroup } from "@scm-manager/ui-types";
export default function groupByNamespace(
repositories: Repository[],
repositories: Repository[]
): RepositoryGroup[] {
let groups = {};
for (let repository of repositories) {
@@ -11,7 +11,7 @@ export default function groupByNamespace(
if (!group) {
group = {
name: groupName,
repositories: [],
repositories: []
};
groups[groupName] = group;
}

View File

@@ -1,2 +1,2 @@
import RepositoryList from './RepositoryList';
import RepositoryList from "./RepositoryList";
export default RepositoryList;

View File

@@ -1,16 +1,16 @@
import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { Changeset, Repository } from '@scm-manager/ui-types';
import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { 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';
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;
@@ -36,8 +36,8 @@ class ChangesetView extends React.Component<Props> {
if (error) {
return (
<ErrorPage
title={t('changesets.errorTitle')}
subtitle={t('changesets.errorSubtitle')}
title={t("changesets.errorTitle")}
subtitle={t("changesets.errorSubtitle")}
error={error}
/>
);
@@ -58,7 +58,7 @@ const mapStateToProps = (state, ownProps: Props) => {
return {
changeset,
error,
loading,
loading
};
};
@@ -66,13 +66,13 @@ const mapDispatchToProps = dispatch => {
return {
fetchChangesetIfNeeded: (repository: Repository, id: string) => {
dispatch(fetchChangesetIfNeeded(repository, id));
},
}
};
};
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps,
)(translate('repos')(ChangesetView)),
mapDispatchToProps
)(translate("repos")(ChangesetView))
);

View File

@@ -1,30 +1,30 @@
import React from 'react';
import { withRouter } from 'react-router-dom';
import React from "react";
import { withRouter } from "react-router-dom";
import {
Branch,
Changeset,
PagedCollection,
Repository,
} from '@scm-manager/ui-types';
Repository
} from "@scm-manager/ui-types";
import {
fetchChangesets,
getChangesets,
getFetchChangesetsFailure,
isFetchChangesetsPending,
selectListAsCollection,
} from '../modules/changesets';
selectListAsCollection
} from "../modules/changesets";
import { connect } from 'react-redux';
import { connect } from "react-redux";
import {
ErrorNotification,
getPageFromMatch,
LinkPaginator,
ChangesetList,
Loading,
Notification,
} from '@scm-manager/ui-components';
import { compose } from 'redux';
import { translate } from 'react-i18next';
Notification
} from "@scm-manager/ui-components";
import { compose } from "redux";
import { translate } from "react-i18next";
type Props = {
repository: Repository;
@@ -67,7 +67,7 @@ class Changesets extends React.Component<Props> {
return (
<div className="panel-block">
<Notification type="info">
{t('changesets.noChangesets')}
{t("changesets.noChangesets")}
</Notification>
</div>
);
@@ -106,7 +106,7 @@ const mapDispatchToProps = dispatch => {
return {
fetchChangesets: (repo: Repository, branch: Branch, page: number) => {
dispatch(fetchChangesets(repo, branch, page));
},
}
};
};
@@ -123,15 +123,15 @@ const mapStateToProps = (state: any, ownProps: Props) => {
list,
page,
loading,
error,
error
};
};
export default compose(
translate('repos'),
translate("repos"),
withRouter,
connect(
mapStateToProps,
mapDispatchToProps,
),
mapDispatchToProps
)
)(Changesets);

View File

@@ -1,21 +1,21 @@
import React from 'react';
import { Branch, Repository } from '@scm-manager/ui-types';
import { translate } from 'react-i18next';
import { Route, withRouter } from 'react-router-dom';
import Changesets from './Changesets';
import { connect } from 'react-redux';
import React from "react";
import { Branch, Repository } from "@scm-manager/ui-types";
import { translate } from "react-i18next";
import { Route, withRouter } from "react-router-dom";
import Changesets from "./Changesets";
import { connect } from "react-redux";
import {
BranchSelector,
ErrorNotification,
Loading,
} from '@scm-manager/ui-components';
Loading
} from "@scm-manager/ui-components";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending,
} from '../branches/modules/branches';
import { compose } from 'redux';
isFetchBranchesPending
} from "../branches/modules/branches";
import { compose } from "redux";
type Props = {
repository: Repository;
@@ -47,7 +47,7 @@ class ChangesetsRoot extends React.Component<Props> {
redirectToDefaultBranch = () => {
if (this.shouldRedirectToDefaultBranch()) {
const defaultBranches = this.props.branches.filter(
b => b.defaultBranch === true,
b => b.defaultBranch === true
);
if (defaultBranches.length > 0) {
this.branchSelected(defaultBranches[0]);
@@ -65,7 +65,7 @@ class ChangesetsRoot extends React.Component<Props> {
};
stripEndingSlash = (url: string) => {
if (url.endsWith('/')) {
if (url.endsWith("/")) {
return url.substring(0, url.length - 1);
}
return url;
@@ -75,7 +75,7 @@ class ChangesetsRoot extends React.Component<Props> {
let url;
if (branch) {
url = `${this.props.baseUrlWithBranch}/${encodeURIComponent(
branch.name,
branch.name
)}/changesets/`;
} else {
url = `${this.props.baseUrlWithoutBranch}/`;
@@ -121,7 +121,7 @@ class ChangesetsRoot extends React.Component<Props> {
return (
<div className="panel-heading">
<BranchSelector
label={t('changesets.branchSelectorLabel')}
label={t("changesets.branchSelectorLabel")}
branches={branches}
selectedBranch={selected}
selected={(b: Branch) => {
@@ -139,7 +139,7 @@ const mapDispatchToProps = dispatch => {
return {
fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo));
},
}
};
};
@@ -154,15 +154,15 @@ const mapStateToProps = (state: any, ownProps: Props) => {
loading,
error,
branches,
selected,
selected
};
};
export default compose(
withRouter,
translate('repos'),
translate("repos"),
connect(
mapStateToProps,
mapDispatchToProps,
),
mapDispatchToProps
)
)(ChangesetsRoot);

View File

@@ -1,33 +1,33 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import { Page } from '@scm-manager/ui-components';
import RepositoryForm from '../components/form';
import React from "react";
import { connect } from "react-redux";
import { translate } from "react-i18next";
import { Page } from "@scm-manager/ui-components";
import RepositoryForm from "../components/form";
import {
Repository,
RepositoryType,
NamespaceStrategies,
} from '@scm-manager/ui-types';
NamespaceStrategies
} from "@scm-manager/ui-types";
import {
fetchRepositoryTypesIfNeeded,
getFetchRepositoryTypesFailure,
getRepositoryTypes,
isFetchRepositoryTypesPending,
} from '../modules/repositoryTypes';
isFetchRepositoryTypesPending
} from "../modules/repositoryTypes";
import {
createRepo,
createRepoReset,
getCreateRepoFailure,
isCreateRepoPending,
} from '../modules/repos';
import { History } from 'history';
import { getRepositoriesLink } from '../../modules/indexResource';
isCreateRepoPending
} from "../modules/repos";
import { History } from "history";
import { getRepositoriesLink } from "../../modules/indexResource";
import {
fetchNamespaceStrategiesIfNeeded,
getFetchNamespaceStrategiesFailure,
getNamespaceStrategies,
isFetchNamespaceStrategiesPending,
} from '../../admin/modules/namespaceStrategies';
isFetchNamespaceStrategiesPending
} from "../../admin/modules/namespaceStrategies";
type Props = {
repositoryTypes: RepositoryType[];
@@ -43,7 +43,7 @@ type Props = {
createRepo: (
link: string,
p2: Repository,
callback: (repo: Repository) => void,
callback: (repo: Repository) => void
) => void;
resetForm: () => void;
@@ -62,7 +62,7 @@ class Create extends React.Component<Props> {
repoCreated = (repo: Repository) => {
const { history } = this.props;
history.push('/repo/' + repo.namespace + '/' + repo.name);
history.push("/repo/" + repo.namespace + "/" + repo.name);
};
render() {
@@ -72,14 +72,14 @@ class Create extends React.Component<Props> {
repositoryTypes,
namespaceStrategies,
createRepo,
error,
error
} = this.props;
const { t, repoLink } = this.props;
return (
<Page
title={t('create.title')}
subtitle={t('create.subtitle')}
title={t("create.title")}
subtitle={t("create.subtitle")}
loading={pageLoading}
error={error}
showContentOnError={true}
@@ -90,7 +90,7 @@ class Create extends React.Component<Props> {
namespaceStrategy={namespaceStrategies.current}
submitForm={repo => {
createRepo(repoLink, repo, (repo: Repository) =>
this.repoCreated(repo),
this.repoCreated(repo)
);
}}
/>
@@ -117,7 +117,7 @@ const mapStateToProps = state => {
pageLoading,
createLoading,
error,
repoLink,
repoLink
};
};
@@ -132,17 +132,17 @@ const mapDispatchToProps = dispatch => {
createRepo: (
link: string,
repository: Repository,
callback: () => void,
callback: () => void
) => {
dispatch(createRepo(link, repository, callback));
},
resetForm: () => {
dispatch(createRepoReset());
},
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(translate('repos')(Create));
mapDispatchToProps
)(translate("repos")(Create));

View File

@@ -1,20 +1,20 @@
import React from 'react';
import { translate } from 'react-i18next';
import { Repository } from '@scm-manager/ui-types';
import React from "react";
import { translate } from "react-i18next";
import { Repository } from "@scm-manager/ui-types";
import {
Subtitle,
DeleteButton,
confirmAlert,
ErrorNotification,
} from '@scm-manager/ui-components';
ErrorNotification
} from "@scm-manager/ui-components";
import {
deleteRepo,
getDeleteRepoFailure,
isDeleteRepoPending,
} from '../modules/repos';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { History } from 'history';
isDeleteRepoPending
} from "../modules/repos";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { History } from "history";
type Props = {
loading: boolean;
@@ -30,11 +30,11 @@ type Props = {
class DeleteRepo extends React.Component<Props> {
static defaultProps = {
confirmDialog: true,
confirmDialog: true
};
deleted = () => {
this.props.history.push('/repos/');
this.props.history.push("/repos/");
};
deleteRepo = () => {
@@ -44,18 +44,18 @@ class DeleteRepo extends React.Component<Props> {
confirmDelete = () => {
const { t } = this.props;
confirmAlert({
title: t('deleteRepo.confirmAlert.title'),
message: t('deleteRepo.confirmAlert.message'),
title: t("deleteRepo.confirmAlert.title"),
message: t("deleteRepo.confirmAlert.message"),
buttons: [
{
label: t('deleteRepo.confirmAlert.submit'),
onClick: () => this.deleteRepo(),
label: t("deleteRepo.confirmAlert.submit"),
onClick: () => this.deleteRepo()
},
{
label: t('deleteRepo.confirmAlert.cancel'),
onClick: () => null,
},
],
label: t("deleteRepo.confirmAlert.cancel"),
onClick: () => null
}
]
});
};
@@ -74,12 +74,12 @@ class DeleteRepo extends React.Component<Props> {
return (
<>
<hr />
<Subtitle subtitle={t('deleteRepo.subtitle')} />
<Subtitle subtitle={t("deleteRepo.subtitle")} />
<ErrorNotification error={error} />
<div className="columns">
<div className="column">
<DeleteButton
label={t('deleteRepo.button')}
label={t("deleteRepo.button")}
action={action}
loading={loading}
/>
@@ -96,7 +96,7 @@ const mapStateToProps = (state, ownProps) => {
const error = getDeleteRepoFailure(state, namespace, name);
return {
loading,
error,
error
};
};
@@ -104,11 +104,11 @@ const mapDispatchToProps = dispatch => {
return {
deleteRepo: (repo: Repository, callback: () => void) => {
dispatch(deleteRepo(repo, callback));
},
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(withRouter(translate('repos')(DeleteRepo)));
mapDispatchToProps
)(withRouter(translate("repos")(DeleteRepo)));

View File

@@ -1,18 +1,18 @@
import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import RepositoryForm from '../components/form';
import DeleteRepo from './DeleteRepo';
import { Repository } from '@scm-manager/ui-types';
import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import RepositoryForm from "../components/form";
import DeleteRepo from "./DeleteRepo";
import { Repository } from "@scm-manager/ui-types";
import {
modifyRepo,
isModifyRepoPending,
getModifyRepoFailure,
modifyRepoReset,
} from '../modules/repos';
import { History } from 'history';
import { ErrorNotification } from '@scm-manager/ui-components';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
modifyRepoReset
} from "../modules/repos";
import { History } from "history";
import { ErrorNotification } from "@scm-manager/ui-components";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
type Props = {
loading: boolean;
@@ -39,7 +39,7 @@ class EditRepo extends React.Component<Props> {
};
stripEndingSlash = (url: string) => {
if (url.endsWith('/')) {
if (url.endsWith("/")) {
return url.substring(0, url.length - 2);
}
return url;
@@ -56,7 +56,7 @@ class EditRepo extends React.Component<Props> {
const extensionProps = {
repository,
url,
url
};
return (
@@ -86,7 +86,7 @@ const mapStateToProps = (state, ownProps) => {
const error = getModifyRepoFailure(state, namespace, name);
return {
loading,
error,
error
};
};
@@ -97,11 +97,11 @@ const mapDispatchToProps = dispatch => {
},
modifyRepoReset: (repo: Repository) => {
dispatch(modifyRepoReset(repo));
},
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
mapDispatchToProps
)(withRouter(EditRepo));

View File

@@ -1,16 +1,16 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import { History } from 'history';
import { withRouter } from 'react-router-dom';
import { RepositoryCollection } from '@scm-manager/ui-types';
import React from "react";
import { connect } from "react-redux";
import { translate } from "react-i18next";
import { History } from "history";
import { withRouter } from "react-router-dom";
import { RepositoryCollection } from "@scm-manager/ui-types";
import {
fetchReposByPage,
getFetchReposFailure,
getRepositoryCollection,
isAbleToCreateRepos,
isFetchReposPending,
} from '../modules/repos';
isFetchReposPending
} from "../modules/repos";
import {
Page,
PageActions,
@@ -18,10 +18,10 @@ import {
CreateButton,
Notification,
LinkPaginator,
urls,
} from '@scm-manager/ui-components';
import RepositoryList from '../components/list';
import { getRepositoriesLink } from '../../modules/indexResource';
urls
} from "@scm-manager/ui-components";
import RepositoryList from "../components/list";
import { getRepositoriesLink } from "../../modules/indexResource";
type Props = {
loading: boolean;
@@ -46,7 +46,7 @@ class Overview extends React.Component<Props> {
fetchReposByPage(
reposLink,
page,
urls.getQueryStringFromLocation(location),
urls.getQueryStringFromLocation(location)
);
}
@@ -57,7 +57,7 @@ class Overview extends React.Component<Props> {
page,
reposLink,
location,
fetchReposByPage,
fetchReposByPage
} = this.props;
if (collection && page && !loading) {
const statePage: number = collection.page + 1;
@@ -65,7 +65,7 @@ class Overview extends React.Component<Props> {
fetchReposByPage(
reposLink,
page,
urls.getQueryStringFromLocation(location),
urls.getQueryStringFromLocation(location)
);
}
}
@@ -75,8 +75,8 @@ class Overview extends React.Component<Props> {
const { error, loading, showCreateButton, t } = this.props;
return (
<Page
title={t('overview.title')}
subtitle={t('overview.subtitle')}
title={t("overview.title")}
subtitle={t("overview.subtitle")}
loading={loading}
error={error}
>
@@ -85,7 +85,7 @@ class Overview extends React.Component<Props> {
<OverviewPageActions
showCreateButton={showCreateButton}
link="repos"
label={t('overview.createButton')}
label={t("overview.createButton")}
/>
</PageActions>
</Page>
@@ -108,7 +108,7 @@ class Overview extends React.Component<Props> {
);
}
return (
<Notification type="info">{t('overview.noRepositories')}</Notification>
<Notification type="info">{t("overview.noRepositories")}</Notification>
);
}
@@ -129,7 +129,7 @@ class Overview extends React.Component<Props> {
const { showCreateButton, t } = this.props;
if (showCreateButton) {
return (
<CreateButton label={t('overview.createButton')} link="/repos/create" />
<CreateButton label={t("overview.createButton")} link="/repos/create" />
);
}
return null;
@@ -150,7 +150,7 @@ const mapStateToProps = (state, ownProps) => {
error,
page,
showCreateButton,
reposLink,
reposLink
};
};
@@ -158,10 +158,10 @@ const mapDispatchToProps = dispatch => {
return {
fetchReposByPage: (link: string, page: number, filter?: string) => {
dispatch(fetchReposByPage(link, page, filter));
},
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(translate('repos')(withRouter(Overview)));
mapDispatchToProps
)(translate("repos")(withRouter(Overview)));

View File

@@ -1,14 +1,14 @@
import React from 'react';
import React from "react";
import {
fetchRepoByName,
getFetchRepoFailure,
getRepository,
isFetchRepoPending,
} from '../modules/repos';
isFetchRepoPending
} from "../modules/repos";
import { connect } from 'react-redux';
import { Redirect, Route, Switch } from 'react-router-dom';
import { Repository } from '@scm-manager/ui-types';
import { connect } from "react-redux";
import { Redirect, Route, Switch } from "react-router-dom";
import { Repository } from "@scm-manager/ui-types";
import {
ErrorPage,
@@ -17,25 +17,25 @@ import {
NavLink,
Page,
Section,
SubNavigation,
} from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
import RepositoryDetails from '../components/RepositoryDetails';
import EditRepo from './EditRepo';
import BranchesOverview from '../branches/containers/BranchesOverview';
import CreateBranch from '../branches/containers/CreateBranch';
import Permissions from '../permissions/containers/Permissions';
SubNavigation
} from "@scm-manager/ui-components";
import { translate } from "react-i18next";
import RepositoryDetails from "../components/RepositoryDetails";
import EditRepo from "./EditRepo";
import BranchesOverview from "../branches/containers/BranchesOverview";
import CreateBranch from "../branches/containers/CreateBranch";
import Permissions from "../permissions/containers/Permissions";
import { History } from 'history';
import EditRepoNavLink from '../components/EditRepoNavLink';
import BranchRoot from '../branches/containers/BranchRoot';
import ChangesetsRoot from './ChangesetsRoot';
import ChangesetView from './ChangesetView';
import PermissionsNavLink from '../components/PermissionsNavLink';
import Sources from '../sources/containers/Sources';
import RepositoryNavLink from '../components/RepositoryNavLink';
import { getLinks, getRepositoriesLink } from '../../modules/indexResource';
import { binder, ExtensionPoint } from '@scm-manager/ui-extensions';
import { History } from "history";
import EditRepoNavLink from "../components/EditRepoNavLink";
import BranchRoot from "../branches/containers/BranchRoot";
import ChangesetsRoot from "./ChangesetsRoot";
import ChangesetView from "./ChangesetView";
import PermissionsNavLink from "../components/PermissionsNavLink";
import Sources from "../sources/containers/Sources";
import RepositoryNavLink from "../components/RepositoryNavLink";
import { getLinks, getRepositoriesLink } from "../../modules/indexResource";
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
type Props = {
namespace: string;
@@ -63,7 +63,7 @@ class RepositoryRoot extends React.Component<Props> {
}
stripEndingSlash = (url: string) => {
if (url.endsWith('/')) {
if (url.endsWith("/")) {
return url.substring(0, url.length - 1);
}
return url;
@@ -91,8 +91,8 @@ class RepositoryRoot extends React.Component<Props> {
if (error) {
return (
<ErrorPage
title={t('repositoryRoot.errorTitle')}
subtitle={t('repositoryRoot.errorSubtitle')}
title={t("repositoryRoot.errorTitle")}
subtitle={t("repositoryRoot.errorSubtitle")}
error={error}
/>
);
@@ -107,22 +107,22 @@ class RepositoryRoot extends React.Component<Props> {
const extensionProps = {
repository,
url,
indexLinks,
indexLinks
};
const redirectUrlFactory = binder.getExtension(
'repository.redirect',
this.props,
"repository.redirect",
this.props
);
let redirectedUrl;
if (redirectUrlFactory) {
redirectedUrl = url + redirectUrlFactory(this.props);
} else {
redirectedUrl = url + '/info';
redirectedUrl = url + "/info";
}
return (
<Page title={repository.namespace + '/' + repository.name}>
<Page title={repository.namespace + "/" + repository.name}>
<div className="columns">
<div className="column is-three-quarters">
<Switch>
@@ -215,7 +215,7 @@ class RepositoryRoot extends React.Component<Props> {
</div>
<div className="column">
<Navigation>
<Section label={t('repositoryRoot.menu.navigationLabel')}>
<Section label={t("repositoryRoot.menu.navigationLabel")}>
<ExtensionPoint
name="repository.navigation.topLevel"
props={extensionProps}
@@ -224,14 +224,14 @@ class RepositoryRoot extends React.Component<Props> {
<NavLink
to={`${url}/info`}
icon="fas fa-info-circle"
label={t('repositoryRoot.menu.informationNavLink')}
label={t("repositoryRoot.menu.informationNavLink")}
/>
<RepositoryNavLink
repository={repository}
linkName="branches"
to={`${url}/branches/`}
icon="fas fa-code-branch"
label={t('repositoryRoot.menu.branchesNavLink')}
label={t("repositoryRoot.menu.branchesNavLink")}
activeWhenMatch={this.matchesBranches}
activeOnlyWhenExact={false}
/>
@@ -240,7 +240,7 @@ class RepositoryRoot extends React.Component<Props> {
linkName="changesets"
to={`${url}/changesets/`}
icon="fas fa-exchange-alt"
label={t('repositoryRoot.menu.historyNavLink')}
label={t("repositoryRoot.menu.historyNavLink")}
activeWhenMatch={this.matchesChangesets}
activeOnlyWhenExact={false}
/>
@@ -249,7 +249,7 @@ class RepositoryRoot extends React.Component<Props> {
linkName="sources"
to={`${url}/sources`}
icon="fas fa-code"
label={t('repositoryRoot.menu.sourcesNavLink')}
label={t("repositoryRoot.menu.sourcesNavLink")}
activeOnlyWhenExact={false}
/>
<ExtensionPoint
@@ -259,7 +259,7 @@ class RepositoryRoot extends React.Component<Props> {
/>
<SubNavigation
to={`${url}/settings/general`}
label={t('repositoryRoot.menu.settingsNavLink')}
label={t("repositoryRoot.menu.settingsNavLink")}
>
<EditRepoNavLink
repository={repository}
@@ -298,7 +298,7 @@ const mapStateToProps = (state, ownProps) => {
loading,
error,
repoLink,
indexLinks,
indexLinks
};
};
@@ -306,11 +306,11 @@ const mapDispatchToProps = dispatch => {
return {
fetchRepoByName: (link: string, namespace: string, name: string) => {
dispatch(fetchRepoByName(link, namespace, name));
},
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(translate('repos')(RepositoryRoot));
mapDispatchToProps
)(translate("repos")(RepositoryRoot));

View File

@@ -1,6 +1,6 @@
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock from 'fetch-mock';
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import reducer, {
FETCH_CHANGESET,
FETCH_CHANGESET_FAILURE,
@@ -22,46 +22,46 @@ import reducer, {
isFetchChangesetPending,
isFetchChangesetsPending,
selectListAsCollection,
shouldFetchChangeset,
} from './changesets';
shouldFetchChangeset
} from "./changesets";
const branch = {
name: 'specific',
revision: '123',
name: "specific",
revision: "123",
_links: {
history: {
href:
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets',
},
},
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets"
}
}
};
const repository = {
namespace: 'foo',
name: 'bar',
type: 'GIT',
namespace: "foo",
name: "bar",
type: "GIT",
_links: {
self: {
href: 'http://scm.hitchhicker.com/api/v2/repositories/foo/bar',
href: "http://scm.hitchhicker.com/api/v2/repositories/foo/bar"
},
changesets: {
href: 'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets',
href: "http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets"
},
branches: {
href:
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/branches',
},
},
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/branches"
}
}
};
const changesets = {};
describe('changesets', () => {
describe('fetching of changesets', () => {
describe("changesets", () => {
describe("fetching of changesets", () => {
const DEFAULT_BRANCH_URL =
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets';
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets";
const SPECIFIC_BRANCH_URL =
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets';
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets";
const mockStore = configureMockStore([thunk]);
@@ -70,25 +70,25 @@ describe('changesets', () => {
fetchMock.restore();
});
const changesetId = 'aba876c0625d90a6aff1494f3d161aaa7008b958';
const changesetId = "aba876c0625d90a6aff1494f3d161aaa7008b958";
it('should fetch changeset', () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + '/' + changesetId, '{}');
it("should fetch changeset", () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, "{}");
const expectedActions = [
{
type: FETCH_CHANGESET_PENDING,
itemId: 'foo/bar/' + changesetId,
itemId: "foo/bar/" + changesetId
},
{
type: FETCH_CHANGESET_SUCCESS,
payload: {
changeset: {},
id: changesetId,
repository: repository,
repository: repository
},
itemId: 'foo/bar/' + changesetId,
},
itemId: "foo/bar/" + changesetId
}
];
const store = mockStore({});
@@ -99,14 +99,14 @@ describe('changesets', () => {
});
});
it('should fail fetching changeset on error', () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + '/' + changesetId, 500);
it("should fail fetching changeset on error", () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, 500);
const expectedActions = [
{
type: FETCH_CHANGESET_PENDING,
itemId: 'foo/bar/' + changesetId,
},
itemId: "foo/bar/" + changesetId
}
];
const store = mockStore({});
@@ -119,74 +119,74 @@ describe('changesets', () => {
});
});
it('should fetch changeset if needed', () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + '/id3', '{}');
it("should fetch changeset if needed", () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/id3", "{}");
const expectedActions = [
{
type: FETCH_CHANGESET_PENDING,
itemId: 'foo/bar/id3',
itemId: "foo/bar/id3"
},
{
type: FETCH_CHANGESET_SUCCESS,
payload: {
changeset: {},
id: 'id3',
repository: repository,
id: "id3",
repository: repository
},
itemId: 'foo/bar/id3',
},
itemId: "foo/bar/id3"
}
];
const store = mockStore({});
return store
.dispatch(fetchChangesetIfNeeded(repository, 'id3'))
.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);
it("should not fetch changeset if not needed", () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/id1", 500);
const state = {
changesets: {
'foo/bar': {
"foo/bar": {
byId: {
id1: {
id: 'id1',
id: "id1"
},
id2: {
id: 'id2',
},
},
},
},
id: "id2"
}
}
}
}
};
const store = mockStore(state);
return expect(
store.dispatch(fetchChangesetIfNeeded(repository, 'id1')),
store.dispatch(fetchChangesetIfNeeded(repository, "id1"))
).toEqual(undefined);
});
it('should fetch changesets for default branch', () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL, '{}');
it("should fetch changesets for default branch", () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL, "{}");
const expectedActions = [
{
type: FETCH_CHANGESETS_PENDING,
itemId: 'foo/bar',
itemId: "foo/bar"
},
{
type: FETCH_CHANGESETS_SUCCESS,
payload: {
repository,
undefined,
changesets,
changesets
},
itemId: 'foo/bar',
},
itemId: "foo/bar"
}
];
const store = mockStore({});
@@ -195,24 +195,24 @@ describe('changesets', () => {
});
});
it('should fetch changesets for specific branch', () => {
const itemId = 'foo/bar/specific';
fetchMock.getOnce(SPECIFIC_BRANCH_URL, '{}');
it("should fetch changesets for specific branch", () => {
const itemId = "foo/bar/specific";
fetchMock.getOnce(SPECIFIC_BRANCH_URL, "{}");
const expectedActions = [
{
type: FETCH_CHANGESETS_PENDING,
itemId,
itemId
},
{
type: FETCH_CHANGESETS_SUCCESS,
payload: {
repository,
branch,
changesets,
changesets
},
itemId,
},
itemId
}
];
const store = mockStore({});
@@ -221,15 +221,15 @@ describe('changesets', () => {
});
});
it('should fail fetching changesets on error', () => {
const itemId = 'foo/bar';
it("should fail fetching changesets on error", () => {
const itemId = "foo/bar";
fetchMock.getOnce(DEFAULT_BRANCH_URL, 500);
const expectedActions = [
{
type: FETCH_CHANGESETS_PENDING,
itemId,
},
itemId
}
];
const store = mockStore({});
@@ -240,15 +240,15 @@ describe('changesets', () => {
});
});
it('should fail fetching changesets for specific branch on error', () => {
const itemId = 'foo/bar/specific';
it("should fail fetching changesets for specific branch on error", () => {
const itemId = "foo/bar/specific";
fetchMock.getOnce(SPECIFIC_BRANCH_URL, 500);
const expectedActions = [
{
type: FETCH_CHANGESETS_PENDING,
itemId,
},
itemId
}
];
const store = mockStore({});
@@ -259,23 +259,23 @@ describe('changesets', () => {
});
});
it('should fetch changesets by page', () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + '?page=4', '{}');
it("should fetch changesets by page", () => {
fetchMock.getOnce(DEFAULT_BRANCH_URL + "?page=4", "{}");
const expectedActions = [
{
type: FETCH_CHANGESETS_PENDING,
itemId: 'foo/bar',
itemId: "foo/bar"
},
{
type: FETCH_CHANGESETS_SUCCESS,
payload: {
repository,
undefined,
changesets,
changesets
},
itemId: 'foo/bar',
},
itemId: "foo/bar"
}
];
const store = mockStore({});
@@ -286,23 +286,23 @@ describe('changesets', () => {
});
});
it('should fetch changesets by branch and page', () => {
fetchMock.getOnce(SPECIFIC_BRANCH_URL + '?page=4', '{}');
it("should fetch changesets by branch and page", () => {
fetchMock.getOnce(SPECIFIC_BRANCH_URL + "?page=4", "{}");
const expectedActions = [
{
type: FETCH_CHANGESETS_PENDING,
itemId: 'foo/bar/specific',
itemId: "foo/bar/specific"
},
{
type: FETCH_CHANGESETS_SUCCESS,
payload: {
repository,
branch,
changesets,
changesets
},
itemId: 'foo/bar/specific',
},
itemId: "foo/bar/specific"
}
];
const store = mockStore({});
@@ -312,7 +312,7 @@ describe('changesets', () => {
});
});
describe('changesets reducer', () => {
describe("changesets reducer", () => {
const responseBody = {
page: 1,
pageTotal: 10,
@@ -320,354 +320,354 @@ describe('changesets', () => {
_embedded: {
changesets: [
{
id: 'changeset1',
id: "changeset1",
author: {
mail: 'z@phod.com',
name: 'zaphod',
},
mail: "z@phod.com",
name: "zaphod"
}
},
{
id: 'changeset2',
description: 'foo',
id: "changeset2",
description: "foo"
},
{
id: 'changeset3',
description: 'bar',
},
id: "changeset3",
description: "bar"
}
],
_embedded: {
tags: [],
branches: [],
parents: [],
},
},
parents: []
}
}
};
it('should set state to received changesets', () => {
it("should set state to received changesets", () => {
const newState = reducer(
{},
fetchChangesetsSuccess(repository, undefined, responseBody),
fetchChangesetsSuccess(repository, undefined, responseBody)
);
expect(newState).toBeDefined();
expect(newState['foo/bar'].byId['changeset1'].author.mail).toEqual(
'z@phod.com',
expect(newState["foo/bar"].byId["changeset1"].author.mail).toEqual(
"z@phod.com"
);
expect(newState['foo/bar'].byId['changeset2'].description).toEqual('foo');
expect(newState['foo/bar'].byId['changeset3'].description).toEqual('bar');
expect(newState['foo/bar'].byBranch['']).toEqual({
expect(newState["foo/bar"].byId["changeset2"].description).toEqual("foo");
expect(newState["foo/bar"].byId["changeset3"].description).toEqual("bar");
expect(newState["foo/bar"].byBranch[""]).toEqual({
entry: {
page: 1,
pageTotal: 10,
_links: {},
_links: {}
},
entries: ['changeset1', 'changeset2', 'changeset3'],
entries: ["changeset1", "changeset2", "changeset3"]
});
});
it('should store the changeset list to branch', () => {
it("should store the changeset list to branch", () => {
const newState = reducer(
{},
fetchChangesetsSuccess(repository, branch, responseBody),
fetchChangesetsSuccess(repository, branch, responseBody)
);
expect(newState['foo/bar'].byId['changeset1']).toBeDefined();
expect(newState['foo/bar'].byBranch['specific'].entries).toEqual([
'changeset1',
'changeset2',
'changeset3',
expect(newState["foo/bar"].byId["changeset1"]).toBeDefined();
expect(newState["foo/bar"].byBranch["specific"].entries).toEqual([
"changeset1",
"changeset2",
"changeset3"
]);
});
it('should not remove existing changesets', () => {
it("should not remove existing changesets", () => {
const state = {
'foo/bar': {
"foo/bar": {
byId: {
id2: {
id: 'id2',
id: "id2"
},
id1: {
id: 'id1',
},
id: "id1"
}
},
byBranch: {
'': {
entries: ['id1', 'id2'],
},
},
},
"": {
entries: ["id1", "id2"]
}
}
}
};
const newState = reducer(
state,
fetchChangesetsSuccess(repository, undefined, responseBody),
fetchChangesetsSuccess(repository, undefined, responseBody)
);
const fooBar = newState['foo/bar'];
const fooBar = newState["foo/bar"];
expect(fooBar.byBranch[''].entries).toEqual([
'changeset1',
'changeset2',
'changeset3',
expect(fooBar.byBranch[""].entries).toEqual([
"changeset1",
"changeset2",
"changeset3"
]);
expect(fooBar.byId['id2']).toEqual({
id: 'id2',
expect(fooBar.byId["id2"]).toEqual({
id: "id2"
});
expect(fooBar.byId['id1']).toEqual({
id: 'id1',
expect(fooBar.byId["id1"]).toEqual({
id: "id1"
});
});
const responseBodySingleChangeset = {
id: 'id3',
id: "id3",
author: {
mail: 'z@phod.com',
name: 'zaphod',
mail: "z@phod.com",
name: "zaphod"
},
date: '2018-09-13T08:46:22Z',
description: 'added testChangeset',
date: "2018-09-13T08:46:22Z",
description: "added testChangeset",
_links: {},
_embedded: {
tags: [],
branches: [],
},
branches: []
}
};
it('should add changeset to state', () => {
it("should add changeset to state", () => {
const newState = reducer(
{
'foo/bar': {
"foo/bar": {
byId: {
id2: {
id: 'id2',
id: "id2",
author: {
mail: 'mail@author.com',
name: 'author',
},
},
mail: "mail@author.com",
name: "author"
}
}
},
list: {
entry: {
page: 1,
pageTotal: 10,
_links: {},
_links: {}
},
entries: ['id2'],
},
},
entries: ["id2"]
}
}
},
fetchChangesetSuccess(responseBodySingleChangeset, repository, 'id3'),
fetchChangesetSuccess(responseBodySingleChangeset, repository, "id3")
);
expect(newState).toBeDefined();
expect(newState['foo/bar'].byId['id3'].description).toEqual(
'added testChangeset',
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({
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: {},
_links: {}
},
entries: ['id2'],
entries: ["id2"]
});
});
});
describe('changeset selectors', () => {
const error = new Error('Something went wrong');
describe("changeset selectors", () => {
const error = new Error("Something went wrong");
it('should return changeset', () => {
it("should return changeset", () => {
const state = {
changesets: {
'foo/bar': {
"foo/bar": {
byId: {
id1: {
id: 'id1',
id: "id1"
},
id2: {
id: 'id2',
},
},
},
},
id: "id2"
}
}
}
}
};
const result = getChangeset(state, repository, 'id1');
const result = getChangeset(state, repository, "id1");
expect(result).toEqual({
id: 'id1',
id: "id1"
});
});
it('should return null if changeset does not exist', () => {
it("should return null if changeset does not exist", () => {
const state = {
changesets: {
'foo/bar': {
"foo/bar": {
byId: {
id1: {
id: 'id1',
id: "id1"
},
id2: {
id: 'id2',
},
},
},
},
id: "id2"
}
}
}
}
};
const result = getChangeset(state, repository, 'id3');
const result = getChangeset(state, repository, "id3");
expect(result).toEqual(null);
});
it('should return true if changeset does not exist', () => {
it("should return true if changeset does not exist", () => {
const state = {
changesets: {
'foo/bar': {
"foo/bar": {
byId: {
id1: {
id: 'id1',
id: "id1"
},
id2: {
id: 'id2',
},
},
},
},
id: "id2"
}
}
}
}
};
const result = shouldFetchChangeset(state, repository, 'id3');
const result = shouldFetchChangeset(state, repository, "id3");
expect(result).toEqual(true);
});
it('should return false if changeset exists', () => {
it("should return false if changeset exists", () => {
const state = {
changesets: {
'foo/bar': {
"foo/bar": {
byId: {
id1: {
id: 'id1',
id: "id1"
},
id2: {
id: 'id2',
},
},
},
},
id: "id2"
}
}
}
}
};
const result = shouldFetchChangeset(state, repository, 'id2');
const result = shouldFetchChangeset(state, repository, "id2");
expect(result).toEqual(false);
});
it('should return true, when fetching changeset is pending', () => {
it("should return true, when fetching changeset is pending", () => {
const state = {
pending: {
[FETCH_CHANGESET + '/foo/bar/id1']: true,
},
[FETCH_CHANGESET + "/foo/bar/id1"]: true
}
};
expect(isFetchChangesetPending(state, repository, 'id1')).toBeTruthy();
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 false, when fetching changeset is not pending", () => {
expect(isFetchChangesetPending({}, repository, "id1")).toEqual(false);
});
it('should return error if fetching changeset failed', () => {
it("should return error if fetching changeset failed", () => {
const state = {
failure: {
[FETCH_CHANGESET + '/foo/bar/id1']: error,
},
[FETCH_CHANGESET + "/foo/bar/id1"]: error
}
};
expect(getFetchChangesetFailure(state, repository, 'id1')).toEqual(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 return false if fetching changeset did not fail", () => {
expect(getFetchChangesetFailure({}, repository, "id1")).toBeUndefined();
});
it('should get all changesets for a given repository', () => {
it("should get all changesets for a given repository", () => {
const state = {
changesets: {
'foo/bar': {
"foo/bar": {
byId: {
id2: {
id: 'id2',
id: "id2"
},
id1: {
id: 'id1',
},
id: "id1"
}
},
byBranch: {
'': {
entries: ['id1', 'id2'],
},
},
},
},
"": {
entries: ["id1", "id2"]
}
}
}
}
};
const result = getChangesets(state, repository);
expect(result).toEqual([
{
id: 'id1',
id: "id1"
},
{
id: 'id2',
},
id: "id2"
}
]);
});
it('should return true, when fetching changesets is pending', () => {
it("should return true, when fetching changesets is pending", () => {
const state = {
pending: {
[FETCH_CHANGESETS + '/foo/bar']: true,
},
[FETCH_CHANGESETS + "/foo/bar"]: true
}
};
expect(isFetchChangesetsPending(state, repository)).toBeTruthy();
});
it('should return false, when fetching changesets is not pending', () => {
it("should return false, when fetching changesets is not pending", () => {
expect(isFetchChangesetsPending({}, repository)).toEqual(false);
});
it('should return error if fetching changesets failed', () => {
it("should return error if fetching changesets failed", () => {
const state = {
failure: {
[FETCH_CHANGESETS + '/foo/bar']: error,
},
[FETCH_CHANGESETS + "/foo/bar"]: error
}
};
expect(getFetchChangesetsFailure(state, repository)).toEqual(error);
});
it('should return false if fetching changesets did not fail', () => {
it("should return false if fetching changesets did not fail", () => {
expect(getFetchChangesetsFailure({}, repository)).toBeUndefined();
});
it('should return list as collection for the default branch', () => {
it("should return list as collection for the default branch", () => {
const state = {
changesets: {
'foo/bar': {
"foo/bar": {
byId: {
id2: {
id: 'id2',
id: "id2"
},
id1: {
id: 'id1',
},
id: "id1"
}
},
byBranch: {
'': {
"": {
entry: {
page: 1,
pageTotal: 10,
_links: {},
_links: {}
},
entries: ['id1', 'id2'],
},
},
},
},
entries: ["id1", "id2"]
}
}
}
}
};
const collection = selectListAsCollection(state, repository);

View File

@@ -1,24 +1,24 @@
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';
SUCCESS_SUFFIX
} from "../../modules/types";
import { apiClient, urls } from "@scm-manager/ui-components";
import { isPending } from "../../modules/pending";
import { getFailure } from "../../modules/failure";
import {
Action,
Branch,
PagedCollection,
Repository,
} from '@scm-manager/ui-types';
Repository
} from "@scm-manager/ui-types";
export const FETCH_CHANGESETS = 'scm/repos/FETCH_CHANGESETS';
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}`;
export const FETCH_CHANGESET = 'scm/repos/FETCH_CHANGESET';
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}`;
@@ -53,50 +53,50 @@ function createChangesetUrl(repository: Repository, id: string) {
export function fetchChangesetPending(
repository: Repository,
id: string,
id: string
): Action {
return {
type: FETCH_CHANGESET_PENDING,
itemId: createChangesetItemId(repository, id),
itemId: createChangesetItemId(repository, id)
};
}
export function fetchChangesetSuccess(
changeset: any,
repository: Repository,
id: string,
id: string
): Action {
return {
type: FETCH_CHANGESET_SUCCESS,
payload: {
changeset,
repository,
id,
id
},
itemId: createChangesetItemId(repository, id),
itemId: createChangesetItemId(repository, id)
};
}
function fetchChangesetFailure(
repository: Repository,
id: string,
error: Error,
error: Error
): Action {
return {
type: FETCH_CHANGESET_FAILURE,
payload: {
repository,
id,
error,
error
},
itemId: createChangesetItemId(repository, id),
itemId: createChangesetItemId(repository, id)
};
}
export function fetchChangesets(
repository: Repository,
branch?: Branch,
page?: number,
page?: number
) {
const link = createChangesetsLink(repository, branch, page);
@@ -117,7 +117,7 @@ export function fetchChangesets(
function createChangesetsLink(
repository: Repository,
branch?: Branch,
page?: number,
page?: number
) {
let link = repository._links.changesets.href;
@@ -133,58 +133,58 @@ function createChangesetsLink(
export function fetchChangesetsPending(
repository: Repository,
branch?: Branch,
branch?: Branch
): Action {
const itemId = createItemId(repository, branch);
return {
type: FETCH_CHANGESETS_PENDING,
itemId,
itemId
};
}
export function fetchChangesetsSuccess(
repository: Repository,
branch?: Branch,
changesets: any,
changesets: any
): Action {
return {
type: FETCH_CHANGESETS_SUCCESS,
payload: {
repository,
branch,
changesets,
changesets
},
itemId: createItemId(repository, branch),
itemId: createItemId(repository, branch)
};
}
function fetchChangesetsFailure(
repository: Repository,
branch?: Branch,
error: Error,
error: Error
): Action {
return {
type: FETCH_CHANGESETS_FAILURE,
payload: {
repository,
error,
branch,
branch
},
itemId: createItemId(repository, branch),
itemId: createItemId(repository, branch)
};
}
function createChangesetItemId(repository: Repository, id: string) {
const { namespace, name } = repository;
return namespace + '/' + name + '/' + id;
return namespace + "/" + name + "/" + id;
}
function createItemId(repository: Repository, branch?: Branch): string {
const { namespace, name } = repository;
let itemId = namespace + '/' + name;
let itemId = namespace + "/" + name;
if (branch) {
itemId = itemId + '/' + branch.name;
itemId = itemId + "/" + branch.name;
}
return itemId;
}
@@ -193,8 +193,8 @@ function createItemId(repository: Repository, branch?: Branch): string {
export default function reducer(
state: any = {},
action: Action = {
type: 'UNKNOWN',
},
type: "UNKNOWN"
}
): object {
if (!action.payload) {
return state;
@@ -218,9 +218,9 @@ export default function reducer(
...state[_key],
byId: {
..._oldByIds,
[changeset.id]: changeset,
},
},
[changeset.id]: changeset
}
}
};
case FETCH_CHANGESETS_SUCCESS:
@@ -239,7 +239,7 @@ export default function reducer(
oldState = state[repoId];
}
const branchName = payload.branch ? payload.branch.name : '';
const branchName = payload.branch ? payload.branch.name : "";
const byIds = extractChangesetsByIds(changesets);
return {
@@ -247,7 +247,7 @@ export default function reducer(
[repoId]: {
byId: {
...oldState.byId,
...byIds,
...byIds
},
byBranch: {
...oldState.byBranch,
@@ -256,11 +256,11 @@ export default function reducer(
entry: {
page: payload.changesets.page,
pageTotal: payload.changesets.pageTotal,
_links: payload.changesets._links,
},
},
},
},
_links: payload.changesets._links
}
}
}
}
};
default:
return state;
@@ -281,7 +281,7 @@ function extractChangesetsByIds(changesets: any) {
export function getChangesets(
state: object,
repository: Repository,
branch?: Branch,
branch?: Branch
) {
const repoKey = createItemId(repository);
@@ -290,7 +290,7 @@ export function getChangesets(
return null;
}
const branchName = branch ? branch.name : '';
const branchName = branch ? branch.name : "";
const changesets = stateRoot.byBranch[branchName];
if (!changesets) {
@@ -305,7 +305,7 @@ export function getChangesets(
export function getChangeset(
state: object,
repository: Repository,
id: string,
id: string
) {
const key = createItemId(repository);
const changesets =
@@ -321,7 +321,7 @@ export function getChangeset(
export function shouldFetchChangeset(
state: object,
repository: Repository,
id: string,
id: string
) {
if (getChangeset(state, repository, id)) {
return false;
@@ -332,31 +332,31 @@ export function shouldFetchChangeset(
export function isFetchChangesetPending(
state: object,
repository: Repository,
id: string,
id: string
) {
return isPending(
state,
FETCH_CHANGESET,
createChangesetItemId(repository, id),
createChangesetItemId(repository, id)
);
}
export function getFetchChangesetFailure(
state: object,
repository: Repository,
id: string,
id: string
) {
return getFailure(
state,
FETCH_CHANGESET,
createChangesetItemId(repository, id),
createChangesetItemId(repository, id)
);
}
export function isFetchChangesetsPending(
state: object,
repository: Repository,
branch?: Branch,
branch?: Branch
) {
return isPending(state, FETCH_CHANGESETS, createItemId(repository, branch));
}
@@ -364,7 +364,7 @@ export function isFetchChangesetsPending(
export function getFetchChangesetsFailure(
state: object,
repository: Repository,
branch?: Branch,
branch?: Branch
) {
return getFailure(state, FETCH_CHANGESETS, createItemId(repository, branch));
}
@@ -372,7 +372,7 @@ export function getFetchChangesetsFailure(
const selectList = (state: object, repository: Repository, branch?: Branch) => {
const repoId = createItemId(repository);
const branchName = branch ? branch.name : '';
const branchName = branch ? branch.name : "";
if (state.changesets[repoId]) {
const repoState = state.changesets[repoId];
@@ -386,7 +386,7 @@ const selectList = (state: object, repository: Repository, branch?: Branch) => {
const selectListEntry = (
state: object,
repository: Repository,
branch?: Branch,
branch?: Branch
): object => {
const list = selectList(state, repository, branch);
if (list.entry) {
@@ -398,7 +398,7 @@ const selectListEntry = (
export const selectListAsCollection = (
state: object,
repository: Repository,
branch?: Branch,
branch?: Branch
): PagedCollection => {
return selectListEntry(state, repository, branch);
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +1,45 @@
import { apiClient } from '@scm-manager/ui-components';
import * as types from '../../modules/types';
import { apiClient } from "@scm-manager/ui-components";
import * as types from "../../modules/types";
import {
Action,
Repository,
RepositoryCollection,
} from '@scm-manager/ui-types';
import { isPending } from '../../modules/pending';
import { getFailure } from '../../modules/failure';
RepositoryCollection
} from "@scm-manager/ui-types";
import { isPending } from "../../modules/pending";
import { getFailure } from "../../modules/failure";
export const FETCH_REPOS = 'scm/repos/FETCH_REPOS';
export const FETCH_REPOS = "scm/repos/FETCH_REPOS";
export const FETCH_REPOS_PENDING = `${FETCH_REPOS}_${types.PENDING_SUFFIX}`;
export const FETCH_REPOS_SUCCESS = `${FETCH_REPOS}_${types.SUCCESS_SUFFIX}`;
export const FETCH_REPOS_FAILURE = `${FETCH_REPOS}_${types.FAILURE_SUFFIX}`;
export const FETCH_REPO = 'scm/repos/FETCH_REPO';
export const FETCH_REPO = "scm/repos/FETCH_REPO";
export const FETCH_REPO_PENDING = `${FETCH_REPO}_${types.PENDING_SUFFIX}`;
export const FETCH_REPO_SUCCESS = `${FETCH_REPO}_${types.SUCCESS_SUFFIX}`;
export const FETCH_REPO_FAILURE = `${FETCH_REPO}_${types.FAILURE_SUFFIX}`;
export const CREATE_REPO = 'scm/repos/CREATE_REPO';
export const CREATE_REPO = "scm/repos/CREATE_REPO";
export const CREATE_REPO_PENDING = `${CREATE_REPO}_${types.PENDING_SUFFIX}`;
export const CREATE_REPO_SUCCESS = `${CREATE_REPO}_${types.SUCCESS_SUFFIX}`;
export const CREATE_REPO_FAILURE = `${CREATE_REPO}_${types.FAILURE_SUFFIX}`;
export const CREATE_REPO_RESET = `${CREATE_REPO}_${types.RESET_SUFFIX}`;
export const MODIFY_REPO = 'scm/repos/MODIFY_REPO';
export const MODIFY_REPO = "scm/repos/MODIFY_REPO";
export const MODIFY_REPO_PENDING = `${MODIFY_REPO}_${types.PENDING_SUFFIX}`;
export const MODIFY_REPO_SUCCESS = `${MODIFY_REPO}_${types.SUCCESS_SUFFIX}`;
export const MODIFY_REPO_FAILURE = `${MODIFY_REPO}_${types.FAILURE_SUFFIX}`;
export const MODIFY_REPO_RESET = `${MODIFY_REPO}_${types.RESET_SUFFIX}`;
export const DELETE_REPO = 'scm/repos/DELETE_REPO';
export const DELETE_REPO = "scm/repos/DELETE_REPO";
export const DELETE_REPO_PENDING = `${DELETE_REPO}_${types.PENDING_SUFFIX}`;
export const DELETE_REPO_SUCCESS = `${DELETE_REPO}_${types.SUCCESS_SUFFIX}`;
export const DELETE_REPO_FAILURE = `${DELETE_REPO}_${types.FAILURE_SUFFIX}`;
const CONTENT_TYPE = 'application/vnd.scmm-repository+json;v=2';
const CONTENT_TYPE = "application/vnd.scmm-repository+json;v=2";
// fetch repos
const SORT_BY = 'sortBy=namespaceAndName';
const SORT_BY = "sortBy=namespaceAndName";
export function fetchRepos(link: string) {
return fetchReposByLink(link);
@@ -48,7 +48,7 @@ export function fetchRepos(link: string) {
export function fetchReposByPage(link: string, page: number, filter?: string) {
if (filter) {
return fetchReposByLink(
`${link}?page=${page - 1}&q=${decodeURIComponent(filter)}`,
`${link}?page=${page - 1}&q=${decodeURIComponent(filter)}`
);
}
return fetchReposByLink(`${link}?page=${page - 1}`);
@@ -59,10 +59,10 @@ function appendSortByLink(url: string) {
return url;
}
let urlWithSortBy = url;
if (url.includes('?')) {
urlWithSortBy += '&';
if (url.includes("?")) {
urlWithSortBy += "&";
} else {
urlWithSortBy += '?';
urlWithSortBy += "?";
}
return urlWithSortBy + SORT_BY;
}
@@ -85,21 +85,21 @@ export function fetchReposByLink(link: string) {
export function fetchReposPending(): Action {
return {
type: FETCH_REPOS_PENDING,
type: FETCH_REPOS_PENDING
};
}
export function fetchReposSuccess(repositories: RepositoryCollection): Action {
return {
type: FETCH_REPOS_SUCCESS,
payload: repositories,
payload: repositories
};
}
export function fetchReposFailure(err: Error): Action {
return {
type: FETCH_REPOS_FAILURE,
payload: err,
payload: err
};
}
@@ -109,7 +109,7 @@ export function fetchRepoByLink(repo: Repository) {
}
export function fetchRepoByName(link: string, namespace: string, name: string) {
const repoUrl = link.endsWith('/') ? link : link + '/';
const repoUrl = link.endsWith("/") ? link : link + "/";
return fetchRepo(`${repoUrl}${namespace}/${name}`, namespace, name);
}
@@ -133,9 +133,9 @@ export function fetchRepoPending(namespace: string, name: string): Action {
type: FETCH_REPO_PENDING,
payload: {
namespace,
name,
name
},
itemId: namespace + '/' + name,
itemId: namespace + "/" + name
};
}
@@ -143,23 +143,23 @@ export function fetchRepoSuccess(repository: Repository): Action {
return {
type: FETCH_REPO_SUCCESS,
payload: repository,
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
export function fetchRepoFailure(
namespace: string,
name: string,
error: Error,
error: Error
): Action {
return {
type: FETCH_REPO_FAILURE,
payload: {
namespace,
name,
error,
error
},
itemId: namespace + '/' + name,
itemId: namespace + "/" + name
};
}
@@ -168,14 +168,14 @@ export function fetchRepoFailure(
export function createRepo(
link: string,
repository: Repository,
callback?: (repo: Repository) => void,
callback?: (repo: Repository) => void
) {
return function(dispatch: any) {
dispatch(createRepoPending());
return apiClient
.post(link, repository, CONTENT_TYPE)
.then(response => {
const location = response.headers.get('Location');
const location = response.headers.get("Location");
dispatch(createRepoSuccess());
return apiClient.get(location);
})
@@ -193,26 +193,26 @@ export function createRepo(
export function createRepoPending(): Action {
return {
type: CREATE_REPO_PENDING,
type: CREATE_REPO_PENDING
};
}
export function createRepoSuccess(): Action {
return {
type: CREATE_REPO_SUCCESS,
type: CREATE_REPO_SUCCESS
};
}
export function createRepoFailure(err: Error): Action {
return {
type: CREATE_REPO_FAILURE,
payload: err,
payload: err
};
}
export function createRepoReset(): Action {
return {
type: CREATE_REPO_RESET,
type: CREATE_REPO_RESET
};
}
@@ -243,7 +243,7 @@ export function modifyRepoPending(repository: Repository): Action {
return {
type: MODIFY_REPO_PENDING,
payload: repository,
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
@@ -251,21 +251,21 @@ export function modifyRepoSuccess(repository: Repository): Action {
return {
type: MODIFY_REPO_SUCCESS,
payload: repository,
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
export function modifyRepoFailure(
repository: Repository,
error: Error,
error: Error
): Action {
return {
type: MODIFY_REPO_FAILURE,
payload: {
error,
repository,
repository
},
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
@@ -273,9 +273,9 @@ export function modifyRepoReset(repository: Repository): Action {
return {
type: MODIFY_REPO_RESET,
payload: {
repository,
repository
},
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
@@ -302,7 +302,7 @@ export function deleteRepoPending(repository: Repository): Action {
return {
type: DELETE_REPO_PENDING,
payload: repository,
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
@@ -310,32 +310,32 @@ export function deleteRepoSuccess(repository: Repository): Action {
return {
type: DELETE_REPO_SUCCESS,
payload: repository,
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
export function deleteRepoFailure(
repository: Repository,
error: Error,
error: Error
): Action {
return {
type: DELETE_REPO_FAILURE,
payload: {
error,
repository,
repository
},
itemId: createIdentifier(repository),
itemId: createIdentifier(repository)
};
}
// reducer
function createIdentifier(repository: Repository) {
return repository.namespace + '/' + repository.name;
return repository.namespace + "/" + repository.name;
}
function normalizeByNamespaceAndName(
repositoryCollection: RepositoryCollection,
repositoryCollection: RepositoryCollection
) {
const names = [];
const byNames = {};
@@ -348,10 +348,10 @@ function normalizeByNamespaceAndName(
list: {
...repositoryCollection,
_embedded: {
repositories: names,
},
repositories: names
}
},
byNames: byNames,
byNames: byNames
};
}
@@ -361,16 +361,16 @@ const reducerByNames = (state: object, repository: Repository) => {
...state,
byNames: {
...state.byNames,
[identifier]: repository,
},
[identifier]: repository
}
};
};
export default function reducer(
state: object = {},
action: Action = {
type: 'UNKNOWN',
},
type: "UNKNOWN"
}
): object {
if (!action.payload) {
return state;
@@ -397,8 +397,8 @@ export function getRepositoryCollection(state: object) {
return {
...state.repos.list,
_embedded: {
repositories,
},
repositories
}
};
}
}
@@ -413,24 +413,24 @@ export function getFetchReposFailure(state: object) {
export function getRepository(state: object, namespace: string, name: string) {
if (state.repos && state.repos.byNames) {
return state.repos.byNames[namespace + '/' + name];
return state.repos.byNames[namespace + "/" + name];
}
}
export function isFetchRepoPending(
state: object,
namespace: string,
name: string,
name: string
) {
return isPending(state, FETCH_REPO, namespace + '/' + name);
return isPending(state, FETCH_REPO, namespace + "/" + name);
}
export function getFetchRepoFailure(
state: object,
namespace: string,
name: string,
name: string
) {
return getFailure(state, FETCH_REPO, namespace + '/' + name);
return getFailure(state, FETCH_REPO, namespace + "/" + name);
}
export function isAbleToCreateRepos(state: object) {
@@ -453,39 +453,39 @@ export function getCreateRepoFailure(state: object) {
export function isModifyRepoPending(
state: object,
namespace: string,
name: string,
name: string
) {
return isPending(state, MODIFY_REPO, namespace + '/' + name);
return isPending(state, MODIFY_REPO, namespace + "/" + name);
}
export function getModifyRepoFailure(
state: object,
namespace: string,
name: string,
name: string
) {
return getFailure(state, MODIFY_REPO, namespace + '/' + name);
return getFailure(state, MODIFY_REPO, namespace + "/" + name);
}
export function isDeleteRepoPending(
state: object,
namespace: string,
name: string,
name: string
) {
return isPending(state, DELETE_REPO, namespace + '/' + name);
return isPending(state, DELETE_REPO, namespace + "/" + name);
}
export function getDeleteRepoFailure(
state: object,
namespace: string,
name: string,
name: string
) {
return getFailure(state, DELETE_REPO, namespace + '/' + name);
return getFailure(state, DELETE_REPO, namespace + "/" + name);
}
export function getPermissionsLink(
state: object,
namespace: string,
name: string,
name: string
) {
const repo = getRepository(state, namespace, name);
return repo && repo._links ? repo._links.permissions.href : undefined;

View File

@@ -1,6 +1,6 @@
import fetchMock from 'fetch-mock';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock from "fetch-mock";
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import {
FETCH_REPOSITORY_TYPES,
FETCH_REPOSITORY_TYPES_FAILURE,
@@ -11,91 +11,91 @@ import {
getFetchRepositoryTypesFailure,
getRepositoryTypes,
isFetchRepositoryTypesPending,
shouldFetchRepositoryTypes,
} from './repositoryTypes';
import reducer from './repositoryTypes';
shouldFetchRepositoryTypes
} from "./repositoryTypes";
import reducer from "./repositoryTypes";
const git = {
name: 'git',
displayName: 'Git',
name: "git",
displayName: "Git",
_links: {
self: {
href: 'http://localhost:8081/api/v2/repositoryTypes/git',
},
},
href: "http://localhost:8081/api/v2/repositoryTypes/git"
}
}
};
const hg = {
name: 'hg',
displayName: 'Mercurial',
name: "hg",
displayName: "Mercurial",
_links: {
self: {
href: 'http://localhost:8081/api/v2/repositoryTypes/hg',
},
},
href: "http://localhost:8081/api/v2/repositoryTypes/hg"
}
}
};
const svn = {
name: 'svn',
displayName: 'Subversion',
name: "svn",
displayName: "Subversion",
_links: {
self: {
href: 'http://localhost:8081/api/v2/repositoryTypes/svn',
},
},
href: "http://localhost:8081/api/v2/repositoryTypes/svn"
}
}
};
const collection = {
_embedded: {
repositoryTypes: [git, hg, svn],
repositoryTypes: [git, hg, svn]
},
_links: {
self: {
href: 'http://localhost:8081/api/v2/repositoryTypes',
},
},
href: "http://localhost:8081/api/v2/repositoryTypes"
}
}
};
describe('repository types caching', () => {
it('should fetch repository types, on empty state', () => {
describe("repository types caching", () => {
it("should fetch repository types, on empty state", () => {
expect(shouldFetchRepositoryTypes({})).toBe(true);
});
it('should fetch repository types, if the state contains an empty array', () => {
it("should fetch repository types, if the state contains an empty array", () => {
const state = {
repositoryTypes: [],
repositoryTypes: []
};
expect(shouldFetchRepositoryTypes(state)).toBe(true);
});
it('should not fetch repository types, on pending state', () => {
it("should not fetch repository types, on pending state", () => {
const state = {
pending: {
[FETCH_REPOSITORY_TYPES]: true,
},
[FETCH_REPOSITORY_TYPES]: true
}
};
expect(shouldFetchRepositoryTypes(state)).toBe(false);
});
it('should not fetch repository types, on failure state', () => {
it("should not fetch repository types, on failure state", () => {
const state = {
failure: {
[FETCH_REPOSITORY_TYPES]: new Error('no...'),
},
[FETCH_REPOSITORY_TYPES]: new Error("no...")
}
};
expect(shouldFetchRepositoryTypes(state)).toBe(false);
});
it('should not fetch repository types, if they are already fetched', () => {
it("should not fetch repository types, if they are already fetched", () => {
const state = {
repositoryTypes: [git, hg, svn],
repositoryTypes: [git, hg, svn]
};
expect(shouldFetchRepositoryTypes(state)).toBe(false);
});
});
describe('repository types fetch', () => {
const URL = '/api/v2/repositoryTypes';
describe("repository types fetch", () => {
const URL = "/api/v2/repositoryTypes";
const mockStore = configureMockStore([thunk]);
afterEach(() => {
@@ -103,17 +103,17 @@ describe('repository types fetch', () => {
fetchMock.restore();
});
it('should successfully fetch repository types', () => {
it("should successfully fetch repository types", () => {
fetchMock.getOnce(URL, collection);
const expectedActions = [
{
type: FETCH_REPOSITORY_TYPES_PENDING,
type: FETCH_REPOSITORY_TYPES_PENDING
},
{
type: FETCH_REPOSITORY_TYPES_SUCCESS,
payload: collection,
},
payload: collection
}
];
const store = mockStore({});
@@ -122,9 +122,9 @@ describe('repository types fetch', () => {
});
});
it('should dispatch FETCH_REPOSITORY_TYPES_FAILURE on server error', () => {
it("should dispatch FETCH_REPOSITORY_TYPES_FAILURE on server error", () => {
fetchMock.getOnce(URL, {
status: 500,
status: 500
});
const store = mockStore({});
@@ -136,63 +136,63 @@ describe('repository types fetch', () => {
});
});
it('should dispatch not dispatch any action, if the repository types are already fetched', () => {
it("should dispatch not dispatch any action, if the repository types are already fetched", () => {
const store = mockStore({
repositoryTypes: [git, hg, svn],
repositoryTypes: [git, hg, svn]
});
store.dispatch(fetchRepositoryTypesIfNeeded());
expect(store.getActions().length).toBe(0);
});
});
describe('repository types reducer', () => {
it('should return unmodified state on unknown action', () => {
describe("repository types reducer", () => {
it("should return unmodified state on unknown action", () => {
const state = [];
expect(reducer(state)).toBe(state);
});
it('should store the repository types on FETCH_REPOSITORY_TYPES_SUCCESS', () => {
it("should store the repository types on FETCH_REPOSITORY_TYPES_SUCCESS", () => {
const newState = reducer([], fetchRepositoryTypesSuccess(collection));
expect(newState).toEqual([git, hg, svn]);
});
});
describe('repository types selectors', () => {
const error = new Error('The end of the universe');
describe("repository types selectors", () => {
const error = new Error("The end of the universe");
it('should return an emtpy array', () => {
it("should return an emtpy array", () => {
expect(getRepositoryTypes({})).toEqual([]);
});
it('should return the repository types', () => {
it("should return the repository types", () => {
const state = {
repositoryTypes: [git, hg, svn],
repositoryTypes: [git, hg, svn]
};
expect(getRepositoryTypes(state)).toEqual([git, hg, svn]);
});
it('should return true, when fetch repository types is pending', () => {
it("should return true, when fetch repository types is pending", () => {
const state = {
pending: {
[FETCH_REPOSITORY_TYPES]: true,
},
[FETCH_REPOSITORY_TYPES]: true
}
};
expect(isFetchRepositoryTypesPending(state)).toEqual(true);
});
it('should return false, when fetch repos is not pending', () => {
it("should return false, when fetch repos is not pending", () => {
expect(isFetchRepositoryTypesPending({})).toEqual(false);
});
it('should return error when fetch repository types did fail', () => {
it("should return error when fetch repository types did fail", () => {
const state = {
failure: {
[FETCH_REPOSITORY_TYPES]: error,
},
[FETCH_REPOSITORY_TYPES]: error
}
};
expect(getFetchRepositoryTypesFailure(state)).toEqual(error);
});
it('should return undefined when fetch repos did not fail', () => {
it("should return undefined when fetch repos did not fail", () => {
expect(getFetchRepositoryTypesFailure({})).toBe(undefined);
});
});

View File

@@ -1,14 +1,14 @@
import * as types from '../../modules/types';
import * as types from "../../modules/types";
import {
Action,
RepositoryType,
RepositoryTypeCollection,
} from '@scm-manager/ui-types';
import { apiClient } from '@scm-manager/ui-components';
import { isPending } from '../../modules/pending';
import { getFailure } from '../../modules/failure';
RepositoryTypeCollection
} from "@scm-manager/ui-types";
import { apiClient } from "@scm-manager/ui-components";
import { isPending } from "../../modules/pending";
import { getFailure } from "../../modules/failure";
export const FETCH_REPOSITORY_TYPES = 'scm/repos/FETCH_REPOSITORY_TYPES';
export const FETCH_REPOSITORY_TYPES = "scm/repos/FETCH_REPOSITORY_TYPES";
export const FETCH_REPOSITORY_TYPES_PENDING = `${FETCH_REPOSITORY_TYPES}_${types.PENDING_SUFFIX}`;
export const FETCH_REPOSITORY_TYPES_SUCCESS = `${FETCH_REPOSITORY_TYPES}_${types.SUCCESS_SUFFIX}`;
export const FETCH_REPOSITORY_TYPES_FAILURE = `${FETCH_REPOSITORY_TYPES}_${types.FAILURE_SUFFIX}`;
@@ -24,7 +24,7 @@ export function fetchRepositoryTypesIfNeeded() {
function fetchRepositoryTypes(dispatch: any) {
dispatch(fetchRepositoryTypesPending());
return apiClient
.get('repositoryTypes')
.get("repositoryTypes")
.then(response => response.json())
.then(repositoryTypes => {
dispatch(fetchRepositoryTypesSuccess(repositoryTypes));
@@ -46,23 +46,23 @@ export function shouldFetchRepositoryTypes(state: object) {
export function fetchRepositoryTypesPending(): Action {
return {
type: FETCH_REPOSITORY_TYPES_PENDING,
type: FETCH_REPOSITORY_TYPES_PENDING
};
}
export function fetchRepositoryTypesSuccess(
repositoryTypes: RepositoryTypeCollection,
repositoryTypes: RepositoryTypeCollection
): Action {
return {
type: FETCH_REPOSITORY_TYPES_SUCCESS,
payload: repositoryTypes,
payload: repositoryTypes
};
}
export function fetchRepositoryTypesFailure(error: Error): Action {
return {
type: FETCH_REPOSITORY_TYPES_FAILURE,
payload: error,
payload: error
};
}
@@ -71,11 +71,11 @@ export function fetchRepositoryTypesFailure(error: Error): Action {
export default function reducer(
state: RepositoryType[] = [],
action: Action = {
type: 'UNKNOWN',
},
type: "UNKNOWN"
}
): RepositoryType[] {
if (action.type === FETCH_REPOSITORY_TYPES_SUCCESS && action.payload) {
return action.payload._embedded['repositoryTypes'];
return action.payload._embedded["repositoryTypes"];
}
return state;
}

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { translate } from 'react-i18next';
import { Checkbox } from '@scm-manager/ui-components';
import React from "react";
import { translate } from "react-i18next";
import { Checkbox } from "@scm-manager/ui-components";
type Props = {
t: (p: string) => string;
@@ -17,8 +17,8 @@ class PermissionCheckbox extends React.Component<Props> {
<Checkbox
key={this.props.name}
name={this.props.name}
helpText={t('verbs.repository.' + this.props.name + '.description')}
label={t('verbs.repository.' + this.props.name + '.displayName')}
helpText={t("verbs.repository." + this.props.name + ".description")}
label={t("verbs.repository." + this.props.name + ".displayName")}
checked={this.props.checked}
onChange={this.props.onChange}
disabled={this.props.disabled}
@@ -27,4 +27,4 @@ class PermissionCheckbox extends React.Component<Props> {
}
}
export default translate('plugins')(PermissionCheckbox);
export default translate("plugins")(PermissionCheckbox);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { translate } from 'react-i18next';
import { Select } from '@scm-manager/ui-components';
import React from "react";
import { translate } from "react-i18next";
import { Select } from "@scm-manager/ui-components";
type Props = {
t: (p: string) => string;
@@ -20,19 +20,19 @@ class RoleSelector extends React.Component<Props> {
handleRoleChange,
loading,
label,
helpText,
helpText
} = this.props;
if (!availableRoles) return null;
const options = role
? this.createSelectOptions(availableRoles)
: ['', ...this.createSelectOptions(availableRoles)];
: ["", ...this.createSelectOptions(availableRoles)];
return (
<Select
onChange={handleRoleChange}
value={role ? role : ''}
value={role ? role : ""}
options={options}
loading={loading}
label={label}
@@ -45,10 +45,10 @@ class RoleSelector extends React.Component<Props> {
return roles.map(role => {
return {
label: role,
value: role,
value: role
};
});
}
}
export default translate('repos')(RoleSelector);
export default translate("repos")(RoleSelector);

View File

@@ -1,76 +1,75 @@
import React from 'react';
import { shallow, mount } from '@scm-manager/ui-tests/enzyme-router';
import '@scm-manager/ui-tests/enzyme';
import '@scm-manager/ui-tests/i18n';
import DeletePermissionButton from './DeletePermissionButton';
import React from "react";
import { shallow, mount } from "@scm-manager/ui-tests/enzyme-router";
import "@scm-manager/ui-tests/enzyme";
import "@scm-manager/ui-tests/i18n";
import DeletePermissionButton from "./DeletePermissionButton";
import { confirmAlert } from '@scm-manager/ui-components';
jest.mock('@scm-manager/ui-components', () => ({
import { confirmAlert } from "@scm-manager/ui-components";
jest.mock("@scm-manager/ui-components", () => ({
confirmAlert: jest.fn(),
DeleteButton: require.requireActual('@scm-manager/ui-components')
.DeleteButton,
DeleteButton: require.requireActual("@scm-manager/ui-components").DeleteButton
}));
describe('DeletePermissionButton', () => {
it('should render nothing, if the delete link is missing', () => {
describe("DeletePermissionButton", () => {
it("should render nothing, if the delete link is missing", () => {
const permission = {
_links: {},
_links: {}
};
const navLink = shallow(
<DeletePermissionButton
permission={permission}
deletePermission={() => {}}
/>,
/>
);
expect(navLink.text()).toBe('');
expect(navLink.text()).toBe("");
});
it('should render the delete icon', () => {
it("should render the delete icon", () => {
const permission = {
_links: {
delete: {
href: '/permission',
},
},
href: "/permission"
}
}
};
const deleteIcon = mount(
<DeletePermissionButton
permission={permission}
deletePermission={() => {}}
/>,
/>
);
expect(deleteIcon.html()).not.toBe('');
expect(deleteIcon.html()).not.toBe("");
});
it('should open the confirm dialog on button click', () => {
it("should open the confirm dialog on button click", () => {
const permission = {
_links: {
delete: {
href: '/permission',
},
},
href: "/permission"
}
}
};
const button = mount(
<DeletePermissionButton
permission={permission}
deletePermission={() => {}}
/>,
/>
);
button.find('.fa-trash').simulate('click');
button.find(".fa-trash").simulate("click");
expect(confirmAlert.mock.calls.length).toBe(1);
});
it('should call the delete permission function with delete url', () => {
it("should call the delete permission function with delete url", () => {
const permission = {
_links: {
delete: {
href: '/permission',
},
},
href: "/permission"
}
}
};
let calledUrl = null;
@@ -83,10 +82,10 @@ describe('DeletePermissionButton', () => {
permission={permission}
confirmDialog={false}
deletePermission={capture}
/>,
/>
);
button.find('.fa-trash').simulate('click');
button.find(".fa-trash").simulate("click");
expect(calledUrl).toBe('/permission');
expect(calledUrl).toBe("/permission");
});
});

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { translate } from 'react-i18next';
import { Permission } from '@scm-manager/ui-types';
import { confirmAlert } from '@scm-manager/ui-components';
import React from "react";
import { translate } from "react-i18next";
import { Permission } from "@scm-manager/ui-types";
import { confirmAlert } from "@scm-manager/ui-components";
type Props = {
permission: Permission;
@@ -12,39 +12,39 @@ type Props = {
deletePermission: (
permission: Permission,
namespace: string,
repoName: string,
repoName: string
) => void;
loading: boolean;
};
class DeletePermissionButton extends React.Component<Props> {
static defaultProps = {
confirmDialog: true,
confirmDialog: true
};
deletePermission = () => {
this.props.deletePermission(
this.props.permission,
this.props.namespace,
this.props.repoName,
this.props.repoName
);
};
confirmDelete = () => {
const { t } = this.props;
confirmAlert({
title: t('permission.delete-permission-button.confirm-alert.title'),
message: t('permission.delete-permission-button.confirm-alert.message'),
title: t("permission.delete-permission-button.confirm-alert.title"),
message: t("permission.delete-permission-button.confirm-alert.message"),
buttons: [
{
label: t('permission.delete-permission-button.confirm-alert.submit'),
onClick: () => this.deletePermission(),
label: t("permission.delete-permission-button.confirm-alert.submit"),
onClick: () => this.deletePermission()
},
{
label: t('permission.delete-permission-button.confirm-alert.cancel'),
onClick: () => null,
},
],
label: t("permission.delete-permission-button.confirm-alert.cancel"),
onClick: () => null
}
]
});
};
@@ -69,4 +69,4 @@ class DeletePermissionButton extends React.Component<Props> {
}
}
export default translate('repos')(DeletePermissionButton);
export default translate("repos")(DeletePermissionButton);

View File

@@ -1,69 +1,69 @@
import * as validator from './permissionValidation';
import * as validator from "./permissionValidation";
describe('permission validation', () => {
it('should return true if permission is valid and does not exist', () => {
describe("permission validation", () => {
it("should return true if permission is valid and does not exist", () => {
const permissions = [];
const name = 'PermissionName';
const name = "PermissionName";
const groupPermission = false;
expect(
validator.isPermissionValid(name, groupPermission, permissions),
validator.isPermissionValid(name, groupPermission, permissions)
).toBe(true);
});
it('should return true if permission is valid and does not exists with same group permission', () => {
it("should return true if permission is valid and does not exists with same group permission", () => {
const permissions = [
{
name: 'PermissionName',
name: "PermissionName",
groupPermission: true,
type: 'READ',
type: "READ",
_links: {},
verbs: [],
},
verbs: []
}
];
const name = 'PermissionName';
const name = "PermissionName";
const groupPermission = false;
expect(
validator.isPermissionValid(name, groupPermission, permissions),
validator.isPermissionValid(name, groupPermission, permissions)
).toBe(true);
});
it('should return false if permission is valid but exists', () => {
it("should return false if permission is valid but exists", () => {
const permissions = [
{
name: 'PermissionName',
name: "PermissionName",
groupPermission: false,
type: 'READ',
type: "READ",
_links: {},
verbs: [],
},
verbs: []
}
];
const name = 'PermissionName';
const name = "PermissionName";
const groupPermission = false;
expect(
validator.isPermissionValid(name, groupPermission, permissions),
validator.isPermissionValid(name, groupPermission, permissions)
).toBe(false);
});
it('should return false if permission does not exist but is invalid', () => {
it("should return false if permission does not exist but is invalid", () => {
const permissions = [];
const name = '@PermissionName';
const name = "@PermissionName";
const groupPermission = false;
expect(
validator.isPermissionValid(name, groupPermission, permissions),
validator.isPermissionValid(name, groupPermission, permissions)
).toBe(false);
});
it('should return false if permission is not valid and does not exist', () => {
it("should return false if permission is not valid and does not exist", () => {
const permissions = [];
const name = '@PermissionName';
const name = "@PermissionName";
const groupPermission = false;
expect(
validator.isPermissionValid(name, groupPermission, permissions),
validator.isPermissionValid(name, groupPermission, permissions)
).toBe(false);
});
});

View File

@@ -1,5 +1,5 @@
import { validation } from '@scm-manager/ui-components';
import { PermissionCollection } from '@scm-manager/ui-types';
import { validation } from "@scm-manager/ui-components";
import { PermissionCollection } from "@scm-manager/ui-types";
const isNameValid = validation.isNameValid;
@@ -8,7 +8,7 @@ export { isNameValid };
export const isPermissionValid = (
name: string,
groupPermission: boolean,
permissions: PermissionCollection,
permissions: PermissionCollection
) => {
return (
isNameValid(name) &&
@@ -19,7 +19,7 @@ export const isPermissionValid = (
const currentPermissionIncludeName = (
name: string,
groupPermission: boolean,
permissions: PermissionCollection,
permissions: PermissionCollection
) => {
for (let i = 0; i < permissions.length; i++) {
if (

View File

@@ -1,12 +1,12 @@
import React from 'react';
import React from "react";
import {
ButtonGroup,
Button,
SubmitButton,
Modal,
} from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
import PermissionCheckbox from '../components/PermissionCheckbox';
Modal
} from "@scm-manager/ui-components";
import { translate } from "react-i18next";
import PermissionCheckbox from "../components/PermissionCheckbox";
type Props = {
readOnly: boolean;
@@ -32,10 +32,10 @@ class AdvancedPermissionsDialog extends React.Component<Props, State> {
verb =>
(verbs[verb] = props.selectedVerbs
? props.selectedVerbs.includes(verb)
: false),
: false)
);
this.state = {
verbs,
verbs
};
}
@@ -54,7 +54,7 @@ class AdvancedPermissionsDialog extends React.Component<Props, State> {
));
const submitButton = !readOnly ? (
<SubmitButton label={t('permission.advanced.dialog.submit')} />
<SubmitButton label={t("permission.advanced.dialog.submit")} />
) : null;
const body = <>{verbSelectBoxes}</>;
@@ -64,7 +64,7 @@ class AdvancedPermissionsDialog extends React.Component<Props, State> {
<ButtonGroup>
{submitButton}
<Button
label={t('permission.advanced.dialog.abort')}
label={t("permission.advanced.dialog.abort")}
action={onClose}
/>
</ButtonGroup>
@@ -73,7 +73,7 @@ class AdvancedPermissionsDialog extends React.Component<Props, State> {
return (
<Modal
title={t('permission.advanced.dialog.title')}
title={t("permission.advanced.dialog.title")}
closeFunction={() => onClose()}
body={body}
footer={footer}
@@ -86,10 +86,10 @@ class AdvancedPermissionsDialog extends React.Component<Props, State> {
const { verbs } = this.state;
const newVerbs = {
...verbs,
[name]: value,
[name]: value
};
this.setState({
verbs: newVerbs,
verbs: newVerbs
});
};
@@ -97,9 +97,9 @@ class AdvancedPermissionsDialog extends React.Component<Props, State> {
this.props.onSubmit(
Object.entries(this.state.verbs)
.filter(e => e[1])
.map(e => e[0]),
.map(e => e[0])
);
};
}
export default translate('repos')(AdvancedPermissionsDialog);
export default translate("repos")(AdvancedPermissionsDialog);

View File

@@ -1,11 +1,11 @@
import React from 'react';
import { translate } from 'react-i18next';
import React from "react";
import { translate } from "react-i18next";
import {
PermissionCollection,
PermissionCreateEntry,
RepositoryRole,
SelectValue,
} from '@scm-manager/ui-types';
SelectValue
} from "@scm-manager/ui-types";
import {
Button,
GroupAutocomplete,
@@ -13,12 +13,12 @@ import {
Radio,
SubmitButton,
Subtitle,
UserAutocomplete,
} from '@scm-manager/ui-components';
import * as validator from '../components/permissionValidation';
import RoleSelector from '../components/RoleSelector';
import AdvancedPermissionsDialog from './AdvancedPermissionsDialog';
import { findVerbsForRole } from '../modules/permissions';
UserAutocomplete
} from "@scm-manager/ui-components";
import * as validator from "../components/permissionValidation";
import RoleSelector from "../components/RoleSelector";
import AdvancedPermissionsDialog from "./AdvancedPermissionsDialog";
import { findVerbsForRole } from "../modules/permissions";
type Props = {
availableRoles: RepositoryRole[];
@@ -48,13 +48,13 @@ class CreatePermissionForm extends React.Component<Props, State> {
super(props);
this.state = {
name: '',
name: "",
role: props.availableRoles[0].name,
verbs: undefined,
groupPermission: false,
valid: true,
value: undefined,
showAdvancedDialog: false,
showAdvancedDialog: false
};
}
@@ -73,9 +73,9 @@ class CreatePermissionForm extends React.Component<Props, State> {
permissionScopeChanged = (groupPermission: boolean) => {
this.setState({
value: undefined,
name: '',
name: "",
groupPermission,
valid: false,
valid: false
});
};
@@ -86,7 +86,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
<GroupAutocomplete
autocompleteLink={this.props.groupAutocompleteLink}
valueSelected={this.selectName}
value={this.state.value ? this.state.value : ''}
value={this.state.value ? this.state.value : ""}
/>
);
}
@@ -94,7 +94,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
<UserAutocomplete
autocompleteLink={this.props.userAutocompleteLink}
valueSelected={this.selectName}
value={this.state.value ? this.state.value : ''}
value={this.state.value ? this.state.value : ""}
/>
);
};
@@ -106,8 +106,8 @@ class CreatePermissionForm extends React.Component<Props, State> {
valid: validator.isPermissionValid(
value.value.id,
this.state.groupPermission,
this.props.currentPermissions,
),
this.props.currentPermissions
)
});
};
@@ -132,7 +132,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
<>
<hr />
<Subtitle
subtitle={t('permission.add-permission.add-permission-heading')}
subtitle={t("permission.add-permission.add-permission-heading")}
/>
{advancedDialog}
<form onSubmit={this.submit}>
@@ -142,14 +142,14 @@ class CreatePermissionForm extends React.Component<Props, State> {
name="permission_scope"
value="USER_PERMISSION"
checked={!this.state.groupPermission}
label={t('permission.user-permission')}
label={t("permission.user-permission")}
onChange={this.userPermissionScopeChanged}
/>
<Radio
name="permission_scope"
value="GROUP_PERMISSION"
checked={this.state.groupPermission}
label={t('permission.group-permission')}
label={t("permission.group-permission")}
onChange={this.groupPermissionScopeChanged}
/>
</div>
@@ -163,19 +163,19 @@ class CreatePermissionForm extends React.Component<Props, State> {
<div className="column is-narrow">
<RoleSelector
availableRoles={availableRoleNames}
label={t('permission.role')}
helpText={t('permission.help.roleHelpText')}
label={t("permission.role")}
helpText={t("permission.help.roleHelpText")}
handleRoleChange={this.handleRoleChange}
role={role}
/>
</div>
<div className="column">
<LabelWithHelpIcon
label={t('permission.permissions')}
helpText={t('permission.help.permissionsHelpText')}
label={t("permission.permissions")}
helpText={t("permission.help.permissionsHelpText")}
/>
<Button
label={t('permission.advanced-button.label')}
label={t("permission.advanced-button.label")}
action={this.toggleAdvancedPermissionsDialog}
/>
</div>
@@ -185,9 +185,9 @@ class CreatePermissionForm extends React.Component<Props, State> {
<div className="columns">
<div className="column">
<SubmitButton
label={t('permission.add-permission.submit-button')}
label={t("permission.add-permission.submit-button")}
loading={loading}
disabled={!this.state.valid || this.state.name === ''}
disabled={!this.state.valid || this.state.name === ""}
/>
</div>
</div>
@@ -198,7 +198,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
toggleAdvancedPermissionsDialog = () => {
this.setState(prevState => ({
showAdvancedDialog: !prevState.showAdvancedDialog,
showAdvancedDialog: !prevState.showAdvancedDialog
}));
};
@@ -206,7 +206,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
this.setState({
showAdvancedDialog: false,
role: undefined,
verbs: newVerbs,
verbs: newVerbs
});
};
@@ -215,7 +215,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
name: this.state.name,
role: this.state.role,
verbs: this.state.verbs,
groupPermission: this.state.groupPermission,
groupPermission: this.state.groupPermission
});
this.removeState();
e.preventDefault();
@@ -223,11 +223,11 @@ class CreatePermissionForm extends React.Component<Props, State> {
removeState = () => {
this.setState({
name: '',
name: "",
role: this.props.availableRoles[0].name,
verbs: undefined,
valid: true,
value: undefined,
value: undefined
});
};
@@ -238,7 +238,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
}
this.setState({
role: selectedRole.name,
verbs: [],
verbs: []
});
};
@@ -247,4 +247,4 @@ class CreatePermissionForm extends React.Component<Props, State> {
};
}
export default translate('repos')(CreatePermissionForm);
export default translate("repos")(CreatePermissionForm);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import React from "react";
import { connect } from "react-redux";
import { translate } from "react-i18next";
import {
createPermission,
createPermissionReset,
@@ -20,30 +20,30 @@ import {
isCreatePermissionPending,
isFetchAvailablePermissionsPending,
isFetchPermissionsPending,
modifyPermissionReset,
} from '../modules/permissions';
modifyPermissionReset
} from "../modules/permissions";
import {
ErrorPage,
LabelWithHelpIcon,
Loading,
Subtitle,
} from '@scm-manager/ui-components';
Subtitle
} from "@scm-manager/ui-components";
import {
Permission,
PermissionCollection,
PermissionCreateEntry,
RepositoryRole,
} from '@scm-manager/ui-types';
import SinglePermission from './SinglePermission';
import CreatePermissionForm from './CreatePermissionForm';
import { History } from 'history';
import { getPermissionsLink } from '../../modules/repos';
RepositoryRole
} from "@scm-manager/ui-types";
import SinglePermission from "./SinglePermission";
import CreatePermissionForm from "./CreatePermissionForm";
import { History } from "history";
import { getPermissionsLink } from "../../modules/repos";
import {
getGroupAutoCompleteLink,
getRepositoryRolesLink,
getRepositoryVerbsLink,
getUserAutoCompleteLink,
} from '../../../modules/indexResource';
getUserAutoCompleteLink
} from "../../../modules/indexResource";
type Props = {
availablePermissions: boolean;
@@ -65,7 +65,7 @@ type Props = {
//dispatch functions
fetchAvailablePermissionsIfNeeded: (
repositoryRolesLink: string,
repositoryVerbsLink: string,
repositoryVerbsLink: string
) => void;
fetchPermissions: (link: string, namespace: string, repoName: string) => void;
createPermission: (
@@ -73,7 +73,7 @@ type Props = {
permission: PermissionCreateEntry,
namespace: string,
repoName: string,
callback?: () => void,
callback?: () => void
) => void;
createPermissionReset: (p1: string, p2: string) => void;
modifyPermissionReset: (p1: string, p2: string) => void;
@@ -96,7 +96,7 @@ class Permissions extends React.Component<Props> {
deletePermissionReset,
permissionsLink,
repositoryRolesLink,
repositoryVerbsLink,
repositoryVerbsLink
} = this.props;
createPermissionReset(namespace, repoName);
@@ -111,7 +111,7 @@ class Permissions extends React.Component<Props> {
this.props.permissionsLink,
permission,
this.props.namespace,
this.props.repoName,
this.props.repoName
);
};
@@ -129,13 +129,13 @@ class Permissions extends React.Component<Props> {
loadingCreatePermission,
hasPermissionToCreate,
userAutocompleteLink,
groupAutocompleteLink,
groupAutocompleteLink
} = this.props;
if (error) {
return (
<ErrorPage
title={t('permission.error-title')}
subtitle={t('permission.error-subtitle')}
title={t("permission.error-title")}
subtitle={t("permission.error-subtitle")}
error={error}
/>
);
@@ -159,26 +159,26 @@ class Permissions extends React.Component<Props> {
return (
<div>
<Subtitle subtitle={t('permission.title')} />
<Subtitle subtitle={t("permission.title")} />
<table className="card-table table is-hoverable is-fullwidth">
<thead>
<tr>
<th>
<LabelWithHelpIcon
label={t('permission.name')}
helpText={t('permission.help.nameHelpText')}
label={t("permission.name")}
helpText={t("permission.help.nameHelpText")}
/>
</th>
<th>
<LabelWithHelpIcon
label={t('permission.role')}
helpText={t('permission.help.roleHelpText')}
label={t("permission.role")}
helpText={t("permission.help.roleHelpText")}
/>
</th>
<th>
<LabelWithHelpIcon
label={t('permission.permissions')}
helpText={t('permission.help.permissionsHelpText')}
label={t("permission.permissions")}
helpText={t("permission.help.permissionsHelpText")}
/>
</th>
<th />
@@ -221,7 +221,7 @@ const mapStateToProps = (state, ownProps) => {
const loadingCreatePermission = isCreatePermissionPending(
state,
namespace,
repoName,
repoName
);
const hasPermissionToCreate = hasCreatePermission(state, namespace, repoName);
const repositoryRolesLink = getRepositoryRolesLink(state);
@@ -248,7 +248,7 @@ const mapStateToProps = (state, ownProps) => {
loadingCreatePermission,
permissionsLink,
groupAutocompleteLink,
userAutocompleteLink,
userAutocompleteLink
};
};
@@ -259,13 +259,13 @@ const mapDispatchToProps = dispatch => {
},
fetchAvailablePermissionsIfNeeded: (
repositoryRolesLink: string,
repositoryVerbsLink: string,
repositoryVerbsLink: string
) => {
dispatch(
fetchAvailablePermissionsIfNeeded(
repositoryRolesLink,
repositoryVerbsLink,
),
repositoryVerbsLink
)
);
},
createPermission: (
@@ -273,10 +273,10 @@ const mapDispatchToProps = dispatch => {
permission: PermissionCreateEntry,
namespace: string,
repoName: string,
callback?: () => void,
callback?: () => void
) => {
dispatch(
createPermission(link, permission, namespace, repoName, callback),
createPermission(link, permission, namespace, repoName, callback)
);
},
createPermissionReset: (namespace: string, repoName: string) => {
@@ -287,11 +287,11 @@ const mapDispatchToProps = dispatch => {
},
deletePermissionReset: (namespace: string, repoName: string) => {
dispatch(deletePermissionReset(namespace, repoName));
},
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(translate('repos')(Permissions));
mapDispatchToProps
)(translate("repos")(Permissions));

View File

@@ -1,20 +1,20 @@
import React from 'react';
import { connect } from 'react-redux';
import { History } from 'history';
import { translate } from 'react-i18next';
import styled from 'styled-components';
import { RepositoryRole, Permission } from '@scm-manager/ui-types';
import { Button, Icon } from '@scm-manager/ui-components';
import React from "react";
import { connect } from "react-redux";
import { History } from "history";
import { translate } from "react-i18next";
import styled from "styled-components";
import { RepositoryRole, Permission } from "@scm-manager/ui-types";
import { Button, Icon } from "@scm-manager/ui-components";
import {
modifyPermission,
isModifyPermissionPending,
deletePermission,
isDeletePermissionPending,
findVerbsForRole,
} from '../modules/permissions';
import DeletePermissionButton from '../components/buttons/DeletePermissionButton';
import RoleSelector from '../components/RoleSelector';
import AdvancedPermissionsDialog from './AdvancedPermissionsDialog';
findVerbsForRole
} from "../modules/permissions";
import DeletePermissionButton from "../components/buttons/DeletePermissionButton";
import RoleSelector from "../components/RoleSelector";
import AdvancedPermissionsDialog from "./AdvancedPermissionsDialog";
type Props = {
availableRepositoryRoles: RepositoryRole[];
@@ -23,7 +23,7 @@ type Props = {
modifyPermission: (
permission: Permission,
namespace: string,
name: string,
name: string
) => void;
permission: Permission;
t: (p: string) => string;
@@ -35,7 +35,7 @@ type Props = {
deletePermission: (
permission: Permission,
namespace: string,
name: string,
name: string
) => void;
deleteLoading: boolean;
};
@@ -64,13 +64,13 @@ class SinglePermission extends React.Component<Props, State> {
this.state = {
permission: {
name: '',
name: "",
role: undefined,
verbs: defaultPermission.verbs,
groupPermission: false,
_links: {},
_links: {}
},
showAdvancedDialog: false,
showAdvancedDialog: false
};
}
@@ -84,8 +84,8 @@ class SinglePermission extends React.Component<Props, State> {
role: permission.role,
verbs: permission.verbs,
groupPermission: permission.groupPermission,
_links: permission._links,
},
_links: permission._links
}
});
}
}
@@ -94,7 +94,7 @@ class SinglePermission extends React.Component<Props, State> {
this.props.deletePermission(
this.props.permission,
this.props.namespace,
this.props.repoName,
this.props.repoName
);
};
@@ -105,14 +105,14 @@ class SinglePermission extends React.Component<Props, State> {
loading,
namespace,
repoName,
t,
t
} = this.props;
const { permission, showAdvancedDialog } = this.state;
const availableRoleNames =
!!availableRepositoryRoles && availableRepositoryRoles.map(r => r.name);
const readOnly = !this.mayChangePermissions();
const roleSelector = readOnly ? (
<td>{permission.role ? permission.role : t('permission.custom')}</td>
<td>{permission.role ? permission.role : t("permission.custom")}</td>
) : (
<td>
<RoleSelector
@@ -140,9 +140,9 @@ class SinglePermission extends React.Component<Props, State> {
const iconType =
permission && permission.groupPermission ? (
<Icon title={t('permission.group')} name="user-friends" />
<Icon title={t("permission.group")} name="user-friends" />
) : (
<Icon title={t('permission.user')} name="user" />
<Icon title={t("permission.user")} name="user" />
);
return (
@@ -153,7 +153,7 @@ class SinglePermission extends React.Component<Props, State> {
{roleSelector}
<VCenteredTd>
<Button
label={t('permission.advanced-button.label')}
label={t("permission.advanced-button.label")}
action={this.handleDetailedPermissionsPressed}
/>
</VCenteredTd>
@@ -177,13 +177,13 @@ class SinglePermission extends React.Component<Props, State> {
handleDetailedPermissionsPressed = () => {
this.setState({
showAdvancedDialog: true,
showAdvancedDialog: true
});
};
closeAdvancedPermissionsDialog = () => {
this.setState({
showAdvancedDialog: false,
showAdvancedDialog: false
});
};
@@ -195,10 +195,10 @@ class SinglePermission extends React.Component<Props, State> {
permission: {
...permission,
role: undefined,
verbs: newVerbs,
},
verbs: newVerbs
}
},
() => this.modifyPermissionVerbs(newVerbs),
() => this.modifyPermissionVerbs(newVerbs)
);
};
@@ -209,10 +209,10 @@ class SinglePermission extends React.Component<Props, State> {
permission: {
...permission,
role: role,
verbs: undefined,
},
verbs: undefined
}
},
() => this.modifyPermissionRole(role),
() => this.modifyPermissionRole(role)
);
};
@@ -227,7 +227,7 @@ class SinglePermission extends React.Component<Props, State> {
this.props.modifyPermission(
permission,
this.props.namespace,
this.props.repoName,
this.props.repoName
);
};
@@ -237,7 +237,7 @@ class SinglePermission extends React.Component<Props, State> {
this.props.modifyPermission(
permission,
this.props.namespace,
this.props.repoName,
this.props.repoName
);
};
}
@@ -248,18 +248,18 @@ const mapStateToProps = (state, ownProps) => {
state,
ownProps.namespace,
ownProps.repoName,
permission,
permission
);
const deleteLoading = isDeletePermissionPending(
state,
ownProps.namespace,
ownProps.repoName,
permission,
permission
);
return {
loading,
deleteLoading,
deleteLoading
};
};
@@ -268,20 +268,20 @@ const mapDispatchToProps = dispatch => {
modifyPermission: (
permission: Permission,
namespace: string,
repoName: string,
repoName: string
) => {
dispatch(modifyPermission(permission, namespace, repoName));
},
deletePermission: (
permission: Permission,
namespace: string,
repoName: string,
repoName: string
) => {
dispatch(deletePermission(permission, namespace, repoName));
},
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(translate('repos')(SinglePermission));
mapDispatchToProps
)(translate("repos")(SinglePermission));

View File

@@ -1,47 +1,47 @@
import { Action } from '@scm-manager/ui-components';
import { apiClient } from '@scm-manager/ui-components';
import * as types from '../../../modules/types';
import { Action } from "@scm-manager/ui-components";
import { apiClient } from "@scm-manager/ui-components";
import * as types from "../../../modules/types";
import {
RepositoryRole,
Permission,
PermissionCollection,
PermissionCreateEntry,
} from '@scm-manager/ui-types';
import { isPending } from '../../../modules/pending';
import { getFailure } from '../../../modules/failure';
import { Dispatch } from 'redux';
PermissionCreateEntry
} from "@scm-manager/ui-types";
import { isPending } from "../../../modules/pending";
import { getFailure } from "../../../modules/failure";
import { Dispatch } from "redux";
export const FETCH_AVAILABLE = 'scm/permissions/FETCH_AVAILABLE';
export const FETCH_AVAILABLE = "scm/permissions/FETCH_AVAILABLE";
export const FETCH_AVAILABLE_PENDING = `${FETCH_AVAILABLE}_${types.PENDING_SUFFIX}`;
export const FETCH_AVAILABLE_SUCCESS = `${FETCH_AVAILABLE}_${types.SUCCESS_SUFFIX}`;
export const FETCH_AVAILABLE_FAILURE = `${FETCH_AVAILABLE}_${types.FAILURE_SUFFIX}`;
export const FETCH_PERMISSIONS = 'scm/permissions/FETCH_PERMISSIONS';
export const FETCH_PERMISSIONS = "scm/permissions/FETCH_PERMISSIONS";
export const FETCH_PERMISSIONS_PENDING = `${FETCH_PERMISSIONS}_${types.PENDING_SUFFIX}`;
export const FETCH_PERMISSIONS_SUCCESS = `${FETCH_PERMISSIONS}_${types.SUCCESS_SUFFIX}`;
export const FETCH_PERMISSIONS_FAILURE = `${FETCH_PERMISSIONS}_${types.FAILURE_SUFFIX}`;
export const MODIFY_PERMISSION = 'scm/permissions/MODFIY_PERMISSION';
export const MODIFY_PERMISSION = "scm/permissions/MODFIY_PERMISSION";
export const MODIFY_PERMISSION_PENDING = `${MODIFY_PERMISSION}_${types.PENDING_SUFFIX}`;
export const MODIFY_PERMISSION_SUCCESS = `${MODIFY_PERMISSION}_${types.SUCCESS_SUFFIX}`;
export const MODIFY_PERMISSION_FAILURE = `${MODIFY_PERMISSION}_${types.FAILURE_SUFFIX}`;
export const MODIFY_PERMISSION_RESET = `${MODIFY_PERMISSION}_${types.RESET_SUFFIX}`;
export const CREATE_PERMISSION = 'scm/permissions/CREATE_PERMISSION';
export const CREATE_PERMISSION = "scm/permissions/CREATE_PERMISSION";
export const CREATE_PERMISSION_PENDING = `${CREATE_PERMISSION}_${types.PENDING_SUFFIX}`;
export const CREATE_PERMISSION_SUCCESS = `${CREATE_PERMISSION}_${types.SUCCESS_SUFFIX}`;
export const CREATE_PERMISSION_FAILURE = `${CREATE_PERMISSION}_${types.FAILURE_SUFFIX}`;
export const CREATE_PERMISSION_RESET = `${CREATE_PERMISSION}_${types.RESET_SUFFIX}`;
export const DELETE_PERMISSION = 'scm/permissions/DELETE_PERMISSION';
export const DELETE_PERMISSION = "scm/permissions/DELETE_PERMISSION";
export const DELETE_PERMISSION_PENDING = `${DELETE_PERMISSION}_${types.PENDING_SUFFIX}`;
export const DELETE_PERMISSION_SUCCESS = `${DELETE_PERMISSION}_${types.SUCCESS_SUFFIX}`;
export const DELETE_PERMISSION_FAILURE = `${DELETE_PERMISSION}_${types.FAILURE_SUFFIX}`;
export const DELETE_PERMISSION_RESET = `${DELETE_PERMISSION}_${types.RESET_SUFFIX}`;
const CONTENT_TYPE = 'application/vnd.scmm-repositoryPermission+json';
const CONTENT_TYPE = "application/vnd.scmm-repositoryPermission+json";
// fetch available permissions
export function fetchAvailablePermissionsIfNeeded(
repositoryRolesLink: string,
repositoryVerbsLink: string,
repositoryVerbsLink: string
) {
return function(dispatch: any, getState: () => object) {
if (shouldFetchAvailablePermissions(getState())) {
@@ -49,7 +49,7 @@ export function fetchAvailablePermissionsIfNeeded(
dispatch,
getState,
repositoryRolesLink,
repositoryVerbsLink,
repositoryVerbsLink
);
}
};
@@ -59,7 +59,7 @@ export function fetchAvailablePermissions(
dispatch: any,
getState: () => object,
repositoryRolesLink: string,
repositoryVerbsLink: string,
repositoryVerbsLink: string
) {
dispatch(fetchAvailablePending());
return apiClient
@@ -74,7 +74,7 @@ export function fetchAvailablePermissions(
.then(repositoryVerbs => {
return {
repositoryVerbs,
repositoryRoles,
repositoryRoles
};
});
})
@@ -100,17 +100,17 @@ export function fetchAvailablePending(): Action {
return {
type: FETCH_AVAILABLE_PENDING,
payload: {},
itemId: 'available',
itemId: "available"
};
}
export function fetchAvailableSuccess(
available: [RepositoryRole[], string[]],
available: [RepositoryRole[], string[]]
): Action {
return {
type: FETCH_AVAILABLE_SUCCESS,
payload: available,
itemId: 'available',
itemId: "available"
};
}
@@ -118,9 +118,9 @@ export function fetchAvailableFailure(error: Error): Action {
return {
type: FETCH_AVAILABLE_FAILURE,
payload: {
error,
error
},
itemId: 'available',
itemId: "available"
};
}
@@ -129,7 +129,7 @@ export function fetchAvailableFailure(error: Error): Action {
export function fetchPermissions(
link: string,
namespace: string,
repoName: string,
repoName: string
) {
return function(dispatch: any) {
dispatch(fetchPermissionsPending(namespace, repoName));
@@ -147,43 +147,43 @@ export function fetchPermissions(
export function fetchPermissionsPending(
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: FETCH_PERMISSIONS_PENDING,
payload: {
namespace,
repoName,
repoName
},
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
export function fetchPermissionsSuccess(
permissions: any,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: FETCH_PERMISSIONS_SUCCESS,
payload: permissions,
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
export function fetchPermissionsFailure(
namespace: string,
repoName: string,
error: Error,
error: Error
): Action {
return {
type: FETCH_PERMISSIONS_FAILURE,
payload: {
namespace,
repoName,
error,
error
},
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
@@ -193,7 +193,7 @@ export function modifyPermission(
permission: Permission,
namespace: string,
repoName: string,
callback?: () => void,
callback?: () => void
) {
return function(dispatch: any) {
dispatch(modifyPermissionPending(permission, namespace, repoName));
@@ -214,27 +214,27 @@ export function modifyPermission(
export function modifyPermissionPending(
permission: Permission,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: MODIFY_PERMISSION_PENDING,
payload: permission,
itemId: createItemId(permission, namespace, repoName),
itemId: createItemId(permission, namespace, repoName)
};
}
export function modifyPermissionSuccess(
permission: Permission,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: MODIFY_PERMISSION_SUCCESS,
payload: {
permission,
position: namespace + '/' + repoName,
position: namespace + "/" + repoName
},
itemId: createItemId(permission, namespace, repoName),
itemId: createItemId(permission, namespace, repoName)
};
}
@@ -242,21 +242,21 @@ export function modifyPermissionFailure(
permission: Permission,
error: Error,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: MODIFY_PERMISSION_FAILURE,
payload: {
error,
permission,
permission
},
itemId: createItemId(permission, namespace, repoName),
itemId: createItemId(permission, namespace, repoName)
};
}
function newPermissions(
oldPermissions: PermissionCollection,
newPermission: Permission,
newPermission: Permission
) {
for (let i = 0; i < oldPermissions.length; i++) {
if (oldPermissions[i].name === newPermission.name) {
@@ -271,9 +271,9 @@ export function modifyPermissionReset(namespace: string, repoName: string) {
type: MODIFY_PERMISSION_RESET,
payload: {
namespace,
repoName,
repoName
},
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
@@ -283,27 +283,27 @@ export function createPermission(
permission: PermissionCreateEntry,
namespace: string,
repoName: string,
callback?: () => void,
callback?: () => void
) {
return function(dispatch: Dispatch) {
dispatch(createPermissionPending(permission, namespace, repoName));
return apiClient
.post(link, permission, CONTENT_TYPE)
.then(response => {
const location = response.headers.get('Location');
const location = response.headers.get("Location");
return apiClient.get(location);
})
.then(response => response.json())
.then(createdPermission => {
dispatch(
createPermissionSuccess(createdPermission, namespace, repoName),
createPermissionSuccess(createdPermission, namespace, repoName)
);
if (callback) {
callback();
}
})
.catch(err =>
dispatch(createPermissionFailure(err, namespace, repoName)),
dispatch(createPermissionFailure(err, namespace, repoName))
);
};
}
@@ -311,46 +311,46 @@ export function createPermission(
export function createPermissionPending(
permission: PermissionCreateEntry,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: CREATE_PERMISSION_PENDING,
payload: permission,
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
export function createPermissionSuccess(
permission: PermissionCreateEntry,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: CREATE_PERMISSION_SUCCESS,
payload: {
permission,
position: namespace + '/' + repoName,
position: namespace + "/" + repoName
},
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
export function createPermissionFailure(
error: Error,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: CREATE_PERMISSION_FAILURE,
payload: error,
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
export function createPermissionReset(namespace: string, repoName: string) {
return {
type: CREATE_PERMISSION_RESET,
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
@@ -360,7 +360,7 @@ export function deletePermission(
permission: Permission,
namespace: string,
repoName: string,
callback?: () => void,
callback?: () => void
) {
return function(dispatch: any) {
dispatch(deletePermissionPending(permission, namespace, repoName));
@@ -381,27 +381,27 @@ export function deletePermission(
export function deletePermissionPending(
permission: Permission,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: DELETE_PERMISSION_PENDING,
payload: permission,
itemId: createItemId(permission, namespace, repoName),
itemId: createItemId(permission, namespace, repoName)
};
}
export function deletePermissionSuccess(
permission: Permission,
namespace: string,
repoName: string,
repoName: string
): Action {
return {
type: DELETE_PERMISSION_SUCCESS,
payload: {
permission,
position: namespace + '/' + repoName,
position: namespace + "/" + repoName
},
itemId: createItemId(permission, namespace, repoName),
itemId: createItemId(permission, namespace, repoName)
};
}
@@ -409,15 +409,15 @@ export function deletePermissionFailure(
permission: Permission,
namespace: string,
repoName: string,
error: Error,
error: Error
): Action {
return {
type: DELETE_PERMISSION_FAILURE,
payload: {
error,
permission,
permission
},
itemId: createItemId(permission, namespace, repoName),
itemId: createItemId(permission, namespace, repoName)
};
}
@@ -426,15 +426,15 @@ export function deletePermissionReset(namespace: string, repoName: string) {
type: DELETE_PERMISSION_RESET,
payload: {
namespace,
repoName,
repoName
},
itemId: namespace + '/' + repoName,
itemId: namespace + "/" + repoName
};
}
function deletePermissionFromState(
oldPermissions: PermissionCollection,
permission: Permission,
permission: Permission
) {
let newPermission = [];
for (let i = 0; i < oldPermissions.length; i++) {
@@ -451,18 +451,18 @@ function deletePermissionFromState(
function createItemId(
permission: Permission,
namespace: string,
repoName: string,
repoName: string
) {
let groupPermission = permission.groupPermission ? '@' : '';
return namespace + '/' + repoName + '/' + groupPermission + permission.name;
let groupPermission = permission.groupPermission ? "@" : "";
return namespace + "/" + repoName + "/" + groupPermission + permission.name;
}
// reducer
export default function reducer(
state: object = {},
action: Action = {
type: 'UNKNOWN',
},
type: "UNKNOWN"
}
): object {
if (!action.payload) {
return state;
@@ -471,28 +471,28 @@ export default function reducer(
case FETCH_AVAILABLE_SUCCESS:
return {
...state,
available: action.payload,
available: action.payload
};
case FETCH_PERMISSIONS_SUCCESS:
return {
...state,
[action.itemId]: {
entries: action.payload._embedded.permissions,
createPermission: !!action.payload._links.create,
},
createPermission: !!action.payload._links.create
}
};
case MODIFY_PERMISSION_SUCCESS:
const positionOfPermission = action.payload.position;
const newPermission = newPermissions(
state[action.payload.position].entries,
action.payload.permission,
action.payload.permission
);
return {
...state,
[positionOfPermission]: {
...state[positionOfPermission],
entries: newPermission,
},
entries: newPermission
}
};
case CREATE_PERMISSION_SUCCESS:
// return state;
@@ -503,21 +503,21 @@ export default function reducer(
...state,
[position]: {
...state[position],
entries: permissions,
},
entries: permissions
}
};
case DELETE_PERMISSION_SUCCESS:
const permissionPosition = action.payload.position;
const new_Permissions = deletePermissionFromState(
state[action.payload.position].entries,
action.payload.permission,
action.payload.permission
);
return {
...state,
[permissionPosition]: {
...state[permissionPosition],
entries: new_Permissions,
},
entries: new_Permissions
}
};
default:
return state;
@@ -550,47 +550,47 @@ function available(state: object) {
export function getPermissionsOfRepo(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
if (state.permissions && state.permissions[namespace + '/' + repoName]) {
return state.permissions[namespace + '/' + repoName].entries;
if (state.permissions && state.permissions[namespace + "/" + repoName]) {
return state.permissions[namespace + "/" + repoName].entries;
}
}
export function isFetchAvailablePermissionsPending(state: object) {
return isPending(state, FETCH_AVAILABLE, 'available');
return isPending(state, FETCH_AVAILABLE, "available");
}
export function isFetchPermissionsPending(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
return isPending(state, FETCH_PERMISSIONS, namespace + '/' + repoName);
return isPending(state, FETCH_PERMISSIONS, namespace + "/" + repoName);
}
export function getFetchAvailablePermissionsFailure(state: object) {
return getFailure(state, FETCH_AVAILABLE, 'available');
return getFailure(state, FETCH_AVAILABLE, "available");
}
export function getFetchPermissionsFailure(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
return getFailure(state, FETCH_PERMISSIONS, namespace + '/' + repoName);
return getFailure(state, FETCH_PERMISSIONS, namespace + "/" + repoName);
}
export function isModifyPermissionPending(
state: object,
namespace: string,
repoName: string,
permission: Permission,
permission: Permission
) {
return isPending(
state,
MODIFY_PERMISSION,
createItemId(permission, namespace, repoName),
createItemId(permission, namespace, repoName)
);
}
@@ -598,51 +598,51 @@ export function getModifyPermissionFailure(
state: object,
namespace: string,
repoName: string,
permission: Permission,
permission: Permission
) {
return getFailure(
state,
MODIFY_PERMISSION,
createItemId(permission, namespace, repoName),
createItemId(permission, namespace, repoName)
);
}
export function hasCreatePermission(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
if (state.permissions && state.permissions[namespace + '/' + repoName])
return state.permissions[namespace + '/' + repoName].createPermission;
if (state.permissions && state.permissions[namespace + "/" + repoName])
return state.permissions[namespace + "/" + repoName].createPermission;
else return null;
}
export function isCreatePermissionPending(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
return isPending(state, CREATE_PERMISSION, namespace + '/' + repoName);
return isPending(state, CREATE_PERMISSION, namespace + "/" + repoName);
}
export function getCreatePermissionFailure(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
return getFailure(state, CREATE_PERMISSION, namespace + '/' + repoName);
return getFailure(state, CREATE_PERMISSION, namespace + "/" + repoName);
}
export function isDeletePermissionPending(
state: object,
namespace: string,
repoName: string,
permission: Permission,
permission: Permission
) {
return isPending(
state,
DELETE_PERMISSION,
createItemId(permission, namespace, repoName),
createItemId(permission, namespace, repoName)
);
}
@@ -650,23 +650,23 @@ export function getDeletePermissionFailure(
state: object,
namespace: string,
repoName: string,
permission: Permission,
permission: Permission
) {
return getFailure(
state,
DELETE_PERMISSION,
createItemId(permission, namespace, repoName),
createItemId(permission, namespace, repoName)
);
}
export function getDeletePermissionsFailure(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
const permissions =
state.permissions && state.permissions[namespace + '/' + repoName]
? state.permissions[namespace + '/' + repoName].entries
state.permissions && state.permissions[namespace + "/" + repoName]
? state.permissions[namespace + "/" + repoName].entries
: null;
if (permissions == null) return undefined;
for (let i = 0; i < permissions.length; i++) {
@@ -676,7 +676,7 @@ export function getDeletePermissionsFailure(
return getFailure(
state,
DELETE_PERMISSION,
createItemId(permissions[i], namespace, repoName),
createItemId(permissions[i], namespace, repoName)
);
}
}
@@ -686,11 +686,11 @@ export function getDeletePermissionsFailure(
export function getModifyPermissionsFailure(
state: object,
namespace: string,
repoName: string,
repoName: string
) {
const permissions =
state.permissions && state.permissions[namespace + '/' + repoName]
? state.permissions[namespace + '/' + repoName].entries
state.permissions && state.permissions[namespace + "/" + repoName]
? state.permissions[namespace + "/" + repoName].entries
: null;
if (permissions == null) return undefined;
for (let i = 0; i < permissions.length; i++) {
@@ -700,7 +700,7 @@ export function getModifyPermissionsFailure(
return getFailure(
state,
MODIFY_PERMISSION,
createItemId(permissions[i], namespace, repoName),
createItemId(permissions[i], namespace, repoName)
);
}
}
@@ -709,10 +709,10 @@ export function getModifyPermissionsFailure(
export function findVerbsForRole(
availableRepositoryRoles: RepositoryRole[],
roleName: string,
roleName: string
) {
const matchingRole = availableRepositoryRoles.find(
role => roleName === role.name,
role => roleName === role.name
);
if (matchingRole) {
return matchingRole.verbs;

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { File } from '@scm-manager/ui-types';
import React from "react";
import { File } from "@scm-manager/ui-types";
type Props = {
file: File;
@@ -8,11 +8,11 @@ type Props = {
class FileIcon extends React.Component<Props> {
render() {
const { file } = this.props;
let icon = 'file';
let icon = "file";
if (file.subRepository) {
icon = 'folder-plus';
icon = "folder-plus";
} else if (file.directory) {
icon = 'folder';
icon = "folder";
}
return <i className={`fa fa-${icon}`} />;
}

View File

@@ -1,10 +1,10 @@
import { findParent } from './FileTree';
import { findParent } from "./FileTree";
describe('find parent tests', () => {
it('should return the parent path', () => {
expect(findParent('src/main/js/')).toBe('src/main');
expect(findParent('src/main/js')).toBe('src/main');
expect(findParent('src/main')).toBe('src');
expect(findParent('src')).toBe('');
describe("find parent tests", () => {
it("should return the parent path", () => {
expect(findParent("src/main/js/")).toBe("src/main");
expect(findParent("src/main/js")).toBe("src/main");
expect(findParent("src/main")).toBe("src");
expect(findParent("src")).toBe("");
});
});

View File

@@ -1,22 +1,22 @@
import React from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { translate } from 'react-i18next';
import styled from 'styled-components';
import { binder } from '@scm-manager/ui-extensions';
import { Repository, File } from '@scm-manager/ui-types';
import React from "react";
import { compose } from "redux";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { translate } from "react-i18next";
import styled from "styled-components";
import { binder } from "@scm-manager/ui-extensions";
import { Repository, File } from "@scm-manager/ui-types";
import {
ErrorNotification,
Loading,
Notification,
} from '@scm-manager/ui-components';
Notification
} from "@scm-manager/ui-components";
import {
getFetchSourcesFailure,
isFetchSourcesPending,
getSources,
} from '../modules/sources';
import FileTreeLeaf from './FileTreeLeaf';
getSources
} from "../modules/sources";
import FileTreeLeaf from "./FileTreeLeaf";
type Props = {
loading: boolean;
@@ -37,15 +37,15 @@ const FixedWidthTh = styled.th`
`;
export function findParent(path: string) {
if (path.endsWith('/')) {
if (path.endsWith("/")) {
path = path.substring(0, path.length - 1);
}
const index = path.lastIndexOf('/');
const index = path.lastIndexOf("/");
if (index > 0) {
return path.substring(0, index);
}
return '';
return "";
}
class FileTree extends React.Component<Props> {
@@ -73,9 +73,9 @@ class FileTree extends React.Component<Props> {
if (path) {
files.push({
name: '..',
name: "..",
path: findParent(path),
directory: true,
directory: true
});
}
@@ -102,9 +102,9 @@ class FileTree extends React.Component<Props> {
if (files && files.length > 0) {
let baseUrlWithRevision = baseUrl;
if (revision) {
baseUrlWithRevision += '/' + encodeURIComponent(revision);
baseUrlWithRevision += "/" + encodeURIComponent(revision);
} else {
baseUrlWithRevision += '/' + encodeURIComponent(tree.revision);
baseUrlWithRevision += "/" + encodeURIComponent(tree.revision);
}
return (
@@ -112,17 +112,17 @@ class FileTree extends React.Component<Props> {
<thead>
<tr>
<FixedWidthTh />
<th>{t('sources.file-tree.name')}</th>
<th>{t("sources.file-tree.name")}</th>
<th className="is-hidden-mobile">
{t('sources.file-tree.length')}
{t("sources.file-tree.length")}
</th>
<th className="is-hidden-mobile">
{t('sources.file-tree.lastModified')}
{t("sources.file-tree.lastModified")}
</th>
<th className="is-hidden-mobile">
{t('sources.file-tree.description')}
{t("sources.file-tree.description")}
</th>
{binder.hasExtension('repos.sources.tree.row.right') && (
{binder.hasExtension("repos.sources.tree.row.right") && (
<th className="is-hidden-mobile" />
)}
</tr>
@@ -139,7 +139,7 @@ class FileTree extends React.Component<Props> {
</table>
);
}
return <Notification type="info">{t('sources.noSources')}</Notification>;
return <Notification type="info">{t("sources.noSources")}</Notification>;
}
}
@@ -155,11 +155,11 @@ const mapStateToProps = (state: any, ownProps: Props) => {
path,
loading,
error,
tree,
tree
};
};
export default compose(
withRouter,
connect(mapStateToProps),
)(translate('repos')(FileTree));
connect(mapStateToProps)
)(translate("repos")(FileTree));

View File

@@ -1,28 +1,28 @@
import { createLink } from './FileTreeLeaf';
import { File } from '@scm-manager/ui-types';
import { createLink } from "./FileTreeLeaf";
import { File } from "@scm-manager/ui-types";
describe('create link tests', () => {
describe("create link tests", () => {
function dir(path: string): File {
return {
name: 'dir',
name: "dir",
path: path,
directory: true,
length: 1,
revision: '1a',
revision: "1a",
_links: {},
_embedded: {
children: [],
},
children: []
}
};
}
it('should create link', () => {
expect(createLink('src', dir('main'))).toBe('src/main/');
expect(createLink('src', dir('/main'))).toBe('src/main/');
expect(createLink('src', dir('/main/'))).toBe('src/main/');
it("should create link", () => {
expect(createLink("src", dir("main"))).toBe("src/main/");
expect(createLink("src", dir("/main"))).toBe("src/main/");
expect(createLink("src", dir("/main/"))).toBe("src/main/");
});
it('should return base url if the directory path is empty', () => {
expect(createLink('src', dir(''))).toBe('src/');
it("should return base url if the directory path is empty", () => {
expect(createLink("src", dir(""))).toBe("src/");
});
});

View File

@@ -1,11 +1,11 @@
import * as React from 'react';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import styled from 'styled-components';
import { binder, ExtensionPoint } from '@scm-manager/ui-extensions';
import { File } from '@scm-manager/ui-types';
import { DateFromNow, FileSize } from '@scm-manager/ui-components';
import FileIcon from './FileIcon';
import * as React from "react";
import { Link } from "react-router-dom";
import classNames from "classnames";
import styled from "styled-components";
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
import { File } from "@scm-manager/ui-types";
import { DateFromNow, FileSize } from "@scm-manager/ui-components";
import FileIcon from "./FileIcon";
type Props = {
file: File;
@@ -20,13 +20,13 @@ export function createLink(base: string, file: File) {
let link = base;
if (file.path) {
let path = file.path;
if (path.startsWith('/')) {
if (path.startsWith("/")) {
path = path.substring(1);
}
link += '/' + path;
link += "/" + path;
}
if (!link.endsWith('/')) {
link += '/';
if (!link.endsWith("/")) {
link += "/";
}
return link;
}
@@ -61,7 +61,7 @@ export default class FileTreeLeaf extends React.Component<Props> {
render() {
const { file } = this.props;
const fileSize = file.directory ? '' : <FileSize bytes={file.length} />;
const fileSize = file.directory ? "" : <FileSize bytes={file.length} />;
return (
<tr>
@@ -73,16 +73,16 @@ export default class FileTreeLeaf extends React.Component<Props> {
<td className="is-hidden-mobile">
<DateFromNow date={file.lastModified} />
</td>
<MinWidthTd className={classNames('is-word-break', 'is-hidden-mobile')}>
<MinWidthTd className={classNames("is-word-break", "is-hidden-mobile")}>
{file.description}
</MinWidthTd>
{binder.hasExtension('repos.sources.tree.row.right') && (
{binder.hasExtension("repos.sources.tree.row.right") && (
<td className="is-hidden-mobile">
{!file.directory && (
<ExtensionPoint
name="repos.sources.tree.row.right"
props={{
file,
file
}}
renderAll={true}
/>

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { translate } from 'react-i18next';
import { File } from '@scm-manager/ui-types';
import { DownloadButton } from '@scm-manager/ui-components';
import React from "react";
import { translate } from "react-i18next";
import { File } from "@scm-manager/ui-types";
import { DownloadButton } from "@scm-manager/ui-components";
type Props = {
t: (p: string) => string;
@@ -15,11 +15,11 @@ class DownloadViewer extends React.Component<Props> {
<div className="has-text-centered">
<DownloadButton
url={file._links.self.href}
displayName={t('sources.content.downloadButton')}
displayName={t("sources.content.downloadButton")}
/>
</div>
);
}
}
export default translate('repos')(DownloadViewer);
export default translate("repos")(DownloadViewer);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { translate } from 'react-i18next';
import { ButtonAddons, Button } from '@scm-manager/ui-components';
import React from "react";
import { translate } from "react-i18next";
import { ButtonAddons, Button } from "@scm-manager/ui-components";
type Props = {
className?: string;
@@ -19,7 +19,7 @@ class FileButtonAddons extends React.Component<Props> {
};
color = (selected: boolean) => {
return selected ? 'link is-selected' : null;
return selected ? "link is-selected" : null;
};
render() {
@@ -27,7 +27,7 @@ class FileButtonAddons extends React.Component<Props> {
return (
<ButtonAddons className={className}>
<div title={t('sources.content.sourcesButton')}>
<div title={t("sources.content.sourcesButton")}>
<Button
action={this.showSources}
className="reduced"
@@ -38,7 +38,7 @@ class FileButtonAddons extends React.Component<Props> {
</span>
</Button>
</div>
<div title={t('sources.content.historyButton')}>
<div title={t("sources.content.historyButton")}>
<Button
action={this.showHistory}
className="reduced"
@@ -54,4 +54,4 @@ class FileButtonAddons extends React.Component<Props> {
}
}
export default translate('repos')(FileButtonAddons);
export default translate("repos")(FileButtonAddons);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { translate } from 'react-i18next';
import { File } from '@scm-manager/ui-types';
import React from "react";
import { translate } from "react-i18next";
import { File } from "@scm-manager/ui-types";
type Props = {
t: (p: string) => string;
@@ -20,4 +20,4 @@ class ImageViewer extends React.Component<Props> {
}
}
export default translate('repos')(ImageViewer);
export default translate("repos")(ImageViewer);

View File

@@ -1,29 +1,29 @@
import fetchMock from 'fetch-mock';
import { getContent, getLanguage } from './SourcecodeViewer';
import fetchMock from "fetch-mock";
import { getContent, getLanguage } from "./SourcecodeViewer";
describe('get content', () => {
const CONTENT_URL = '/repositories/scmadmin/TestRepo/content/testContent';
describe("get content", () => {
const CONTENT_URL = "/repositories/scmadmin/TestRepo/content/testContent";
afterEach(() => {
fetchMock.reset();
fetchMock.restore();
});
it('should return content', done => {
fetchMock.getOnce('/api/v2' + CONTENT_URL, 'This is a testContent');
it("should return content", done => {
fetchMock.getOnce("/api/v2" + CONTENT_URL, "This is a testContent");
getContent(CONTENT_URL).then(content => {
expect(content).toBe('This is a testContent');
expect(content).toBe("This is a testContent");
done();
});
});
});
describe('get correct language type', () => {
it('should return javascript', () => {
expect(getLanguage('JAVASCRIPT')).toBe('javascript');
describe("get correct language type", () => {
it("should return javascript", () => {
expect(getLanguage("JAVASCRIPT")).toBe("javascript");
});
it('should return nothing for plain text', () => {
expect(getLanguage('')).toBe('');
it("should return nothing for plain text", () => {
expect(getLanguage("")).toBe("");
});
});

View File

@@ -1,8 +1,8 @@
import React from 'react';
import { translate } from 'react-i18next';
import { apiClient, SyntaxHighlighter } from '@scm-manager/ui-components';
import { File } from '@scm-manager/ui-types';
import { ErrorNotification, Loading } from '@scm-manager/ui-components';
import React from "react";
import { translate } from "react-i18next";
import { apiClient, SyntaxHighlighter } from "@scm-manager/ui-components";
import { File } from "@scm-manager/ui-types";
import { ErrorNotification, Loading } from "@scm-manager/ui-components";
type Props = {
t: (p: string) => string;
@@ -21,8 +21,8 @@ class SourcecodeViewer extends React.Component<Props, State> {
super(props);
this.state = {
content: '',
loaded: false,
content: "",
loaded: false
};
}
@@ -34,13 +34,13 @@ class SourcecodeViewer extends React.Component<Props, State> {
this.setState({
...this.state,
error: result.error,
loaded: true,
loaded: true
});
} else {
this.setState({
...this.state,
content: result,
loaded: true,
loaded: true
});
}
})
@@ -82,9 +82,9 @@ export function getContent(url: string) {
})
.catch(err => {
return {
error: err,
error: err
};
});
}
export default translate('repos')(SourcecodeViewer);
export default translate("repos")(SourcecodeViewer);

View File

@@ -1,20 +1,20 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import classNames from 'classnames';
import styled from 'styled-components';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
import { File, Repository } from '@scm-manager/ui-types';
import React from "react";
import { connect } from "react-redux";
import { translate } from "react-i18next";
import classNames from "classnames";
import styled from "styled-components";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { File, Repository } from "@scm-manager/ui-types";
import {
DateFromNow,
ErrorNotification,
FileSize,
Icon,
} from '@scm-manager/ui-components';
import { getSources } from '../modules/sources';
import FileButtonAddons from '../components/content/FileButtonAddons';
import SourcesView from './SourcesView';
import HistoryView from './HistoryView';
Icon
} from "@scm-manager/ui-components";
import { getSources } from "../modules/sources";
import FileButtonAddons from "../components/content/FileButtonAddons";
import SourcesView from "./SourcesView";
import HistoryView from "./HistoryView";
type Props = {
loading: boolean;
@@ -59,33 +59,33 @@ class Content extends React.Component<Props, State> {
this.state = {
collapsed: true,
showHistory: false,
showHistory: false
};
}
toggleCollapse = () => {
this.setState(prevState => ({
collapsed: !prevState.collapsed,
collapsed: !prevState.collapsed
}));
};
setShowHistoryState(showHistory: boolean) {
this.setState({
...this.state,
showHistory,
showHistory
});
}
handleExtensionError = (error: Error) => {
this.setState({
errorFromExtension: error,
errorFromExtension: error
});
};
showHeader() {
const { file, revision } = this.props;
const { showHistory, collapsed } = this.state;
const icon = collapsed ? 'angle-right' : 'angle-down';
const icon = collapsed ? "angle-right" : "angle-down";
const selector = file._links.history ? (
<RightMarginFileButtonAddons
@@ -99,7 +99,7 @@ class Content extends React.Component<Props, State> {
return (
<span className="has-cursor-pointer">
<VCenteredChild className={classNames('media', 'is-flex')}>
<VCenteredChild className={classNames("media", "is-flex")}>
<div className="media-content" onClick={this.toggleCollapse}>
<RightMarginIcon name={icon} color="inherit" />
<span className="is-word-break">{file.name}</span>
@@ -111,7 +111,7 @@ class Content extends React.Component<Props, State> {
props={{
file,
revision,
handleExtensionError: this.handleExtensionError,
handleExtensionError: this.handleExtensionError
}}
renderAll={true}
/>
@@ -127,7 +127,7 @@ class Content extends React.Component<Props, State> {
const date = <DateFromNow date={file.lastModified} />;
const description = file.description ? (
<p>
{file.description.split('\n').map((item, key) => {
{file.description.split("\n").map((item, key) => {
return (
<span key={key}>
{item}
@@ -137,30 +137,30 @@ class Content extends React.Component<Props, State> {
})}
</p>
) : null;
const fileSize = file.directory ? '' : <FileSize bytes={file.length} />;
const fileSize = file.directory ? "" : <FileSize bytes={file.length} />;
if (!collapsed) {
return (
<LighterGreyBackgroundPanelBlock className="panel-block">
<LighterGreyBackgroundTable className="table">
<tbody>
<tr>
<td>{t('sources.content.path')}</td>
<td>{t("sources.content.path")}</td>
<td className="is-word-break">{file.path}</td>
</tr>
<tr>
<td>{t('sources.content.branch')}</td>
<td>{t("sources.content.branch")}</td>
<td className="is-word-break">{revision}</td>
</tr>
<tr>
<td>{t('sources.content.size')}</td>
<td>{t("sources.content.size")}</td>
<td>{fileSize}</td>
</tr>
<tr>
<td>{t('sources.content.lastModified')}</td>
<td>{t("sources.content.lastModified")}</td>
<td>{date}</td>
</tr>
<tr>
<td>{t('sources.content.description')}</td>
<td>{t("sources.content.description")}</td>
<td className="is-word-break">{description}</td>
</tr>
<ExtensionPoint
@@ -169,7 +169,7 @@ class Content extends React.Component<Props, State> {
props={{
file,
repository,
revision,
revision
}}
/>
</tbody>
@@ -217,8 +217,8 @@ const mapStateToProps = (state: any, ownProps: Props) => {
const file = getSources(state, repository, revision, path);
return {
file,
file
};
};
export default connect(mapStateToProps)(translate('repos')(Content));
export default connect(mapStateToProps)(translate("repos")(Content));

View File

@@ -1,17 +1,17 @@
import React from 'react';
import React from "react";
import {
File,
Changeset,
Repository,
PagedCollection,
} from '@scm-manager/ui-types';
PagedCollection
} from "@scm-manager/ui-types";
import {
ErrorNotification,
Loading,
StatePaginator,
ChangesetList,
} from '@scm-manager/ui-components';
import { getHistory } from './history';
ChangesetList
} from "@scm-manager/ui-components";
import { getHistory } from "./history";
type Props = {
file: File;
@@ -33,7 +33,7 @@ class HistoryView extends React.Component<Props, State> {
this.state = {
loaded: false,
page: 1,
changesets: [],
changesets: []
};
}
@@ -49,7 +49,7 @@ class HistoryView extends React.Component<Props, State> {
this.setState({
...this.state,
error: result.error,
loaded: true,
loaded: true
});
} else {
this.setState({
@@ -57,7 +57,7 @@ class HistoryView extends React.Component<Props, State> {
loaded: true,
changesets: result.changesets,
pageCollection: result.pageCollection,
page: result.pageCollection.page,
page: result.pageCollection.page
});
}
})
@@ -68,7 +68,7 @@ class HistoryView extends React.Component<Props, State> {
const { file } = this.props;
const internalPage = page - 1;
this.updateHistory(
file._links.history.href + '?page=' + internalPage.toString(),
file._links.history.href + "?page=" + internalPage.toString()
);
}

View File

@@ -1,24 +1,24 @@
import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { Branch, Repository } from '@scm-manager/ui-types';
import FileTree from '../components/FileTree';
import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { Branch, Repository } from "@scm-manager/ui-types";
import FileTree from "../components/FileTree";
import {
BranchSelector,
Breadcrumb,
ErrorNotification,
Loading,
} from '@scm-manager/ui-components';
import { translate } from 'react-i18next';
Loading
} from "@scm-manager/ui-components";
import { translate } from "react-i18next";
import {
fetchBranches,
getBranches,
getFetchBranchesFailure,
isFetchBranchesPending,
} from '../../branches/modules/branches';
import { compose } from 'redux';
import Content from './Content';
import { fetchSources, isDirectory } from '../modules/sources';
isFetchBranchesPending
} from "../../branches/modules/branches";
import { compose } from "redux";
import Content from "./Content";
import { fetchSources, isDirectory } from "../modules/sources";
type Props = {
repository: Repository;
@@ -50,7 +50,7 @@ class Sources extends React.Component<Props, State> {
super(props);
this.state = {
selectedBranch: null,
selectedBranch: null
};
}
@@ -60,7 +60,7 @@ class Sources extends React.Component<Props, State> {
repository,
revision,
path,
fetchSources,
fetchSources
} = this.props;
fetchBranches(repository);
@@ -99,7 +99,7 @@ class Sources extends React.Component<Props, State> {
let url;
if (branch) {
this.setState({
selectedBranch: branch,
selectedBranch: branch
});
if (path) {
url = `${baseUrl}/${encodeURIComponent(branch.name)}/${path}`;
@@ -108,7 +108,7 @@ class Sources extends React.Component<Props, State> {
}
} else {
this.setState({
selectedBranch: null,
selectedBranch: null
});
url = `${baseUrl}/`;
}
@@ -123,7 +123,7 @@ class Sources extends React.Component<Props, State> {
error,
revision,
path,
currentFileIsDirectory,
currentFileIsDirectory
} = this.props;
if (error) {
@@ -163,7 +163,7 @@ class Sources extends React.Component<Props, State> {
<BranchSelector
branches={branches}
selectedBranch={revision}
label={t('changesets.branchSelectorLabel')}
label={t("changesets.branchSelectorLabel")}
selected={(b: Branch) => {
this.branchSelected(b);
}}
@@ -215,7 +215,7 @@ const mapStateToProps = (state, ownProps) => {
loading,
error,
branches,
currentFileIsDirectory,
currentFileIsDirectory
};
};
@@ -226,15 +226,15 @@ const mapDispatchToProps = dispatch => {
},
fetchSources: (repository: Repository, revision: string, path: string) => {
dispatch(fetchSources(repository, revision, path));
},
}
};
};
export default compose(
translate('repos'),
translate("repos"),
withRouter,
connect(
mapStateToProps,
mapDispatchToProps,
),
mapDispatchToProps
)
)(Sources);

View File

@@ -1,12 +1,12 @@
import React from 'react';
import React from "react";
import SourcecodeViewer from '../components/content/SourcecodeViewer';
import ImageViewer from '../components/content/ImageViewer';
import DownloadViewer from '../components/content/DownloadViewer';
import { ExtensionPoint } from '@scm-manager/ui-extensions';
import { getContentType } from './contentType';
import { File, Repository } from '@scm-manager/ui-types';
import { ErrorNotification, Loading } from '@scm-manager/ui-components';
import SourcecodeViewer from "../components/content/SourcecodeViewer";
import ImageViewer from "../components/content/ImageViewer";
import DownloadViewer from "../components/content/DownloadViewer";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import { getContentType } from "./contentType";
import { File, Repository } from "@scm-manager/ui-types";
import { ErrorNotification, Loading } from "@scm-manager/ui-components";
type Props = {
repository: Repository;
@@ -27,9 +27,9 @@ class SourcesView extends React.Component<Props, State> {
super(props);
this.state = {
contentType: '',
language: '',
loaded: false,
contentType: "",
language: "",
loaded: false
};
}
@@ -41,14 +41,14 @@ class SourcesView extends React.Component<Props, State> {
this.setState({
...this.state,
error: result.error,
loaded: true,
loaded: true
});
} else {
this.setState({
...this.state,
contentType: result.type,
language: result.language,
loaded: true,
loaded: true
});
}
})
@@ -58,11 +58,11 @@ class SourcesView extends React.Component<Props, State> {
showSources() {
const { file, revision } = this.props;
const { contentType, language } = this.state;
if (contentType.startsWith('image/')) {
if (contentType.startsWith("image/")) {
return <ImageViewer file={file} />;
} else if (language) {
return <SourcecodeViewer file={file} language={language} />;
} else if (contentType.startsWith('text/')) {
} else if (contentType.startsWith("text/")) {
return <SourcecodeViewer file={file} language="none" />;
} else {
return (
@@ -71,7 +71,7 @@ class SourcesView extends React.Component<Props, State> {
props={{
file,
contentType,
revision,
revision
}}
>
<DownloadViewer file={file} />

View File

@@ -1,27 +1,27 @@
import fetchMock from 'fetch-mock';
import { getContentType } from './contentType';
import fetchMock from "fetch-mock";
import { getContentType } from "./contentType";
describe('get content type', () => {
const CONTENT_URL = '/repositories/scmadmin/TestRepo/content/testContent';
describe("get content type", () => {
const CONTENT_URL = "/repositories/scmadmin/TestRepo/content/testContent";
afterEach(() => {
fetchMock.reset();
fetchMock.restore();
});
it('should return content', done => {
it("should return content", done => {
let headers = {
'Content-Type': 'application/text',
'X-Programming-Language': 'JAVA',
"Content-Type": "application/text",
"X-Programming-Language": "JAVA"
};
fetchMock.head('/api/v2' + CONTENT_URL, {
headers,
fetchMock.head("/api/v2" + CONTENT_URL, {
headers
});
getContentType(CONTENT_URL).then(content => {
expect(content.type).toBe('application/text');
expect(content.language).toBe('JAVA');
expect(content.type).toBe("application/text");
expect(content.language).toBe("JAVA");
done();
});
});

View File

@@ -1,17 +1,17 @@
import { apiClient } from '@scm-manager/ui-components';
import { apiClient } from "@scm-manager/ui-components";
export function getContentType(url: string) {
return apiClient
.head(url)
.then(response => {
return {
type: response.headers.get('Content-Type'),
language: response.headers.get('X-Programming-Language'),
type: response.headers.get("Content-Type"),
language: response.headers.get("X-Programming-Language")
};
})
.catch(err => {
return {
error: err,
error: err
};
});
}

View File

@@ -1,8 +1,8 @@
import fetchMock from 'fetch-mock';
import { getHistory } from './history';
import fetchMock from "fetch-mock";
import { getHistory } from "./history";
describe('get content type', () => {
const FILE_URL = '/repositories/scmadmin/TestRepo/history/file';
describe("get content type", () => {
const FILE_URL = "/repositories/scmadmin/TestRepo/history/file";
afterEach(() => {
fetchMock.reset();
@@ -14,32 +14,32 @@ describe('get content type', () => {
pageTotal: 10,
_links: {
self: {
href: '/repositories/scmadmin/TestRepo/history/file?page=0&pageSize=10',
href: "/repositories/scmadmin/TestRepo/history/file?page=0&pageSize=10"
},
first: {
href: '/repositories/scmadmin/TestRepo/history/file?page=0&pageSize=10',
href: "/repositories/scmadmin/TestRepo/history/file?page=0&pageSize=10"
},
next: {
href: '/repositories/scmadmin/TestRepo/history/file?page=1&pageSize=10',
href: "/repositories/scmadmin/TestRepo/history/file?page=1&pageSize=10"
},
last: {
href: '/repositories/scmadmin/TestRepo/history/file?page=9&pageSize=10',
},
href: "/repositories/scmadmin/TestRepo/history/file?page=9&pageSize=10"
}
},
_embedded: {
changesets: [
{
id: '1234',
id: "1234"
},
{
id: '2345',
},
],
},
id: "2345"
}
]
}
};
it('should return history', done => {
fetchMock.get('/api/v2' + FILE_URL, history);
it("should return history", done => {
fetchMock.get("/api/v2" + FILE_URL, history);
getHistory(FILE_URL).then(content => {
expect(content.changesets).toEqual(history._embedded.changesets);

View File

@@ -1,4 +1,4 @@
import { apiClient } from '@scm-manager/ui-components';
import { apiClient } from "@scm-manager/ui-components";
export function getHistory(url: string) {
return apiClient
@@ -11,13 +11,13 @@ export function getHistory(url: string) {
_embedded: result._embedded,
_links: result._links,
page: result.page,
pageTotal: result.pageTotal,
},
pageTotal: result.pageTotal
}
};
})
.catch(err => {
return {
error: err,
error: err
};
});
}

View File

@@ -1,7 +1,7 @@
import { Repository, File } from '@scm-manager/ui-types';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock from 'fetch-mock';
import { Repository, File } from "@scm-manager/ui-types";
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import {
FETCH_SOURCES,
FETCH_SOURCES_FAILURE,
@@ -13,103 +13,103 @@ import {
default as reducer,
getSources,
fetchSourcesSuccess,
isDirectory,
} from './sources';
isDirectory
} from "./sources";
const sourcesUrl =
'http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/';
"http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/";
const repository: Repository = {
name: 'core',
namespace: 'scm',
type: 'git',
name: "core",
namespace: "scm",
type: "git",
_links: {
sources: {
href: sourcesUrl,
},
},
href: sourcesUrl
}
}
};
const collection = {
name: 'src',
path: 'src',
name: "src",
path: "src",
directory: true,
description: 'foo',
description: "foo",
length: 176,
revision: '76aae4bb4ceacf0e88938eb5b6832738b7d537b4',
revision: "76aae4bb4ceacf0e88938eb5b6832738b7d537b4",
subRepository: undefined,
_links: {
self: {
href:
'http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/',
},
"http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/"
}
},
_embedded: {
children: [
{
name: 'src',
path: 'src',
name: "src",
path: "src",
directory: true,
description: '',
description: "",
length: 176,
revision: '76aae4bb4ceacf0e88938eb5b6832738b7d537b4',
lastModified: '',
revision: "76aae4bb4ceacf0e88938eb5b6832738b7d537b4",
lastModified: "",
subRepository: undefined,
_links: {
self: {
href:
'http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/src',
},
"http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/src"
}
},
_embedded: {
children: [],
},
children: []
}
},
{
name: 'package.json',
path: 'package.json',
name: "package.json",
path: "package.json",
directory: false,
description: 'bump version',
description: "bump version",
length: 780,
revision: '76aae4bb4ceacf0e88938eb5b6832738b7d537b4',
lastModified: '2017-07-31T11:17:19Z',
revision: "76aae4bb4ceacf0e88938eb5b6832738b7d537b4",
lastModified: "2017-07-31T11:17:19Z",
subRepository: undefined,
_links: {
self: {
href:
'http://localhost:8081/scm/rest/api/v2/repositories/scm/core/content/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/package.json',
"http://localhost:8081/scm/rest/api/v2/repositories/scm/core/content/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/package.json"
},
history: {
href:
'http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/history/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/package.json',
},
"http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/history/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/package.json"
}
},
_embedded: {
children: [],
},
},
],
},
children: []
}
}
]
}
};
const noDirectory: File = {
name: 'src',
path: 'src',
name: "src",
path: "src",
directory: true,
length: 176,
revision: 'abc',
revision: "abc",
_links: {
self: {
href:
'http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/src',
},
"http://localhost:8081/scm/rest/api/v2/repositories/scm/core/sources/76aae4bb4ceacf0e88938eb5b6832738b7d537b4/src"
}
},
_embedded: {
children: [],
},
children: []
}
};
describe('sources fetch', () => {
describe("sources fetch", () => {
const mockStore = configureMockStore([thunk]);
afterEach(() => {
@@ -117,162 +117,162 @@ describe('sources fetch', () => {
fetchMock.restore();
});
it('should fetch the sources of the repository', () => {
it("should fetch the sources of the repository", () => {
fetchMock.getOnce(sourcesUrl, collection);
const expectedActions = [
{
type: FETCH_SOURCES_PENDING,
itemId: 'scm/core/_/',
itemId: "scm/core/_/"
},
{
type: FETCH_SOURCES_SUCCESS,
itemId: 'scm/core/_/',
payload: collection,
},
itemId: "scm/core/_/",
payload: collection
}
];
const store = mockStore({});
return store.dispatch(fetchSources(repository, '', '')).then(() => {
return store.dispatch(fetchSources(repository, "", "")).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
it('should fetch the sources of the repository with the given revision and path', () => {
fetchMock.getOnce(sourcesUrl + 'abc/src', collection);
it("should fetch the sources of the repository with the given revision and path", () => {
fetchMock.getOnce(sourcesUrl + "abc/src", collection);
const expectedActions = [
{
type: FETCH_SOURCES_PENDING,
itemId: 'scm/core/abc/src',
itemId: "scm/core/abc/src"
},
{
type: FETCH_SOURCES_SUCCESS,
itemId: 'scm/core/abc/src',
payload: collection,
},
itemId: "scm/core/abc/src",
payload: collection
}
];
const store = mockStore({});
return store.dispatch(fetchSources(repository, 'abc', 'src')).then(() => {
return store.dispatch(fetchSources(repository, "abc", "src")).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
it('should dispatch FETCH_SOURCES_FAILURE on server error', () => {
it("should dispatch FETCH_SOURCES_FAILURE on server error", () => {
fetchMock.getOnce(sourcesUrl, {
status: 500,
status: 500
});
const store = mockStore({});
return store.dispatch(fetchSources(repository, '', '')).then(() => {
return store.dispatch(fetchSources(repository, "", "")).then(() => {
const actions = store.getActions();
expect(actions[0].type).toBe(FETCH_SOURCES_PENDING);
expect(actions[1].type).toBe(FETCH_SOURCES_FAILURE);
expect(actions[1].itemId).toBe('scm/core/_/');
expect(actions[1].itemId).toBe("scm/core/_/");
expect(actions[1].payload).toBeDefined();
});
});
});
describe('reducer tests', () => {
it('should return unmodified state on unknown action', () => {
describe("reducer tests", () => {
it("should return unmodified state on unknown action", () => {
const state = {};
expect(reducer(state)).toBe(state);
});
it('should store the collection, without revision and path', () => {
it("should store the collection, without revision and path", () => {
const expectedState = {
'scm/core/_/': collection,
"scm/core/_/": collection
};
expect(
reducer({}, fetchSourcesSuccess(repository, '', '', collection)),
reducer({}, fetchSourcesSuccess(repository, "", "", collection))
).toEqual(expectedState);
});
it('should store the collection, with revision and path', () => {
it("should store the collection, with revision and path", () => {
const expectedState = {
'scm/core/abc/src/main': collection,
"scm/core/abc/src/main": collection
};
expect(
reducer(
{},
fetchSourcesSuccess(repository, 'abc', 'src/main', collection),
),
fetchSourcesSuccess(repository, "abc", "src/main", collection)
)
).toEqual(expectedState);
});
});
describe('selector tests', () => {
it('should return false if it is no directory', () => {
describe("selector tests", () => {
it("should return false if it is no directory", () => {
const state = {
sources: {
'scm/core/abc/src/main/package.json': {
noDirectory,
},
},
"scm/core/abc/src/main/package.json": {
noDirectory
}
}
};
expect(
isDirectory(state, repository, 'abc', 'src/main/package.json'),
isDirectory(state, repository, "abc", "src/main/package.json")
).toBeFalsy();
});
it('should return true if it is directory', () => {
it("should return true if it is directory", () => {
const state = {
sources: {
'scm/core/abc/src': noDirectory,
},
"scm/core/abc/src": noDirectory
}
};
expect(isDirectory(state, repository, 'abc', 'src')).toBe(true);
expect(isDirectory(state, repository, "abc", "src")).toBe(true);
});
it('should return null', () => {
expect(getSources({}, repository, '', '')).toBeFalsy();
it("should return null", () => {
expect(getSources({}, repository, "", "")).toBeFalsy();
});
it('should return the source collection without revision and path', () => {
it("should return the source collection without revision and path", () => {
const state = {
sources: {
'scm/core/_/': collection,
},
"scm/core/_/": collection
}
};
expect(getSources(state, repository, '', '')).toBe(collection);
expect(getSources(state, repository, "", "")).toBe(collection);
});
it('should return the source collection with revision and path', () => {
it("should return the source collection with revision and path", () => {
const state = {
sources: {
'scm/core/abc/src/main': collection,
},
"scm/core/abc/src/main": collection
}
};
expect(getSources(state, repository, 'abc', 'src/main')).toBe(collection);
expect(getSources(state, repository, "abc", "src/main")).toBe(collection);
});
it('should return true, when fetch sources is pending', () => {
it("should return true, when fetch sources is pending", () => {
const state = {
pending: {
[FETCH_SOURCES + '/scm/core/_/']: true,
},
[FETCH_SOURCES + "/scm/core/_/"]: true
}
};
expect(isFetchSourcesPending(state, repository, '', '')).toEqual(true);
expect(isFetchSourcesPending(state, repository, "", "")).toEqual(true);
});
it('should return false, when fetch sources is not pending', () => {
expect(isFetchSourcesPending({}, repository, '', '')).toEqual(false);
it("should return false, when fetch sources is not pending", () => {
expect(isFetchSourcesPending({}, repository, "", "")).toEqual(false);
});
const error = new Error('incredible error from hell');
const error = new Error("incredible error from hell");
it('should return error when fetch sources did fail', () => {
it("should return error when fetch sources did fail", () => {
const state = {
failure: {
[FETCH_SOURCES + '/scm/core/_/']: error,
},
[FETCH_SOURCES + "/scm/core/_/"]: error
}
};
expect(getFetchSourcesFailure(state, repository, '', '')).toEqual(error);
expect(getFetchSourcesFailure(state, repository, "", "")).toEqual(error);
});
it('should return undefined when fetch sources did not fail', () => {
expect(getFetchSourcesFailure({}, repository, '', '')).toBe(undefined);
it("should return undefined when fetch sources did not fail", () => {
expect(getFetchSourcesFailure({}, repository, "", "")).toBe(undefined);
});
});

View File

@@ -1,10 +1,10 @@
import * as types from '../../../modules/types';
import { Repository, File, Action } from '@scm-manager/ui-types';
import { apiClient } from '@scm-manager/ui-components';
import { isPending } from '../../../modules/pending';
import { getFailure } from '../../../modules/failure';
import * as types from "../../../modules/types";
import { Repository, File, Action } from "@scm-manager/ui-types";
import { apiClient } from "@scm-manager/ui-components";
import { isPending } from "../../../modules/pending";
import { getFailure } from "../../../modules/failure";
export const FETCH_SOURCES = 'scm/repos/FETCH_SOURCES';
export const FETCH_SOURCES = "scm/repos/FETCH_SOURCES";
export const FETCH_SOURCES_PENDING = `${FETCH_SOURCES}_${types.PENDING_SUFFIX}`;
export const FETCH_SOURCES_SUCCESS = `${FETCH_SOURCES}_${types.SUCCESS_SUFFIX}`;
export const FETCH_SOURCES_FAILURE = `${FETCH_SOURCES}_${types.FAILURE_SUFFIX}`;
@@ -12,7 +12,7 @@ export const FETCH_SOURCES_FAILURE = `${FETCH_SOURCES}_${types.FAILURE_SUFFIX}`;
export function fetchSources(
repository: Repository,
revision: string,
path: string,
path: string
) {
return function(dispatch: any) {
dispatch(fetchSourcesPending(repository, revision, path));
@@ -35,18 +35,18 @@ function createUrl(repository: Repository, revision: string, path: string) {
}
// TODO handle trailing slash
const pathDefined = path ? path : '';
const pathDefined = path ? path : "";
return `${base}${encodeURIComponent(revision)}/${pathDefined}`;
}
export function fetchSourcesPending(
repository: Repository,
revision: string,
path: string,
path: string
): Action {
return {
type: FETCH_SOURCES_PENDING,
itemId: createItemId(repository, revision, path),
itemId: createItemId(repository, revision, path)
};
}
@@ -54,12 +54,12 @@ export function fetchSourcesSuccess(
repository: Repository,
revision: string,
path: string,
sources: File,
sources: File
) {
return {
type: FETCH_SOURCES_SUCCESS,
payload: sources,
itemId: createItemId(repository, revision, path),
itemId: createItemId(repository, revision, path)
};
}
@@ -67,18 +67,18 @@ export function fetchSourcesFailure(
repository: Repository,
revision: string,
path: string,
error: Error,
error: Error
): Action {
return {
type: FETCH_SOURCES_FAILURE,
payload: error,
itemId: createItemId(repository, revision, path),
itemId: createItemId(repository, revision, path)
};
}
function createItemId(repository: Repository, revision: string, path: string) {
const revPart = revision ? revision : '_';
const pathPart = path ? path : '';
const revPart = revision ? revision : "_";
const pathPart = path ? path : "";
return `${repository.namespace}/${repository.name}/${revPart}/${pathPart}`;
}
@@ -87,13 +87,13 @@ function createItemId(repository: Repository, revision: string, path: string) {
export default function reducer(
state: any = {},
action: Action = {
type: 'UNKNOWN',
},
type: "UNKNOWN"
}
): any {
if (action.itemId && action.type === FETCH_SOURCES_SUCCESS) {
return {
...state,
[action.itemId]: action.payload,
[action.itemId]: action.payload
};
}
return state;
@@ -105,7 +105,7 @@ export function isDirectory(
state: any,
repository: Repository,
revision: string,
path: string,
path: string
): boolean {
const currentFile = getSources(state, repository, revision, path);
if (currentFile && !currentFile.directory) {
@@ -119,7 +119,7 @@ export function getSources(
state: any,
repository: Repository,
revision: string,
path: string,
path: string
): File | null | undefined {
if (state.sources) {
return state.sources[createItemId(repository, revision, path)];
@@ -131,12 +131,12 @@ export function isFetchSourcesPending(
state: any,
repository: Repository,
revision: string,
path: string,
path: string
): boolean {
return isPending(
state,
FETCH_SOURCES,
createItemId(repository, revision, path),
createItemId(repository, revision, path)
);
}
@@ -144,11 +144,11 @@ export function getFetchSourcesFailure(
state: any,
repository: Repository,
revision: string,
path: string,
path: string
): Error | null | undefined {
return getFailure(
state,
FETCH_SOURCES,
createItemId(repository, revision, path),
createItemId(repository, revision, path)
);
}