From ffbfdff52e8888f7d14ce3b0353b7736f4620d0b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 6 Aug 2018 10:08:28 +0200 Subject: [PATCH] finish delete implementation and restructure components --- scm-ui/public/locales/en/repos.json | 9 +++ .../src/repos/components/DeleteNavAction.js | 59 ++++++++++++++ .../repos/components/DeleteNavAction.test.js | 79 +++++++++++++++++++ .../components/{ => form}/RepositoryForm.js | 10 +-- scm-ui/src/repos/components/form/index.js | 2 + .../{ => form}/repositoryValidation.js | 2 +- .../{ => form}/repositoryValidation.test.js | 0 .../components/{ => list}/RepositoryEntry.js | 6 +- .../{ => list}/RepositoryEntryLink.js | 0 .../{ => list}/RepositoryGroupEntry.js | 2 +- .../components/{ => list}/RepositoryList.js | 2 +- .../components/{ => list}/groupByNamespace.js | 2 +- .../{ => list}/groupByNamespace.test.js | 0 scm-ui/src/repos/components/list/index.js | 2 + scm-ui/src/repos/containers/Create.js | 2 +- scm-ui/src/repos/containers/Overview.js | 2 +- scm-ui/src/repos/containers/RepositoryRoot.js | 18 +++++ 17 files changed, 183 insertions(+), 14 deletions(-) create mode 100644 scm-ui/src/repos/components/DeleteNavAction.js create mode 100644 scm-ui/src/repos/components/DeleteNavAction.test.js rename scm-ui/src/repos/components/{ => form}/RepositoryForm.js (92%) create mode 100644 scm-ui/src/repos/components/form/index.js rename scm-ui/src/repos/components/{ => form}/repositoryValidation.js (75%) rename scm-ui/src/repos/components/{ => form}/repositoryValidation.test.js (100%) rename scm-ui/src/repos/components/{ => list}/RepositoryEntry.js (94%) rename scm-ui/src/repos/components/{ => list}/RepositoryEntryLink.js (100%) rename scm-ui/src/repos/components/{ => list}/RepositoryGroupEntry.js (95%) rename scm-ui/src/repos/components/{ => list}/RepositoryList.js (90%) rename scm-ui/src/repos/components/{ => list}/groupByNamespace.js (91%) rename scm-ui/src/repos/components/{ => list}/groupByNamespace.test.js (100%) create mode 100644 scm-ui/src/repos/components/list/index.js diff --git a/scm-ui/public/locales/en/repos.json b/scm-ui/public/locales/en/repos.json index 76deba1c8a..e28ea3754c 100644 --- a/scm-ui/public/locales/en/repos.json +++ b/scm-ui/public/locales/en/repos.json @@ -28,5 +28,14 @@ }, "repository-form": { "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" + } } } diff --git a/scm-ui/src/repos/components/DeleteNavAction.js b/scm-ui/src/repos/components/DeleteNavAction.js new file mode 100644 index 0000000000..0fd554f045 --- /dev/null +++ b/scm-ui/src/repos/components/DeleteNavAction.js @@ -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 { + 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 ; + } +} + +export default translate("repos")(DeleteNavAction); diff --git a/scm-ui/src/repos/components/DeleteNavAction.test.js b/scm-ui/src/repos/components/DeleteNavAction.test.js new file mode 100644 index 0000000000..635f84c7a9 --- /dev/null +++ b/scm-ui/src/repos/components/DeleteNavAction.test.js @@ -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( + {}} /> + ); + expect(navLink.text()).toBe(""); + }); + + it("should render the navLink", () => { + const repository = { + _links: { + delete: { + href: "/repositories" + } + } + }; + + const navLink = mount( + {}} /> + ); + expect(navLink.text()).not.toBe(""); + }); + + it("should open the confirm dialog on navLink click", () => { + const repository = { + _links: { + delete: { + href: "/repositorys" + } + } + }; + + const navLink = mount( + {}} /> + ); + 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( + + ); + navLink.find("a").simulate("click"); + + expect(calledUrl).toBe("/repos"); + }); +}); diff --git a/scm-ui/src/repos/components/RepositoryForm.js b/scm-ui/src/repos/components/form/RepositoryForm.js similarity index 92% rename from scm-ui/src/repos/components/RepositoryForm.js rename to scm-ui/src/repos/components/form/RepositoryForm.js index 92741f1d83..bde5d20d3b 100644 --- a/scm-ui/src/repos/components/RepositoryForm.js +++ b/scm-ui/src/repos/components/form/RepositoryForm.js @@ -1,12 +1,12 @@ // @flow import React from "react"; import { translate } from "react-i18next"; -import { InputField, Select } from "../../components/forms"; -import { SubmitButton } from "../../components/buttons"; -import type { Repository } from "../types/Repositories"; +import { InputField, Select } from "../../../components/forms/index"; +import { SubmitButton } from "../../../components/buttons/index"; +import type { Repository } from "../../types/Repositories"; import * as validator from "./repositoryValidation"; -import type { RepositoryType } from "../types/RepositoryTypes"; -import Textarea from "../../components/forms/Textarea"; +import type { RepositoryType } from "../../types/RepositoryTypes"; +import Textarea from "../../../components/forms/Textarea"; type Props = { submitForm: Repository => void, diff --git a/scm-ui/src/repos/components/form/index.js b/scm-ui/src/repos/components/form/index.js new file mode 100644 index 0000000000..4af39bf51e --- /dev/null +++ b/scm-ui/src/repos/components/form/index.js @@ -0,0 +1,2 @@ +import RepositoryForm from "./RepositoryForm"; +export default RepositoryForm; diff --git a/scm-ui/src/repos/components/repositoryValidation.js b/scm-ui/src/repos/components/form/repositoryValidation.js similarity index 75% rename from scm-ui/src/repos/components/repositoryValidation.js rename to scm-ui/src/repos/components/form/repositoryValidation.js index d85b961c99..dbd099144f 100644 --- a/scm-ui/src/repos/components/repositoryValidation.js +++ b/scm-ui/src/repos/components/form/repositoryValidation.js @@ -1,5 +1,5 @@ // @flow -import * as generalValidator from "../../components/validation"; +import * as generalValidator from "../../../components/validation"; export const isNameValid = (name: string) => { return generalValidator.isNameValid(name); diff --git a/scm-ui/src/repos/components/repositoryValidation.test.js b/scm-ui/src/repos/components/form/repositoryValidation.test.js similarity index 100% rename from scm-ui/src/repos/components/repositoryValidation.test.js rename to scm-ui/src/repos/components/form/repositoryValidation.test.js diff --git a/scm-ui/src/repos/components/RepositoryEntry.js b/scm-ui/src/repos/components/list/RepositoryEntry.js similarity index 94% rename from scm-ui/src/repos/components/RepositoryEntry.js rename to scm-ui/src/repos/components/list/RepositoryEntry.js index eceed7c1ff..72ebd70d77 100644 --- a/scm-ui/src/repos/components/RepositoryEntry.js +++ b/scm-ui/src/repos/components/list/RepositoryEntry.js @@ -2,12 +2,12 @@ import React from "react"; import { Link } from "react-router-dom"; import injectSheet from "react-jss"; -import type { Repository } from "../types/Repositories"; -import DateFromNow from "../../components/DateFromNow"; +import type { Repository } from "../../types/Repositories"; +import DateFromNow from "../../../components/DateFromNow"; import RepositoryEntryLink from "./RepositoryEntryLink"; 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 diff --git a/scm-ui/src/repos/components/RepositoryEntryLink.js b/scm-ui/src/repos/components/list/RepositoryEntryLink.js similarity index 100% rename from scm-ui/src/repos/components/RepositoryEntryLink.js rename to scm-ui/src/repos/components/list/RepositoryEntryLink.js diff --git a/scm-ui/src/repos/components/RepositoryGroupEntry.js b/scm-ui/src/repos/components/list/RepositoryGroupEntry.js similarity index 95% rename from scm-ui/src/repos/components/RepositoryGroupEntry.js rename to scm-ui/src/repos/components/list/RepositoryGroupEntry.js index b0d145c338..09b3932b28 100644 --- a/scm-ui/src/repos/components/RepositoryGroupEntry.js +++ b/scm-ui/src/repos/components/list/RepositoryGroupEntry.js @@ -1,6 +1,6 @@ //@flow import React from "react"; -import type { RepositoryGroup } from "../types/Repositories"; +import type { RepositoryGroup } from "../../types/Repositories"; import injectSheet from "react-jss"; import classNames from "classnames"; import RepositoryEntry from "./RepositoryEntry"; diff --git a/scm-ui/src/repos/components/RepositoryList.js b/scm-ui/src/repos/components/list/RepositoryList.js similarity index 90% rename from scm-ui/src/repos/components/RepositoryList.js rename to scm-ui/src/repos/components/list/RepositoryList.js index c6a8d3b86c..367c054990 100644 --- a/scm-ui/src/repos/components/RepositoryList.js +++ b/scm-ui/src/repos/components/list/RepositoryList.js @@ -1,7 +1,7 @@ //@flow import React from "react"; -import type { Repository } from "../types/Repositories"; +import type { Repository } from "../../types/Repositories"; import groupByNamespace from "./groupByNamespace"; import RepositoryGroupEntry from "./RepositoryGroupEntry"; diff --git a/scm-ui/src/repos/components/groupByNamespace.js b/scm-ui/src/repos/components/list/groupByNamespace.js similarity index 91% rename from scm-ui/src/repos/components/groupByNamespace.js rename to scm-ui/src/repos/components/list/groupByNamespace.js index 55dec92391..825fa5e67b 100644 --- a/scm-ui/src/repos/components/groupByNamespace.js +++ b/scm-ui/src/repos/components/list/groupByNamespace.js @@ -1,5 +1,5 @@ // @flow -import type { Repository, RepositoryGroup } from "../types/Repositories"; +import type { Repository, RepositoryGroup } from "../../types/Repositories"; export default function groupByNamespace( repositories: Repository[] diff --git a/scm-ui/src/repos/components/groupByNamespace.test.js b/scm-ui/src/repos/components/list/groupByNamespace.test.js similarity index 100% rename from scm-ui/src/repos/components/groupByNamespace.test.js rename to scm-ui/src/repos/components/list/groupByNamespace.test.js diff --git a/scm-ui/src/repos/components/list/index.js b/scm-ui/src/repos/components/list/index.js new file mode 100644 index 0000000000..62c264cb7b --- /dev/null +++ b/scm-ui/src/repos/components/list/index.js @@ -0,0 +1,2 @@ +import RepositoryList from "./RepositoryList"; +export default RepositoryList; diff --git a/scm-ui/src/repos/containers/Create.js b/scm-ui/src/repos/containers/Create.js index 664f7e2d1b..b705788d1d 100644 --- a/scm-ui/src/repos/containers/Create.js +++ b/scm-ui/src/repos/containers/Create.js @@ -3,7 +3,7 @@ import React from "react"; import { connect } from "react-redux"; import { translate } from "react-i18next"; import { Page } from "../../components/layout"; -import RepositoryForm from "../components/RepositoryForm"; +import RepositoryForm from "../components/form"; import type { RepositoryType } from "../types/RepositoryTypes"; import { fetchRepositoryTypesIfNeeded, diff --git a/scm-ui/src/repos/containers/Overview.js b/scm-ui/src/repos/containers/Overview.js index 54d90a354a..f4b49ed8d2 100644 --- a/scm-ui/src/repos/containers/Overview.js +++ b/scm-ui/src/repos/containers/Overview.js @@ -15,7 +15,7 @@ import { } from "../modules/repos"; import { translate } from "react-i18next"; import { Page } from "../../components/layout"; -import RepositoryList from "../components/RepositoryList"; +import RepositoryList from "../components/list"; import Paginator from "../../components/Paginator"; import { withRouter } from "react-router-dom"; import type { History } from "history"; diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js index ccc75ad05c..97390aaa52 100644 --- a/scm-ui/src/repos/containers/RepositoryRoot.js +++ b/scm-ui/src/repos/containers/RepositoryRoot.js @@ -1,6 +1,7 @@ //@flow import React from "react"; import { + deleteRepo, fetchRepo, getFetchRepoFailure, getRepository, @@ -15,6 +16,9 @@ import ErrorPage from "../../components/ErrorPage"; import { translate } from "react-i18next"; import { Navigation, NavLink, Section } from "../../components/navigation"; import RepositoryDetails from "../components/RepositoryDetails"; +import DeleteNavAction from "../components/DeleteNavAction"; + +import type { History } from "history"; type Props = { namespace: string, @@ -25,9 +29,11 @@ type Props = { // dispatch functions fetchRepo: (namespace: string, name: string) => void, + deleteRepo: (repository: Repository, () => void) => void, // context props t: string => string, + history: History, match: any }; @@ -49,6 +55,14 @@ class RepositoryRoot extends React.Component { return this.stripEndingSlash(this.props.match.url); }; + deleted = () => { + this.props.history.push("/repos"); + }; + + delete = (repository: Repository) => { + this.props.deleteRepo(repository, this.deleted); + }; + render() { const { loading, error, repository, t } = this.props; @@ -81,6 +95,7 @@ class RepositoryRoot extends React.Component {
+
@@ -109,6 +124,9 @@ const mapDispatchToProps = dispatch => { return { fetchRepo: (namespace: string, name: string) => { dispatch(fetchRepo(namespace, name)); + }, + deleteRepo: (repository: Repository, callback: () => void) => { + dispatch(deleteRepo(repository, callback)); } }; };