mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-18 03:01:05 +01:00
add frontend for deleting tags
This commit is contained in:
@@ -24,14 +24,15 @@
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Tag } from "@scm-manager/ui-types";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { Tag, Link } from "@scm-manager/ui-types";
|
||||
import styled from "styled-components";
|
||||
import { DateFromNow } from "@scm-manager/ui-components";
|
||||
import { DateFromNow, Icon } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
tag: Tag;
|
||||
baseUrl: string;
|
||||
onDelete: (tag: Tag) => void;
|
||||
};
|
||||
|
||||
const Created = styled.span`
|
||||
@@ -39,20 +40,32 @@ const Created = styled.span`
|
||||
font-size: 0.8rem;
|
||||
`;
|
||||
|
||||
const TagRow: FC<Props> = ({ tag, baseUrl }) => {
|
||||
const TagRow: FC<Props> = ({ tag, baseUrl, onDelete }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
|
||||
let deleteButton;
|
||||
if ((tag?._links?.delete as Link)?.href) {
|
||||
deleteButton = (
|
||||
<a className="level-item" onClick={() => onDelete(tag)}>
|
||||
<span className="icon is-small">
|
||||
<Icon name="trash" className="fas" title={t("tag.delete.button")} />
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const to = `${baseUrl}/${encodeURIComponent(tag.name)}/info`;
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<Link to={to} title={tag.name}>
|
||||
<RouterLink to={to} title={tag.name}>
|
||||
{tag.name}
|
||||
<Created className="has-text-grey is-ellipsis-overflow">
|
||||
{t("tags.overview.created")} <DateFromNow date={tag.date} />
|
||||
</Created>
|
||||
</Link>
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td className="is-darker">{deleteButton}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -22,30 +22,74 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { Tag } from "@scm-manager/ui-types";
|
||||
import React, {FC, useState} from "react";
|
||||
import {Link, Tag} from "@scm-manager/ui-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import TagRow from "./TagRow";
|
||||
import {apiClient, ConfirmAlert, ErrorNotification} from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string;
|
||||
tags: Tag[];
|
||||
fetchTags: () => void;
|
||||
};
|
||||
|
||||
const TagTable: FC<Props> = ({ baseUrl, tags }) => {
|
||||
const TagTable: FC<Props> = ({ baseUrl, tags, fetchTags }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
const [showConfirmAlert, setShowConfirmAlert] = useState(false);
|
||||
const [error, setError] = useState<Error | undefined>();
|
||||
const [tagToBeDeleted, setTagToBeDeleted] = useState<Tag | undefined>();
|
||||
|
||||
const onDelete = (tag: Tag) => {
|
||||
setTagToBeDeleted(tag);
|
||||
setShowConfirmAlert(true);
|
||||
};
|
||||
|
||||
const abortDelete = () => {
|
||||
setTagToBeDeleted(undefined);
|
||||
setShowConfirmAlert(false);
|
||||
};
|
||||
|
||||
const deleteTag = () => {
|
||||
apiClient
|
||||
.delete((tagToBeDeleted?._links.delete as Link).href)
|
||||
.then(() => fetchTags())
|
||||
.catch(setError);
|
||||
};
|
||||
|
||||
const renderRow = () => {
|
||||
let rowContent = null;
|
||||
if (tags) {
|
||||
rowContent = tags.map((tag, index) => {
|
||||
return <TagRow key={index} baseUrl={baseUrl} tag={tag} />;
|
||||
return <TagRow key={index} baseUrl={baseUrl} tag={tag} onDelete={onDelete} />;
|
||||
});
|
||||
}
|
||||
return rowContent;
|
||||
};
|
||||
|
||||
const confirmAlert = (
|
||||
<ConfirmAlert
|
||||
title={t("tag.delete.confirmAlert.title")}
|
||||
message={t("tag.delete.confirmAlert.message", { tag: tagToBeDeleted?.name })}
|
||||
buttons={[
|
||||
{
|
||||
className: "is-outlined",
|
||||
label: t("tag.delete.confirmAlert.submit"),
|
||||
onClick: () => deleteTag()
|
||||
},
|
||||
{
|
||||
label: t("tag.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>
|
||||
@@ -54,7 +98,7 @@ const TagTable: FC<Props> = ({ baseUrl, tags }) => {
|
||||
</thead>
|
||||
<tbody>{renderRow()}</tbody>
|
||||
</table>
|
||||
);
|
||||
</>);
|
||||
};
|
||||
|
||||
export default TagTable;
|
||||
|
||||
@@ -40,7 +40,7 @@ const TagsOverview: FC<Props> = ({ repository, baseUrl }) => {
|
||||
const [error, setError] = useState<Error | undefined>(undefined);
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTags = () => {
|
||||
const link = (repository._links?.tags as Link)?.href;
|
||||
if (link) {
|
||||
setLoading(true);
|
||||
@@ -51,12 +51,16 @@ const TagsOverview: FC<Props> = ({ repository, baseUrl }) => {
|
||||
.then(() => setLoading(false))
|
||||
.catch(setError);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTags();
|
||||
}, [repository]);
|
||||
|
||||
const renderTagsTable = () => {
|
||||
if (!loading && tags?.length > 0) {
|
||||
orderTags(tags);
|
||||
return <TagTable baseUrl={baseUrl} tags={tags} />;
|
||||
return <TagTable baseUrl={baseUrl} tags={tags} fetchTags={() => fetchTags()} />;
|
||||
}
|
||||
return <Notification type="info">{t("tags.overview.noTags")}</Notification>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user