mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-01 19:15:52 +01:00
finish delete implementation and restructure components
This commit is contained in:
@@ -28,5 +28,14 @@
|
|||||||
},
|
},
|
||||||
"repository-form": {
|
"repository-form": {
|
||||||
"submit": "Speichern"
|
"submit": "Speichern"
|
||||||
|
},
|
||||||
|
"delete-nav-action": {
|
||||||
|
"label": "Delete",
|
||||||
|
"confirm-alert": {
|
||||||
|
"title": "Delete repository",
|
||||||
|
"message": "Do you really want to delete the repository?",
|
||||||
|
"submit": "Yes",
|
||||||
|
"cancel": "No"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
scm-ui/src/repos/components/DeleteNavAction.js
Normal file
59
scm-ui/src/repos/components/DeleteNavAction.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import { confirmAlert } from "../../components/modals/ConfirmAlert";
|
||||||
|
import { NavAction } from "../../components/navigation";
|
||||||
|
import type { Repository } from "../types/Repositories";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
repository: Repository,
|
||||||
|
confirmDialog?: boolean,
|
||||||
|
delete: Repository => void,
|
||||||
|
|
||||||
|
// context props
|
||||||
|
t: string => string
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeleteNavAction extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
confirmDialog: true
|
||||||
|
};
|
||||||
|
|
||||||
|
delete = () => {
|
||||||
|
this.props.delete(this.props.repository);
|
||||||
|
};
|
||||||
|
|
||||||
|
confirmDelete = () => {
|
||||||
|
const { t } = this.props;
|
||||||
|
confirmAlert({
|
||||||
|
title: t("delete-nav-action.confirm-alert.title"),
|
||||||
|
message: t("delete-nav-action.confirm-alert.message"),
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: t("delete-nav-action.confirm-alert.submit"),
|
||||||
|
onClick: () => this.delete()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("delete-nav-action.confirm-alert.cancel"),
|
||||||
|
onClick: () => null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
isDeletable = () => {
|
||||||
|
return this.props.repository._links.delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { confirmDialog, t } = this.props;
|
||||||
|
const action = confirmDialog ? this.confirmDelete : this.delete();
|
||||||
|
|
||||||
|
if (!this.isDeletable()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return <NavAction label={t("delete-nav-action.label")} action={action} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("repos")(DeleteNavAction);
|
||||||
79
scm-ui/src/repos/components/DeleteNavAction.test.js
Normal file
79
scm-ui/src/repos/components/DeleteNavAction.test.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { mount, shallow } from "enzyme";
|
||||||
|
import "../../tests/enzyme";
|
||||||
|
import "../../tests/i18n";
|
||||||
|
import DeleteNavAction from "./DeleteNavAction";
|
||||||
|
|
||||||
|
import { confirmAlert } from "../../components/modals/ConfirmAlert";
|
||||||
|
jest.mock("../../components/modals/ConfirmAlert");
|
||||||
|
|
||||||
|
describe("DeleteNavAction", () => {
|
||||||
|
it("should render nothing, if the delete link is missing", () => {
|
||||||
|
const repository = {
|
||||||
|
_links: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const navLink = shallow(
|
||||||
|
<DeleteNavAction repository={repository} delete={() => {}} />
|
||||||
|
);
|
||||||
|
expect(navLink.text()).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render the navLink", () => {
|
||||||
|
const repository = {
|
||||||
|
_links: {
|
||||||
|
delete: {
|
||||||
|
href: "/repositories"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const navLink = mount(
|
||||||
|
<DeleteNavAction repository={repository} delete={() => {}} />
|
||||||
|
);
|
||||||
|
expect(navLink.text()).not.toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should open the confirm dialog on navLink click", () => {
|
||||||
|
const repository = {
|
||||||
|
_links: {
|
||||||
|
delete: {
|
||||||
|
href: "/repositorys"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const navLink = mount(
|
||||||
|
<DeleteNavAction repository={repository} delete={() => {}} />
|
||||||
|
);
|
||||||
|
navLink.find("a").simulate("click");
|
||||||
|
|
||||||
|
expect(confirmAlert.mock.calls.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call the delete repository function with delete url", () => {
|
||||||
|
const repository = {
|
||||||
|
_links: {
|
||||||
|
delete: {
|
||||||
|
href: "/repos"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let calledUrl = null;
|
||||||
|
function capture(repository) {
|
||||||
|
calledUrl = repository._links.delete.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
const navLink = mount(
|
||||||
|
<DeleteNavAction
|
||||||
|
repository={repository}
|
||||||
|
confirmDialog={false}
|
||||||
|
delete={capture}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
navLink.find("a").simulate("click");
|
||||||
|
|
||||||
|
expect(calledUrl).toBe("/repos");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { InputField, Select } from "../../components/forms";
|
import { InputField, Select } from "../../../components/forms/index";
|
||||||
import { SubmitButton } from "../../components/buttons";
|
import { SubmitButton } from "../../../components/buttons/index";
|
||||||
import type { Repository } from "../types/Repositories";
|
import type { Repository } from "../../types/Repositories";
|
||||||
import * as validator from "./repositoryValidation";
|
import * as validator from "./repositoryValidation";
|
||||||
import type { RepositoryType } from "../types/RepositoryTypes";
|
import type { RepositoryType } from "../../types/RepositoryTypes";
|
||||||
import Textarea from "../../components/forms/Textarea";
|
import Textarea from "../../../components/forms/Textarea";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
submitForm: Repository => void,
|
submitForm: Repository => void,
|
||||||
2
scm-ui/src/repos/components/form/index.js
Normal file
2
scm-ui/src/repos/components/form/index.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import RepositoryForm from "./RepositoryForm";
|
||||||
|
export default RepositoryForm;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import * as generalValidator from "../../components/validation";
|
import * as generalValidator from "../../../components/validation";
|
||||||
|
|
||||||
export const isNameValid = (name: string) => {
|
export const isNameValid = (name: string) => {
|
||||||
return generalValidator.isNameValid(name);
|
return generalValidator.isNameValid(name);
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import type { Repository } from "../types/Repositories";
|
import type { Repository } from "../../types/Repositories";
|
||||||
import DateFromNow from "../../components/DateFromNow";
|
import DateFromNow from "../../../components/DateFromNow";
|
||||||
import RepositoryEntryLink from "./RepositoryEntryLink";
|
import RepositoryEntryLink from "./RepositoryEntryLink";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import icon from "../../images/blib.jpg";
|
import icon from "../../../images/blib.jpg";
|
||||||
|
|
||||||
// TODO we need a variable or something central for the hover
|
// TODO we need a variable or something central for the hover
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { RepositoryGroup } from "../types/Repositories";
|
import type { RepositoryGroup } from "../../types/Repositories";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import RepositoryEntry from "./RepositoryEntry";
|
import RepositoryEntry from "./RepositoryEntry";
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import type { Repository } from "../types/Repositories";
|
import type { Repository } from "../../types/Repositories";
|
||||||
|
|
||||||
import groupByNamespace from "./groupByNamespace";
|
import groupByNamespace from "./groupByNamespace";
|
||||||
import RepositoryGroupEntry from "./RepositoryGroupEntry";
|
import RepositoryGroupEntry from "./RepositoryGroupEntry";
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import type { Repository, RepositoryGroup } from "../types/Repositories";
|
import type { Repository, RepositoryGroup } from "../../types/Repositories";
|
||||||
|
|
||||||
export default function groupByNamespace(
|
export default function groupByNamespace(
|
||||||
repositories: Repository[]
|
repositories: Repository[]
|
||||||
2
scm-ui/src/repos/components/list/index.js
Normal file
2
scm-ui/src/repos/components/list/index.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import RepositoryList from "./RepositoryList";
|
||||||
|
export default RepositoryList;
|
||||||
@@ -3,7 +3,7 @@ import React from "react";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { Page } from "../../components/layout";
|
import { Page } from "../../components/layout";
|
||||||
import RepositoryForm from "../components/RepositoryForm";
|
import RepositoryForm from "../components/form";
|
||||||
import type { RepositoryType } from "../types/RepositoryTypes";
|
import type { RepositoryType } from "../types/RepositoryTypes";
|
||||||
import {
|
import {
|
||||||
fetchRepositoryTypesIfNeeded,
|
fetchRepositoryTypesIfNeeded,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
} from "../modules/repos";
|
} from "../modules/repos";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { Page } from "../../components/layout";
|
import { Page } from "../../components/layout";
|
||||||
import RepositoryList from "../components/RepositoryList";
|
import RepositoryList from "../components/list";
|
||||||
import Paginator from "../../components/Paginator";
|
import Paginator from "../../components/Paginator";
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from "react-router-dom";
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
|
deleteRepo,
|
||||||
fetchRepo,
|
fetchRepo,
|
||||||
getFetchRepoFailure,
|
getFetchRepoFailure,
|
||||||
getRepository,
|
getRepository,
|
||||||
@@ -15,6 +16,9 @@ import ErrorPage from "../../components/ErrorPage";
|
|||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { Navigation, NavLink, Section } from "../../components/navigation";
|
import { Navigation, NavLink, Section } from "../../components/navigation";
|
||||||
import RepositoryDetails from "../components/RepositoryDetails";
|
import RepositoryDetails from "../components/RepositoryDetails";
|
||||||
|
import DeleteNavAction from "../components/DeleteNavAction";
|
||||||
|
|
||||||
|
import type { History } from "history";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
namespace: string,
|
namespace: string,
|
||||||
@@ -25,9 +29,11 @@ type Props = {
|
|||||||
|
|
||||||
// dispatch functions
|
// dispatch functions
|
||||||
fetchRepo: (namespace: string, name: string) => void,
|
fetchRepo: (namespace: string, name: string) => void,
|
||||||
|
deleteRepo: (repository: Repository, () => void) => void,
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
t: string => string,
|
t: string => string,
|
||||||
|
history: History,
|
||||||
match: any
|
match: any
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,6 +55,14 @@ class RepositoryRoot extends React.Component<Props> {
|
|||||||
return this.stripEndingSlash(this.props.match.url);
|
return this.stripEndingSlash(this.props.match.url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
deleted = () => {
|
||||||
|
this.props.history.push("/repos");
|
||||||
|
};
|
||||||
|
|
||||||
|
delete = (repository: Repository) => {
|
||||||
|
this.props.deleteRepo(repository, this.deleted);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loading, error, repository, t } = this.props;
|
const { loading, error, repository, t } = this.props;
|
||||||
|
|
||||||
@@ -81,6 +95,7 @@ class RepositoryRoot extends React.Component<Props> {
|
|||||||
<div className="column">
|
<div className="column">
|
||||||
<Navigation>
|
<Navigation>
|
||||||
<Section label={t("repository-root.actions-label")}>
|
<Section label={t("repository-root.actions-label")}>
|
||||||
|
<DeleteNavAction repository={repository} delete={this.delete} />
|
||||||
<NavLink to="/repos" label={t("repository-root.back-label")} />
|
<NavLink to="/repos" label={t("repository-root.back-label")} />
|
||||||
</Section>
|
</Section>
|
||||||
</Navigation>
|
</Navigation>
|
||||||
@@ -109,6 +124,9 @@ const mapDispatchToProps = dispatch => {
|
|||||||
return {
|
return {
|
||||||
fetchRepo: (namespace: string, name: string) => {
|
fetchRepo: (namespace: string, name: string) => {
|
||||||
dispatch(fetchRepo(namespace, name));
|
dispatch(fetchRepo(namespace, name));
|
||||||
|
},
|
||||||
|
deleteRepo: (repository: Repository, callback: () => void) => {
|
||||||
|
dispatch(deleteRepo(repository, callback));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user