mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-12-21 15:59:48 +01:00
Add settings icon to namespace group header
This commit is contained in:
@@ -27,7 +27,7 @@ import classNames from "classnames";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
name: string;
|
name: ReactNode;
|
||||||
url?: string;
|
url?: string;
|
||||||
elements: ReactNode[];
|
elements: ReactNode[];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,5 +58,6 @@ export type NamespaceCollection = {
|
|||||||
|
|
||||||
export type RepositoryGroup = {
|
export type RepositoryGroup = {
|
||||||
name: string;
|
name: string;
|
||||||
|
namespace: Namespace;
|
||||||
repositories: Repository[];
|
repositories: Repository[];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,8 +22,10 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
import { CardColumnGroup, RepositoryEntry } from "@scm-manager/ui-components";
|
import { CardColumnGroup, RepositoryEntry } from "@scm-manager/ui-components";
|
||||||
import { RepositoryGroup } from "@scm-manager/ui-types";
|
import { RepositoryGroup } from "@scm-manager/ui-types";
|
||||||
|
import { Icon } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
group: RepositoryGroup;
|
group: RepositoryGroup;
|
||||||
@@ -32,10 +34,23 @@ type Props = {
|
|||||||
class RepositoryGroupEntry extends React.Component<Props> {
|
class RepositoryGroupEntry extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { group } = this.props;
|
const { group } = this.props;
|
||||||
|
const settingsLink = group.namespace?._links?.permissions && (
|
||||||
|
<Link to={`/namespace/${group.name}/settings`}>
|
||||||
|
<Icon color={"is-link"} name={"cog"} />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
const namespaceHeader = (
|
||||||
|
<>
|
||||||
|
<Link to={`/repos/${group.name}/`} className={"has-text-dark"}>
|
||||||
|
{group.name}
|
||||||
|
</Link>{" "}
|
||||||
|
{settingsLink}
|
||||||
|
</>
|
||||||
|
);
|
||||||
const entries = group.repositories.map((repository, index) => {
|
const entries = group.repositories.map((repository, index) => {
|
||||||
return <RepositoryEntry repository={repository} key={index} />;
|
return <RepositoryEntry repository={repository} key={index} />;
|
||||||
});
|
});
|
||||||
return <CardColumnGroup name={group.name} url={`/repos/${group.name}/`} elements={entries} />;
|
return <CardColumnGroup name={namespaceHeader} elements={entries} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,20 +23,21 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { Repository } from "@scm-manager/ui-types";
|
import { NamespaceCollection, Repository } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
import groupByNamespace from "./groupByNamespace";
|
import groupByNamespace from "./groupByNamespace";
|
||||||
import RepositoryGroupEntry from "./RepositoryGroupEntry";
|
import RepositoryGroupEntry from "./RepositoryGroupEntry";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repositories: Repository[];
|
repositories: Repository[];
|
||||||
|
namespaces: NamespaceCollection;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RepositoryList extends React.Component<Props> {
|
class RepositoryList extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { repositories } = this.props;
|
const { repositories, namespaces } = this.props;
|
||||||
|
|
||||||
const groups = groupByNamespace(repositories);
|
const groups = groupByNamespace(repositories, namespaces);
|
||||||
return (
|
return (
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{groups.map(group => {
|
{groups.map(group => {
|
||||||
|
|||||||
@@ -73,21 +73,29 @@ it("should group the repositories by their namespace", () => {
|
|||||||
hitchhikerHeartOfGold,
|
hitchhikerHeartOfGold,
|
||||||
hitchhikerPuzzle42
|
hitchhikerPuzzle42
|
||||||
];
|
];
|
||||||
|
const namespaces = {
|
||||||
|
_embedded: {
|
||||||
|
namespaces: [{ namespace: "hitchhiker" }, { namespace: "slarti" }, { namespace: "zaphod" }]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const expected = [
|
const expected = [
|
||||||
{
|
{
|
||||||
name: "hitchhiker",
|
name: "hitchhiker",
|
||||||
|
namespace: { namespace: "hitchhiker" },
|
||||||
repositories: [hitchhikerHeartOfGold, hitchhikerPuzzle42, hitchhikerRestand]
|
repositories: [hitchhikerHeartOfGold, hitchhikerPuzzle42, hitchhikerRestand]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "slarti",
|
name: "slarti",
|
||||||
|
namespace: { namespace: "slarti" },
|
||||||
repositories: [slartiFjords, slartiBlueprintsFjords]
|
repositories: [slartiFjords, slartiBlueprintsFjords]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "zaphod",
|
name: "zaphod",
|
||||||
|
namespace: { namespace: "zaphod" },
|
||||||
repositories: [zaphodMarvinFirmware]
|
repositories: [zaphodMarvinFirmware]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(groupByNamespace(repositories)).toEqual(expected);
|
expect(groupByNamespace(repositories, namespaces)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,17 +22,22 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Repository, RepositoryGroup } from "@scm-manager/ui-types";
|
import { NamespaceCollection, Repository, RepositoryGroup } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
export default function groupByNamespace(repositories: Repository[]): RepositoryGroup[] {
|
export default function groupByNamespace(
|
||||||
|
repositories: Repository[],
|
||||||
|
namespaces: NamespaceCollection
|
||||||
|
): RepositoryGroup[] {
|
||||||
const groups = {};
|
const groups = {};
|
||||||
for (const repository of repositories) {
|
for (const repository of repositories) {
|
||||||
const groupName = repository.namespace;
|
const groupName = repository.namespace;
|
||||||
|
|
||||||
let group = groups[groupName];
|
let group = groups[groupName];
|
||||||
if (!group) {
|
if (!group) {
|
||||||
|
const namespace = findNamespace(namespaces, groupName);
|
||||||
group = {
|
group = {
|
||||||
name: groupName,
|
name: groupName,
|
||||||
|
namespace: namespace,
|
||||||
repositories: []
|
repositories: []
|
||||||
};
|
};
|
||||||
groups[groupName] = group;
|
groups[groupName] = group;
|
||||||
@@ -58,3 +63,7 @@ function sortByName(a, b) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findNamespace(namespaces: NamespaceCollection, namespaceToFind: string) {
|
||||||
|
return namespaces._embedded.namespaces.filter(namespace => namespace.namespace === namespaceToFind)[0];
|
||||||
|
}
|
||||||
|
|||||||
@@ -133,12 +133,12 @@ class Overview extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderRepositoryList() {
|
renderRepositoryList() {
|
||||||
const { collection, page, location, t } = this.props;
|
const { collection, page, location, namespaces, t } = this.props;
|
||||||
|
|
||||||
if (collection._embedded && collection._embedded.repositories.length > 0) {
|
if (collection._embedded && collection._embedded.repositories.length > 0) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RepositoryList repositories={collection._embedded.repositories} />
|
<RepositoryList repositories={collection._embedded.repositories} namespaces={namespaces} />
|
||||||
<LinkPaginator collection={collection} page={page} filter={urls.getQueryStringFromLocation(location)} />
|
<LinkPaginator collection={collection} page={page} filter={urls.getQueryStringFromLocation(location)} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user