From e32130cd0b3e7e45d9b2ec17ccc1c859fc1fde85 Mon Sep 17 00:00:00 2001 From: Eduard Heimbuch Date: Wed, 24 Jun 2020 10:39:00 +0200 Subject: [PATCH] create Dangerzone --- scm-ui/ui-webapp/public/locales/de/repos.json | 21 ++- scm-ui/ui-webapp/public/locales/en/repos.json | 21 ++- .../src/repos/containers/DangerZone.tsx | 74 ++++++++++ .../src/repos/containers/DeleteRepo.tsx | 33 +++-- .../src/repos/containers/EditRepo.tsx | 10 +- .../src/repos/containers/RenameRepository.tsx | 129 ++++++++++++++++++ 6 files changed, 267 insertions(+), 21 deletions(-) create mode 100644 scm-ui/ui-webapp/src/repos/containers/DangerZone.tsx create mode 100644 scm-ui/ui-webapp/src/repos/containers/RenameRepository.tsx diff --git a/scm-ui/ui-webapp/public/locales/de/repos.json b/scm-ui/ui-webapp/public/locales/de/repos.json index 882f63a7e6..e6906f8800 100644 --- a/scm-ui/ui-webapp/public/locales/de/repos.json +++ b/scm-ui/ui-webapp/public/locales/de/repos.json @@ -110,7 +110,8 @@ "repositoryForm": { "subtitle": "Repository bearbeiten", "submit": "Speichern", - "initializeRepository": "Repository initiieren" + "initializeRepository": "Repository initiieren", + "dangerZone": "Gefahrenzone" }, "sources": { "file-tree": { @@ -193,6 +194,8 @@ }, "deleteRepo": { "button": "Repository löschen", + "subtitle": "Löscht dieses Repository", + "description": "Diese Aktion kann nicht rückgangig gemacht werden.", "confirmAlert": { "title": "Repository löschen", "message": "Soll das Repository wirklich gelöscht werden?", @@ -200,6 +203,22 @@ "cancel": "Nein" } }, + "renameRepo": { + "button": "Repository umbenennen", + "subtitle": "Benennt dieses Repository um", + "description": "Es werden keine Weiterleitung auf den neuen Namen eingerichtet.", + "modal": { + "title": "Repository umbenennen", + "label": { + "repoName": "Repository Name", + "repoNamespace": "Repository Namespace" + }, + "button": { + "rename": "Umbenennen", + "cancel": "Abbrechen" + } + } + }, "diff": { "sideBySide": "Zur zweispaltigen Ansicht wechseln", "combined": "Zur kombinierten Ansicht wechseln", diff --git a/scm-ui/ui-webapp/public/locales/en/repos.json b/scm-ui/ui-webapp/public/locales/en/repos.json index 7102cff33a..8cafddf9f6 100644 --- a/scm-ui/ui-webapp/public/locales/en/repos.json +++ b/scm-ui/ui-webapp/public/locales/en/repos.json @@ -110,7 +110,8 @@ "repositoryForm": { "subtitle": "Edit Repository", "submit": "Save", - "initializeRepository": "Initialize repository" + "initializeRepository": "Initialize repository", + "dangerZone": "Danger Zone" }, "sources": { "file-tree": { @@ -193,6 +194,8 @@ }, "deleteRepo": { "button": "Delete Repository", + "subtitle": "Deletes this repository", + "description": "Once a repository was deleted, this cannot be undone. Please be careful with this action.", "confirmAlert": { "title": "Delete repository", "message": "Do you really want to delete the repository?", @@ -200,6 +203,22 @@ "cancel": "No" } }, + "renameRepo": { + "button": "Rename Repository", + "subtitle": "Renames this repository", + "description": "There will be no redirects to the renamed repository.", + "modal": { + "title": "Rename repository", + "label": { + "repoName": "Repository name", + "repoNamespace": "Repository namespace" + }, + "button": { + "rename": "Rename", + "cancel": "Cancel" + } + } + }, "diff": { "changes": { "add": "added", diff --git a/scm-ui/ui-webapp/src/repos/containers/DangerZone.tsx b/scm-ui/ui-webapp/src/repos/containers/DangerZone.tsx new file mode 100644 index 0000000000..97cd60b68d --- /dev/null +++ b/scm-ui/ui-webapp/src/repos/containers/DangerZone.tsx @@ -0,0 +1,74 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import React, { FC } from "react"; +import { Repository } from "@scm-manager/ui-types"; +import RenameRepository from "./RenameRepository"; +import DeleteRepo from "./DeleteRepo"; +import styled from "styled-components"; +import { Subtitle } from "@scm-manager/ui-components"; +import { useTranslation } from "react-i18next"; + +type Props = { + repository: Repository; +}; + +const DangerZoneContainer = styled.div` + padding: 1rem; + border: 1px solid #ff6a88; + border-radius: 5px; + > *:not(:last-child) { + padding-bottom: 1.5rem; + border-bottom: solid 2px whitesmoke; + } +`; + +const DangerZone: FC = ({ repository }) => { + const [t] = useTranslation("repos"); + + const dangerZone = []; + if (repository?._links?.rename) { + dangerZone.push(); + } + if (repository?._links?.renameWithNamespace) { + dangerZone.push(); + } + if (repository?._links?.delete) { + dangerZone.push(); + } + + if (dangerZone.length === 0) { + return null; + } + + return ( + <> +
+ + {dangerZone.map(entry => entry)} + + ); +}; + +export default DangerZone; diff --git a/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx b/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx index 4b782fbcaf..8585e98466 100644 --- a/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx @@ -24,23 +24,21 @@ import React from "react"; import { connect } from "react-redux"; import { compose } from "redux"; -import { withRouter } from "react-router-dom"; +import { RouteComponentProps, withRouter } from "react-router-dom"; import { WithTranslation, withTranslation } from "react-i18next"; import { History } from "history"; import { Repository } from "@scm-manager/ui-types"; -import { confirmAlert, DeleteButton, ErrorNotification, Level } from "@scm-manager/ui-components"; +import { confirmAlert, DeleteButton, ErrorNotification, Level, ButtonGroup } from "@scm-manager/ui-components"; import { deleteRepo, getDeleteRepoFailure, isDeleteRepoPending } from "../modules/repos"; -type Props = WithTranslation & { - loading: boolean; - error: Error; - repository: Repository; - confirmDialog?: boolean; - deleteRepo: (p1: Repository, p2: () => void) => void; - - // context props - history: History; -}; +type Props = RouteComponentProps & + WithTranslation & { + loading: boolean; + error: Error; + repository: Repository; + confirmDialog?: boolean; + deleteRepo: (p1: Repository, p2: () => void) => void; + }; class DeleteRepo extends React.Component { static defaultProps = { @@ -88,9 +86,16 @@ class DeleteRepo extends React.Component { return ( <> -
- } /> + + {t("deleteRepo.subtitle")} +

{t("deleteRepo.description")}

+ + } + right={} + /> ); } diff --git a/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx b/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx index a6e9874628..a919423fa4 100644 --- a/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx @@ -25,13 +25,13 @@ 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 { getModifyRepoFailure, isModifyRepoPending, modifyRepo, modifyRepoReset } from "../modules/repos"; import { History } from "history"; import { ErrorNotification } from "@scm-manager/ui-components"; import { ExtensionPoint } from "@scm-manager/ui-extensions"; import { compose } from "redux"; +import DangerZone from "./DangerZone"; type Props = { loading: boolean; @@ -79,7 +79,7 @@ class EditRepo extends React.Component { }; return ( -
+ <> { }} /> - -
+ + ); } } @@ -116,4 +116,4 @@ const mapDispatchToProps = (dispatch: any) => { }; }; -export default compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(EditRepo); +export default compose(connect(mapStateToProps, mapDispatchToProps))(withRouter(EditRepo)); diff --git a/scm-ui/ui-webapp/src/repos/containers/RenameRepository.tsx b/scm-ui/ui-webapp/src/repos/containers/RenameRepository.tsx new file mode 100644 index 0000000000..16ff616798 --- /dev/null +++ b/scm-ui/ui-webapp/src/repos/containers/RenameRepository.tsx @@ -0,0 +1,129 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import React, { FC, useState } from "react"; +import { Repository } from "@scm-manager/ui-types"; +import { + ErrorNotification, + Level, + Button, + Loading, + Modal, + InputField, + validation, + ButtonGroup +} from "@scm-manager/ui-components"; +import { useTranslation } from "react-i18next"; + +type Props = { + repository: Repository; + renameNamespace: boolean; +}; + +const RenameRepository: FC = ({ repository, renameNamespace }) => { + const [t] = useTranslation("repos"); + const [error, setError] = useState(undefined); + const [loading, setLoading] = useState(false); + const [showModal, setShowModal] = useState(false); + const [repositoryName, setRepositoryName] = useState(repository.name); + const [repositoryNamespace, setRepositoryNamespace] = useState(repository.namespace); + + if (error) { + return ; + } + + if (loading) { + return ; + } + + const isValid = + validation.isNameValid(repositoryName) && + validation.isNameValid(repositoryNamespace) && + (repository.name !== repositoryName || repository.namespace !== repositoryNamespace); + + const modalBody = ( +
+ + {renameNamespace && ( + + )} +
+ ); + + const footer = ( + <> + +