mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 08:25:44 +01:00
add tag overview for repository
This commit is contained in:
@@ -27,5 +27,6 @@ import { Links } from "./hal";
|
|||||||
export type Tag = {
|
export type Tag = {
|
||||||
name: string;
|
name: string;
|
||||||
revision: string;
|
revision: string;
|
||||||
|
date: Date;
|
||||||
_links: Links;
|
_links: Links;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"navigationLabel": "Repository",
|
"navigationLabel": "Repository",
|
||||||
"informationNavLink": "Informationen",
|
"informationNavLink": "Informationen",
|
||||||
"branchesNavLink": "Branches",
|
"branchesNavLink": "Branches",
|
||||||
|
"tagsNavLink": "Tags",
|
||||||
"sourcesNavLink": "Code",
|
"sourcesNavLink": "Code",
|
||||||
"settingsNavLink": "Einstellungen",
|
"settingsNavLink": "Einstellungen",
|
||||||
"generalNavLink": "Generell",
|
"generalNavLink": "Generell",
|
||||||
@@ -71,6 +72,19 @@
|
|||||||
"sources": "Sources",
|
"sources": "Sources",
|
||||||
"defaultTag": "Default"
|
"defaultTag": "Default"
|
||||||
},
|
},
|
||||||
|
"tags": {
|
||||||
|
"overview": {
|
||||||
|
"title": "Übersicht aller verfügbaren Tags",
|
||||||
|
"noTags": "Keine Tags gefunden.",
|
||||||
|
"created": "Erstellt"
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"tags": "Tags"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"name": "Name:"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"sources": "Sources",
|
"sources": "Sources",
|
||||||
"commits": "Commits",
|
"commits": "Commits",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"navigationLabel": "Repository",
|
"navigationLabel": "Repository",
|
||||||
"informationNavLink": "Information",
|
"informationNavLink": "Information",
|
||||||
"branchesNavLink": "Branches",
|
"branchesNavLink": "Branches",
|
||||||
|
"tagsNavLink": "Tags",
|
||||||
"sourcesNavLink": "Code",
|
"sourcesNavLink": "Code",
|
||||||
"settingsNavLink": "Settings",
|
"settingsNavLink": "Settings",
|
||||||
"generalNavLink": "General",
|
"generalNavLink": "General",
|
||||||
@@ -71,6 +72,19 @@
|
|||||||
"sources": "Sources",
|
"sources": "Sources",
|
||||||
"defaultTag": "Default"
|
"defaultTag": "Default"
|
||||||
},
|
},
|
||||||
|
"tags": {
|
||||||
|
"overview": {
|
||||||
|
"title": "Overview of all tags",
|
||||||
|
"noTags": "No tags found.",
|
||||||
|
"created": "Created"
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"tags": "Tags"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"name": "Name:"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"sources": "Sources",
|
"sources": "Sources",
|
||||||
"commits": "Commits",
|
"commits": "Commits",
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ import CodeOverview from "../codeSection/containers/CodeOverview";
|
|||||||
import ChangesetView from "./ChangesetView";
|
import ChangesetView from "./ChangesetView";
|
||||||
import SourceExtensions from "../sources/containers/SourceExtensions";
|
import SourceExtensions from "../sources/containers/SourceExtensions";
|
||||||
import { FileControlFactory, JumpToFileButton } from "@scm-manager/ui-components";
|
import { FileControlFactory, JumpToFileButton } from "@scm-manager/ui-components";
|
||||||
|
import TagsOverview from "../tags/container/TagsOverview";
|
||||||
|
import TagRoot from "../tags/container/TagRoot";
|
||||||
|
|
||||||
type Props = RouteComponentProps &
|
type Props = RouteComponentProps &
|
||||||
WithTranslation & {
|
WithTranslation & {
|
||||||
@@ -99,6 +101,12 @@ class RepositoryRoot extends React.Component<Props> {
|
|||||||
return route.location.pathname.match(regex);
|
return route.location.pathname.match(regex);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
matchesTags = (route: any) => {
|
||||||
|
const url = this.matchedUrl();
|
||||||
|
const regex = new RegExp(`${url}/tag/.+/info`);
|
||||||
|
return route.location.pathname.match(regex);
|
||||||
|
};
|
||||||
|
|
||||||
matchesCode = (route: any) => {
|
matchesCode = (route: any) => {
|
||||||
const url = this.matchedUrl();
|
const url = this.matchedUrl();
|
||||||
const regex = new RegExp(`${url}(/code)/.*`);
|
const regex = new RegExp(`${url}(/code)/.*`);
|
||||||
@@ -245,6 +253,15 @@ class RepositoryRoot extends React.Component<Props> {
|
|||||||
render={() => <BranchesOverview repository={repository} baseUrl={`${url}/branch`} />}
|
render={() => <BranchesOverview repository={repository} baseUrl={`${url}/branch`} />}
|
||||||
/>
|
/>
|
||||||
<Route path={`${url}/branches/create`} render={() => <CreateBranch repository={repository} />} />
|
<Route path={`${url}/branches/create`} render={() => <CreateBranch repository={repository} />} />
|
||||||
|
<Route
|
||||||
|
path={`${url}/tag/:tag`}
|
||||||
|
render={() => <TagRoot repository={repository} baseUrl={`${url}/tag`} />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={`${url}/tags`}
|
||||||
|
exact={true}
|
||||||
|
render={() => <TagsOverview repository={repository} baseUrl={`${url}/tag`} />}
|
||||||
|
/>
|
||||||
<ExtensionPoint name="repository.route" props={extensionProps} renderAll={true} />
|
<ExtensionPoint name="repository.route" props={extensionProps} renderAll={true} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</PrimaryContentColumn>
|
</PrimaryContentColumn>
|
||||||
@@ -267,6 +284,16 @@ class RepositoryRoot extends React.Component<Props> {
|
|||||||
activeOnlyWhenExact={false}
|
activeOnlyWhenExact={false}
|
||||||
title={t("repositoryRoot.menu.branchesNavLink")}
|
title={t("repositoryRoot.menu.branchesNavLink")}
|
||||||
/>
|
/>
|
||||||
|
<RepositoryNavLink
|
||||||
|
repository={repository}
|
||||||
|
linkName="tags"
|
||||||
|
to={`${url}/tags/`}
|
||||||
|
icon="fas fa-tags"
|
||||||
|
label={t("repositoryRoot.menu.tagsNavLink")}
|
||||||
|
activeWhenMatch={this.matchesTags}
|
||||||
|
activeOnlyWhenExact={false}
|
||||||
|
title={t("repositoryRoot.menu.tagsNavLink")}
|
||||||
|
/>
|
||||||
<RepositoryNavLink
|
<RepositoryNavLink
|
||||||
repository={repository}
|
repository={repository}
|
||||||
linkName={this.getCodeLinkname()}
|
linkName={this.getCodeLinkname()}
|
||||||
|
|||||||
49
scm-ui/ui-webapp/src/repos/tags/components/TagDetail.tsx
Normal file
49
scm-ui/ui-webapp/src/repos/tags/components/TagDetail.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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 { useTranslation } from "react-i18next";
|
||||||
|
import { Tag } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tag?: Tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TagDetail: FC<Props> = ({ tag }) => {
|
||||||
|
const [t] = useTranslation("repos");
|
||||||
|
|
||||||
|
if (!tag) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="media">
|
||||||
|
<div className="media-content subtitle">
|
||||||
|
<strong>{t("tag.name")}</strong> {tag?.name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagDetail;
|
||||||
60
scm-ui/ui-webapp/src/repos/tags/components/TagRow.tsx
Normal file
60
scm-ui/ui-webapp/src/repos/tags/components/TagRow.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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 { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { Tag } from "@scm-manager/ui-types";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { DateFromNow } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tag: Tag;
|
||||||
|
baseUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Created = styled.span`
|
||||||
|
margin-left: 1rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TagRow: FC<Props> = ({ tag, baseUrl }) => {
|
||||||
|
const [t] = useTranslation("repos");
|
||||||
|
|
||||||
|
const to = `${baseUrl}/${encodeURIComponent(tag.name)}/info`;
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Link 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>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagRow;
|
||||||
60
scm-ui/ui-webapp/src/repos/tags/components/TagTable.tsx
Normal file
60
scm-ui/ui-webapp/src/repos/tags/components/TagTable.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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 { Tag } from "@scm-manager/ui-types";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import TagRow from "./TagRow";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
baseUrl: string;
|
||||||
|
tags: Tag[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const TagTable: FC<Props> = ({ baseUrl, tags }) => {
|
||||||
|
const [t] = useTranslation("repos");
|
||||||
|
|
||||||
|
const renderRow = () => {
|
||||||
|
let rowContent = null;
|
||||||
|
if (tags) {
|
||||||
|
rowContent = tags.map((tag, index) => {
|
||||||
|
return <TagRow key={index} baseUrl={baseUrl} tag={tag} />;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rowContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table className="card-table table is-hoverable is-fullwidth is-word-break">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{t("tags.table.tags")}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>{renderRow()}</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagTable;
|
||||||
54
scm-ui/ui-webapp/src/repos/tags/components/TagView.tsx
Normal file
54
scm-ui/ui-webapp/src/repos/tags/components/TagView.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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, Tag } from "@scm-manager/ui-types";
|
||||||
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
|
import TagDetail from "./TagDetail";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
repository: Repository;
|
||||||
|
tag?: Tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TagView: FC<Props> = ({ repository, tag }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TagDetail tag={tag} />
|
||||||
|
<hr />
|
||||||
|
<div className="content">
|
||||||
|
<ExtensionPoint
|
||||||
|
name="repos.tag-details.information"
|
||||||
|
renderAll={true}
|
||||||
|
props={{
|
||||||
|
repository,
|
||||||
|
tag
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagView;
|
||||||
98
scm-ui/ui-webapp/src/repos/tags/container/TagRoot.tsx
Normal file
98
scm-ui/ui-webapp/src/repos/tags/container/TagRoot.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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, useEffect, useState } from "react";
|
||||||
|
import { Link, Repository, Tag } from "@scm-manager/ui-types";
|
||||||
|
import { Redirect, Switch, useLocation, useRouteMatch, Route } from "react-router-dom";
|
||||||
|
import { apiClient, ErrorNotification, Loading } from "@scm-manager/ui-components";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import TagView from "../components/TagView";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
repository: Repository;
|
||||||
|
baseUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TagRoot: FC<Props> = ({ repository, baseUrl }) => {
|
||||||
|
const match = useRouteMatch();
|
||||||
|
const [tags, setTags] = useState<Tag[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<Error | undefined>(undefined);
|
||||||
|
const [tag, setTag] = useState<Tag>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const link = (repository._links?.tags as Link)?.href;
|
||||||
|
if (link) {
|
||||||
|
setLoading(true);
|
||||||
|
apiClient
|
||||||
|
.get(link)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(r => setTags(r._embedded.tags))
|
||||||
|
.catch(setError);
|
||||||
|
}
|
||||||
|
}, [repository]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const tagName = match?.params?.tag;
|
||||||
|
const link = tags && tags.length > 0 && (tags.find(tag => tag.name === tagName)?._links.self as Link).href;
|
||||||
|
if (link) {
|
||||||
|
apiClient
|
||||||
|
.get(link)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(setTag)
|
||||||
|
.then(() => setLoading(false))
|
||||||
|
.catch(setError);
|
||||||
|
}
|
||||||
|
}, [tags]);
|
||||||
|
|
||||||
|
const stripEndingSlash = (url: string) => {
|
||||||
|
if (url.endsWith("/")) {
|
||||||
|
return url.substring(0, url.length - 1);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
};
|
||||||
|
|
||||||
|
const matchedUrl = () => {
|
||||||
|
return stripEndingSlash(match.url);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <ErrorNotification error={error} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading || !tags) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = matchedUrl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Switch>
|
||||||
|
<Redirect exact from={url} to={`${url}/info`} />
|
||||||
|
<Route path={`${url}/info`} component={() => <TagView repository={repository} tag={tag} />} />
|
||||||
|
</Switch>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagRoot;
|
||||||
80
scm-ui/ui-webapp/src/repos/tags/container/TagsOverview.tsx
Normal file
80
scm-ui/ui-webapp/src/repos/tags/container/TagsOverview.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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, useEffect, useState } from "react";
|
||||||
|
import { Repository, Tag, Link } from "@scm-manager/ui-types";
|
||||||
|
import { ErrorNotification, Loading, Notification, Subtitle, apiClient } from "@scm-manager/ui-components";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import orderTags from "../orderTags";
|
||||||
|
import TagTable from "../components/TagTable";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
repository: Repository;
|
||||||
|
baseUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TagsOverview: FC<Props> = ({ repository, baseUrl }) => {
|
||||||
|
const [t] = useTranslation("repos");
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<Error | undefined>(undefined);
|
||||||
|
const [tags, setTags] = useState<Tag[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const link = (repository._links?.tags as Link)?.href;
|
||||||
|
if (link) {
|
||||||
|
setLoading(true);
|
||||||
|
apiClient
|
||||||
|
.get(link)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(r => setTags(r._embedded.tags))
|
||||||
|
.then(() => setLoading(false))
|
||||||
|
.catch(setError);
|
||||||
|
}
|
||||||
|
}, [repository]);
|
||||||
|
|
||||||
|
const renderTagsTable = () => {
|
||||||
|
if (!loading && tags && tags.length > 0) {
|
||||||
|
orderTags(tags);
|
||||||
|
return <TagTable baseUrl={baseUrl} tags={tags} />;
|
||||||
|
}
|
||||||
|
return <Notification type="info">{t("tags.overview.noTags")}</Notification>;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <ErrorNotification error={error} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Subtitle subtitle={t("tags.overview.title")} />
|
||||||
|
{renderTagsTable()}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagsOverview;
|
||||||
52
scm-ui/ui-webapp/src/repos/tags/orderTags.test.ts
Normal file
52
scm-ui/ui-webapp/src/repos/tags/orderTags.test.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 orderTags from "./orderTags";
|
||||||
|
|
||||||
|
const tag1 = {
|
||||||
|
name: "tag1",
|
||||||
|
revision: "revision1",
|
||||||
|
date: new Date(2020, 1, 1),
|
||||||
|
_links: {}
|
||||||
|
};
|
||||||
|
const tag2 = {
|
||||||
|
name: "tag2",
|
||||||
|
revision: "revision2",
|
||||||
|
date: new Date(2020, 1, 3),
|
||||||
|
_links: {}
|
||||||
|
};
|
||||||
|
const tag3 = {
|
||||||
|
name: "tag3",
|
||||||
|
revision: "revision3",
|
||||||
|
date: new Date(2020, 1, 2),
|
||||||
|
_links: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("order tags", () => {
|
||||||
|
it("should order tags descending by date", () => {
|
||||||
|
const tags = [tag1, tag2, tag3];
|
||||||
|
orderTags(tags);
|
||||||
|
expect(tags).toEqual([tag2, tag3, tag1]);
|
||||||
|
});
|
||||||
|
});
|
||||||
32
scm-ui/ui-webapp/src/repos/tags/orderTags.ts
Normal file
32
scm-ui/ui-webapp/src/repos/tags/orderTags.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// sort tags by date beginning with latest first
|
||||||
|
import { Tag } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
export default function orderTags(tags: Tag[]) {
|
||||||
|
tags.sort((a, b) => {
|
||||||
|
return new Date(b.date) - new Date(a.date);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user