mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-07 08:02:09 +01:00
Add an extension point for contributor rows in contributor table
Co-authored-by: Rene Pfeuffer<rene.pfeuffer@cloudogu.com>
This commit is contained in:
2
gradle/changelog/add-timestamp-first-push.yaml
Normal file
2
gradle/changelog/add-timestamp-first-push.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: added
|
||||
description: Extension point for contributor row in contributor table
|
||||
49
scm-ui/ui-components/src/repos/changesets/Contributor.tsx
Normal file
49
scm-ui/ui-components/src/repos/changesets/Contributor.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2020 - present Cloudogu GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { Person } from "@scm-manager/ui-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { extensionPoints, useBinder } from "@scm-manager/ui-extensions";
|
||||
import ContributorAvatar from "./ContributorAvatar";
|
||||
|
||||
const Contributor: FC<{ person: Person }> = ({ person }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
const binder = useBinder();
|
||||
const avatarFactory = binder.getExtension<extensionPoints.AvatarFactory>("avatar.factory");
|
||||
let prefix = null;
|
||||
if (avatarFactory) {
|
||||
const avatar = avatarFactory(person);
|
||||
if (avatar) {
|
||||
prefix = (
|
||||
<>
|
||||
<ContributorAvatar src={avatar} alt={person.name} />{" "}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
if (person.mail) {
|
||||
return (
|
||||
<a href={"mailto:" + person.mail} title={t("changeset.contributors.mailto") + " " + person.mail}>
|
||||
{prefix}
|
||||
{person.name}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return <>{person.name}</>;
|
||||
};
|
||||
|
||||
export default Contributor;
|
||||
33
scm-ui/ui-components/src/repos/changesets/ContributorRow.tsx
Normal file
33
scm-ui/ui-components/src/repos/changesets/ContributorRow.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 - present Cloudogu GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const SizedTd = styled.td`
|
||||
width: 10rem;
|
||||
`;
|
||||
|
||||
const ContributorRow: FC<{ label: string }> = ({ label, children }) => {
|
||||
return (
|
||||
<tr key={label}>
|
||||
<SizedTd>{label}:</SizedTd>
|
||||
<td className="is-ellipsis-overflow m-0">{children}</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContributorRow;
|
||||
@@ -31,3 +31,5 @@ export { default as ChangesetTagsCollapsed } from "./ChangesetTagsCollapsed";
|
||||
export { default as ContributorAvatar } from "./ContributorAvatar";
|
||||
export { default as SignatureIcon } from "./SignatureIcon";
|
||||
export { default as SingleChangeset } from "./SingleChangeset";
|
||||
export { default as Contributor } from "./Contributor";
|
||||
export { default as ContributorRow } from "./ContributorRow";
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import React, { ComponentProps, ComponentType, FC, ReactNode } from "react";
|
||||
import React, { ComponentProps, ComponentType, ReactNode } from "react";
|
||||
import {
|
||||
Branch,
|
||||
BranchDetails,
|
||||
@@ -305,6 +305,11 @@ export type ChangesetsAuthorSuffix = RenderableExtensionPointDefinition<
|
||||
{ changeset: Changeset }
|
||||
>;
|
||||
|
||||
export type ChangesetsContributorTableRow = RenderableExtensionPointDefinition<
|
||||
"changesets.contributor.table.row",
|
||||
{ changeset: Changeset }
|
||||
>;
|
||||
|
||||
export type GroupNavigation = RenderableExtensionPointDefinition<"group.navigation", { group: Group; url: string }>;
|
||||
|
||||
export type GroupRoute = RenderableExtensionPointDefinition<"group.route", { group: Group; url: string }>;
|
||||
|
||||
@@ -15,46 +15,15 @@
|
||||
*/
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { Changeset, Person } from "@scm-manager/ui-types";
|
||||
import styled from "styled-components";
|
||||
import { Changeset } from "@scm-manager/ui-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { extensionPoints, useBinder } from "@scm-manager/ui-extensions";
|
||||
import { CommaSeparatedList, ContributorAvatar } from "@scm-manager/ui-components";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
import { CommaSeparatedList, Contributor, ContributorRow } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
changeset: Changeset;
|
||||
};
|
||||
|
||||
const SizedTd = styled.td`
|
||||
width: 10rem;
|
||||
`;
|
||||
|
||||
const Contributor: FC<{ person: Person }> = ({ person }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
const binder = useBinder();
|
||||
const avatarFactory = binder.getExtension<extensionPoints.AvatarFactory>("avatar.factory");
|
||||
let prefix = null;
|
||||
if (avatarFactory) {
|
||||
const avatar = avatarFactory(person);
|
||||
if (avatar) {
|
||||
prefix = (
|
||||
<>
|
||||
<ContributorAvatar src={avatar} alt={person.name} />{" "}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
if (person.mail) {
|
||||
return (
|
||||
<a href={"mailto:" + person.mail} title={t("changeset.contributors.mailto") + " " + person.mail}>
|
||||
{prefix}
|
||||
{person.name}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return <>{person.name}</>;
|
||||
};
|
||||
|
||||
const getUnique = (items: string[]) =>
|
||||
Object.keys(
|
||||
items.reduce((result, item) => {
|
||||
@@ -72,11 +41,11 @@ const ContributorTable: FC<Props> = ({ changeset }) => {
|
||||
if (!changeset.contributors) {
|
||||
return [];
|
||||
}
|
||||
return getUnique(changeset.contributors.map(contributor => contributor.type));
|
||||
return getUnique(changeset.contributors.map((contributor) => contributor.type));
|
||||
};
|
||||
|
||||
const getPersonsByContributorType = (type: string) => {
|
||||
return changeset.contributors?.filter(contributor => contributor.type === type).map(t => t.person);
|
||||
return changeset.contributors?.filter((contributor) => contributor.type === type).map((t) => t.person);
|
||||
};
|
||||
|
||||
const getContributorsByType = () => {
|
||||
@@ -84,31 +53,27 @@ const ContributorTable: FC<Props> = ({ changeset }) => {
|
||||
|
||||
const personsByContributorType = [];
|
||||
for (const type of availableContributorTypes) {
|
||||
personsByContributorType.push({ type, persons: getPersonsByContributorType(type) });
|
||||
personsByContributorType.push({ type, contributors: getPersonsByContributorType(type) });
|
||||
}
|
||||
return personsByContributorType;
|
||||
};
|
||||
|
||||
return (
|
||||
<table>
|
||||
<tr>
|
||||
<SizedTd>{t("changeset.contributor.type.author")}:</SizedTd>
|
||||
<td>
|
||||
<Contributor person={changeset.author} />
|
||||
</td>
|
||||
</tr>
|
||||
{getContributorsByType().map(contributor => (
|
||||
<tr key={contributor.type}>
|
||||
<SizedTd>{t("changeset.contributor.type." + contributor.type)}:</SizedTd>
|
||||
<td className="is-ellipsis-overflow m-0">
|
||||
<CommaSeparatedList>
|
||||
{contributor.persons?.map(person => (
|
||||
<Contributor key={person.name} person={person} />
|
||||
))}
|
||||
</CommaSeparatedList>
|
||||
</td>
|
||||
</tr>
|
||||
<ContributorRow label={t("changeset.contributor.type.author")}>
|
||||
<Contributor person={changeset.author} />
|
||||
</ContributorRow>
|
||||
|
||||
{getContributorsByType().map((contribution) => (
|
||||
<ContributorRow key={contribution.type} label={t("changeset.contributor.type." + contribution.type)}>
|
||||
<CommaSeparatedList>
|
||||
{contribution.contributors?.map((contributor) => (
|
||||
<Contributor key={contributor.name} person={contributor} />
|
||||
))}
|
||||
</CommaSeparatedList>
|
||||
</ContributorRow>
|
||||
))}
|
||||
<ExtensionPoint name="changesets.contributor.table.row" props={{ changeset }} renderAll={true} />
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user