mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-07 22:15:45 +01:00
add 'delete branch' function to frontend
This commit is contained in:
@@ -62,11 +62,11 @@ export const ConfirmAlert: FC<Props> = ({ title, message, buttons, close }) => {
|
||||
|
||||
const footer = (
|
||||
<div className="field is-grouped">
|
||||
{buttons.map((button, i) => (
|
||||
<p className="control">
|
||||
{buttons.map((button, index) => (
|
||||
<p className="control" key={index}>
|
||||
<a
|
||||
className={classNames("button", "is-info", button.className)}
|
||||
key={i}
|
||||
key={index}
|
||||
onClick={() => handleClickButton(button)}
|
||||
>
|
||||
{button.label}
|
||||
|
||||
@@ -68,7 +68,19 @@
|
||||
"name": "Name:",
|
||||
"commits": "Commits",
|
||||
"sources": "Sources",
|
||||
"defaultTag": "Default"
|
||||
"defaultTag": "Default",
|
||||
"dangerZone": "Branch löschen",
|
||||
"delete": {
|
||||
"button": "Branch löschen",
|
||||
"subtitle": "Branch löschen",
|
||||
"description": "Gelöschte Branches können nicht wiederhergestellt werden.",
|
||||
"confirmAlert": {
|
||||
"title": "Branch löschen",
|
||||
"message": "Möchten Sie diesen Branch wirklich löschen?",
|
||||
"cancel": "Nein",
|
||||
"submit": "Ja"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"overview": {
|
||||
|
||||
@@ -68,7 +68,19 @@
|
||||
"name": "Name:",
|
||||
"commits": "Commits",
|
||||
"sources": "Sources",
|
||||
"defaultTag": "Default"
|
||||
"defaultTag": "Default",
|
||||
"dangerZone": "Delete branch",
|
||||
"delete": {
|
||||
"button": "Delete branch",
|
||||
"subtitle": "Delete branch",
|
||||
"description": "Deleted branches can not be restored.",
|
||||
"confirmAlert": {
|
||||
"title": "Delete branch",
|
||||
"message": "Do you really want to delete the branch?",
|
||||
"cancel": "No",
|
||||
"submit": "Yes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"overview": {
|
||||
|
||||
@@ -44,7 +44,7 @@ const BranchRow: FC<Props> = ({ baseUrl, branch, onDelete }) => {
|
||||
deleteButton = (
|
||||
<a className="level-item" onClick={() => onDelete(url)}>
|
||||
<span className="icon is-small">
|
||||
<Icon name="trash" className="fas" title={t("branch.delete")} />
|
||||
<Icon name="trash" className="fas" title={t("branch.delete.button")} />
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
|
||||
@@ -21,19 +21,40 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React, { FC } from "react";
|
||||
import React, { FC, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import BranchRow from "./BranchRow";
|
||||
import { Branch } from "@scm-manager/ui-types";
|
||||
import { apiClient, ConfirmAlert, ErrorNotification } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string;
|
||||
branches: Branch[];
|
||||
onDelete: (url: string) => void;
|
||||
fetchBranches: () => void;
|
||||
};
|
||||
|
||||
const BranchTable: FC<Props> = ({ baseUrl, branches, onDelete }) => {
|
||||
const BranchTable: FC<Props> = ({ baseUrl, branches, fetchBranches }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
const [showConfirmAlert, setShowConfirmAlert] = useState(false);
|
||||
const [error, setError] = useState<Error | undefined>();
|
||||
const [deleteBranchUrl, setDeleteBranchUrl] = useState("");
|
||||
|
||||
const onDelete = (url: string) => {
|
||||
setDeleteBranchUrl(url);
|
||||
setShowConfirmAlert(true);
|
||||
};
|
||||
|
||||
const abortDelete = () => {
|
||||
setDeleteBranchUrl("");
|
||||
setShowConfirmAlert(false);
|
||||
};
|
||||
|
||||
const deleteBranch = () => {
|
||||
apiClient
|
||||
.delete(deleteBranchUrl)
|
||||
.then(() => fetchBranches())
|
||||
.catch(setError);
|
||||
};
|
||||
|
||||
const renderRow = () => {
|
||||
let rowContent = null;
|
||||
@@ -44,7 +65,30 @@ const BranchTable: FC<Props> = ({ baseUrl, branches, onDelete }) => {
|
||||
}
|
||||
return rowContent;
|
||||
};
|
||||
|
||||
const confirmAlert = (
|
||||
<ConfirmAlert
|
||||
title={t("branch.delete.confirmAlert.title")}
|
||||
message={t("branch.delete.confirmAlert.message")}
|
||||
buttons={[
|
||||
{
|
||||
className: "is-outlined",
|
||||
label: t("branch.delete.confirmAlert.submit"),
|
||||
onClick: () => deleteBranch()
|
||||
},
|
||||
{
|
||||
label: t("branch.delete.confirmAlert.cancel"),
|
||||
onClick: () => abortDelete()
|
||||
}
|
||||
]}
|
||||
close={() => abortDelete()}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showConfirmAlert && confirmAlert}
|
||||
{error && <ErrorNotification error={error} />}
|
||||
<table className="card-table table is-hoverable is-fullwidth is-word-break">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -53,6 +97,7 @@ const BranchTable: FC<Props> = ({ baseUrl, branches, onDelete }) => {
|
||||
</thead>
|
||||
<tbody>{renderRow()}</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import React from "react";
|
||||
import BranchDetail from "./BranchDetail";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||
import BranchDangerZone from "../containers/BranchDangerZone";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
@@ -34,7 +35,6 @@ type Props = {
|
||||
class BranchView extends React.Component<Props> {
|
||||
render() {
|
||||
const { repository, branch } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BranchDetail repository={repository} branch={branch} />
|
||||
@@ -49,6 +49,7 @@ class BranchView extends React.Component<Props> {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<BranchDangerZone repository={repository} branch={branch} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 { Branch, Repository } from "@scm-manager/ui-types";
|
||||
import { Subtitle } from "@scm-manager/ui-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { DangerZoneContainer } from "../../containers/RepositoryDangerZone";
|
||||
import DeleteBranch from "./DeleteBranch";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
branch: Branch;
|
||||
};
|
||||
|
||||
const BranchDangerZone: FC<Props> = ({ repository, branch }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
|
||||
const dangerZone = [];
|
||||
|
||||
if (branch?._links?.delete) {
|
||||
dangerZone.push(<DeleteBranch repository={repository} branch={branch} key={dangerZone.length} />);
|
||||
}
|
||||
|
||||
if (dangerZone.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<hr />
|
||||
<Subtitle subtitle={t("branch.dangerZone")} />
|
||||
<DangerZoneContainer>{dangerZone}</DangerZoneContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BranchDangerZone;
|
||||
@@ -28,10 +28,9 @@ import { compose } from "redux";
|
||||
import { Redirect, Route, Switch, withRouter } from "react-router-dom";
|
||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||
import { fetchBranch, getBranch, getFetchBranchFailure, isFetchBranchPending } from "../modules/branches";
|
||||
import { ErrorNotification, Loading, NotFoundError } from "@scm-manager/ui-components";
|
||||
import { ErrorNotification, Loading, NotFoundError, urls } from "@scm-manager/ui-components";
|
||||
import { History } from "history";
|
||||
import queryString from "query-string";
|
||||
import { urls } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
|
||||
@@ -37,7 +37,6 @@ import {
|
||||
} from "../modules/branches";
|
||||
import { orderBranches } from "../util/orderBranches";
|
||||
import BranchTable from "../components/BranchTable";
|
||||
import { apiClient } from "@scm-manager/ui-components/src";
|
||||
|
||||
type Props = WithTranslation & {
|
||||
repository: Repository;
|
||||
@@ -81,15 +80,11 @@ class BranchesOverview extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
onDelete(url: string) {
|
||||
apiClient.delete(url).catch(error => this.setState({ error }));
|
||||
}
|
||||
|
||||
renderBranchesTable() {
|
||||
const { baseUrl, branches, t } = this.props;
|
||||
const { baseUrl, branches, repository, fetchBranches, t } = this.props;
|
||||
if (branches && branches.length > 0) {
|
||||
orderBranches(branches);
|
||||
return <BranchTable baseUrl={baseUrl} branches={branches} onDelete={this.onDelete} />;
|
||||
return <BranchTable baseUrl={baseUrl} branches={branches} fetchBranches={() => fetchBranches(repository)} />;
|
||||
}
|
||||
return <Notification type="info">{t("branches.overview.noBranches")}</Notification>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 { useHistory } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Branch, Link, Repository } from "@scm-manager/ui-types";
|
||||
import { apiClient, ConfirmAlert, DeleteButton, ErrorNotification, Level } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
repository: Repository;
|
||||
branch: Branch;
|
||||
};
|
||||
|
||||
const DeleteBranch: FC<Props> = ({ repository, branch }: Props) => {
|
||||
const [showConfirmAlert, setShowConfirmAlert] = useState(false);
|
||||
const [error, setError] = useState<Error | undefined>();
|
||||
const [t] = useTranslation("repos");
|
||||
const history = useHistory();
|
||||
|
||||
console.log("branchview", repository, branch);
|
||||
|
||||
const deleteBranch = () => {
|
||||
apiClient
|
||||
.delete((branch._links.delete as Link).href)
|
||||
.then(() => history.push(`/repo/${repository.namespace}/${repository.name}/branches/`))
|
||||
.catch(setError);
|
||||
};
|
||||
|
||||
if (!branch._links.delete) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let confirmAlert = null;
|
||||
if (showConfirmAlert) {
|
||||
confirmAlert = (
|
||||
<ConfirmAlert
|
||||
title={t("branch.delete.confirmAlert.title")}
|
||||
message={t("branch.delete.confirmAlert.message")}
|
||||
buttons={[
|
||||
{
|
||||
className: "is-outlined",
|
||||
label: t("branch.delete.confirmAlert.submit"),
|
||||
onClick: () => deleteBranch()
|
||||
},
|
||||
{
|
||||
label: t("branch.delete.confirmAlert.cancel"),
|
||||
onClick: () => null
|
||||
}
|
||||
]}
|
||||
close={() => setShowConfirmAlert(false)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ErrorNotification error={error} />
|
||||
{showConfirmAlert && confirmAlert}
|
||||
<Level
|
||||
left={
|
||||
<p>
|
||||
<strong>{t("branch.delete.subtitle")}</strong>
|
||||
<br />
|
||||
{t("branch.delete.description")}
|
||||
</p>
|
||||
}
|
||||
right={<DeleteButton label={t("branch.delete.button")} action={() => setShowConfirmAlert(true)} />}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteBranch;
|
||||
@@ -31,7 +31,7 @@ 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";
|
||||
import RepositoryDangerZone from "./RepositoryDangerZone";
|
||||
import { getLinks } from "../../modules/indexResource";
|
||||
import { urls } from "@scm-manager/ui-components";
|
||||
|
||||
@@ -80,7 +80,7 @@ class EditRepo extends React.Component<Props> {
|
||||
}}
|
||||
/>
|
||||
<ExtensionPoint name="repo-config.route" props={extensionProps} renderAll={true} />
|
||||
<DangerZone repository={repository} indexLinks={indexLinks} />
|
||||
<RepositoryDangerZone repository={repository} indexLinks={indexLinks} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ type Props = {
|
||||
indexLinks: Links;
|
||||
};
|
||||
|
||||
const DangerZoneContainer = styled.div`
|
||||
export const DangerZoneContainer = styled.div`
|
||||
padding: 1.5rem 1rem;
|
||||
border: 1px solid #ff6a88;
|
||||
border-radius: 5px;
|
||||
@@ -56,7 +56,7 @@ const DangerZoneContainer = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const DangerZone: FC<Props> = ({ repository, indexLinks }) => {
|
||||
const RepositoryDangerZone: FC<Props> = ({ repository, indexLinks }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
|
||||
const dangerZone = [];
|
||||
@@ -81,4 +81,4 @@ const DangerZone: FC<Props> = ({ repository, indexLinks }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default DangerZone;
|
||||
export default RepositoryDangerZone;
|
||||
Reference in New Issue
Block a user