Merge branch 'develop' into feature/import_git_from_url

This commit is contained in:
Eduard Heimbuch
2020-11-26 14:01:19 +01:00
66 changed files with 1045 additions and 399 deletions

View File

@@ -26,21 +26,45 @@ import { Branch, Repository } from "@scm-manager/ui-types";
import { WithTranslation, withTranslation } from "react-i18next";
import BranchButtonGroup from "./BranchButtonGroup";
import DefaultBranchTag from "./DefaultBranchTag";
import { DateFromNow } from "@scm-manager/ui-components";
import styled from "styled-components";
type Props = WithTranslation & {
repository: Repository;
branch: Branch;
};
const FlexRow = styled.div`
display: flex;
align-items: center;
flex-wrap: wrap;
`;
const Created = styled.div`
margin-left: 0.5rem;
font-size: 0.8rem;
`;
const Label = styled.strong`
margin-right: 0.3rem;
`;
const Date = styled(DateFromNow)`
font-size: 0.8rem;
`;
class BranchDetail extends React.Component<Props> {
render() {
const { repository, branch, t } = this.props;
return (
<div className="media">
<div className="media-content subtitle">
<strong>{t("branch.name")}</strong> {branch.name} <DefaultBranchTag defaultBranch={branch.defaultBranch} />
</div>
<FlexRow className="media-content subtitle">
<Label>{t("branch.name")}</Label> {branch.name} <DefaultBranchTag defaultBranch={branch.defaultBranch} />
<Created className="is-ellipsis-overflow">
{t("tags.overview.created")} <Date date={branch.lastCommitDate} className="has-text-grey" />
</Created>
</FlexRow>
<div className="media-right">
<BranchButtonGroup repository={repository} branch={branch} />
</div>

View File

@@ -25,8 +25,9 @@ import React, { FC } from "react";
import { Link as ReactLink } from "react-router-dom";
import { Branch, Link } from "@scm-manager/ui-types";
import DefaultBranchTag from "./DefaultBranchTag";
import { Icon } from "@scm-manager/ui-components";
import { DateFromNow, Icon } from "@scm-manager/ui-components";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
type Props = {
baseUrl: string;
@@ -34,6 +35,11 @@ type Props = {
onDelete: (branch: Branch) => void;
};
const Created = styled.span`
margin-left: 1rem;
font-size: 0.8rem;
`;
const BranchRow: FC<Props> = ({ baseUrl, branch, onDelete }) => {
const to = `${baseUrl}/${encodeURIComponent(branch.name)}/info`;
const [t] = useTranslation("repos");
@@ -56,6 +62,11 @@ const BranchRow: FC<Props> = ({ baseUrl, branch, onDelete }) => {
{branch.name}
<DefaultBranchTag defaultBranch={branch.defaultBranch} />
</ReactLink>
{branch.lastCommitDate && (
<Created className="has-text-grey is-ellipsis-overflow">
{t("branches.table.lastCommit")} <DateFromNow date={branch.lastCommitDate} />
</Created>
)}
</td>
<td className="is-darker">{deleteButton}</td>
</tr>

View File

@@ -30,10 +30,11 @@ import { apiClient, ConfirmAlert, ErrorNotification } from "@scm-manager/ui-comp
type Props = {
baseUrl: string;
branches: Branch[];
type: string;
fetchBranches: () => void;
};
const BranchTable: FC<Props> = ({ baseUrl, branches, fetchBranches }) => {
const BranchTable: FC<Props> = ({ baseUrl, branches, type, fetchBranches }) => {
const [t] = useTranslation("repos");
const [showConfirmAlert, setShowConfirmAlert] = useState(false);
const [error, setError] = useState<Error | undefined>();
@@ -92,7 +93,7 @@ const BranchTable: FC<Props> = ({ baseUrl, branches, fetchBranches }) => {
<table className="card-table table is-hoverable is-fullwidth is-word-break">
<thead>
<tr>
<th>{t("branches.table.branches")}</th>
<th>{t(`branches.table.branches.${type}`)}</th>
</tr>
</thead>
<tbody>{renderRow()}</tbody>

View File

@@ -84,7 +84,28 @@ class BranchesOverview extends React.Component<Props> {
const { baseUrl, branches, repository, fetchBranches, t } = this.props;
if (branches && branches.length > 0) {
orderBranches(branches);
return <BranchTable baseUrl={baseUrl} branches={branches} fetchBranches={() => fetchBranches(repository)} />;
const staleBranches = branches.filter(b => b.stale);
const activeBranches = branches.filter(b => !b.stale);
return (
<>
{activeBranches.length > 0 && (
<BranchTable
baseUrl={baseUrl}
type={"active"}
branches={activeBranches}
fetchBranches={() => fetchBranches(repository)}
/>
)}
{staleBranches.length > 0 && (
<BranchTable
baseUrl={baseUrl}
type={"stale"}
branches={staleBranches}
fetchBranches={() => fetchBranches(repository)}
/>
)}
</>
);
}
return <Notification type="info">{t("branches.overview.noBranches")}</Notification>;
}

View File

@@ -47,9 +47,14 @@ const developBranch = {
revision: "revision5",
defaultBranch: false
};
const mainBranch = {
name: "main",
revision: "revision6",
defaultBranch: false
};
const masterBranch = {
name: "master",
revision: "revision6",
revision: "revision7",
defaultBranch: false
};
@@ -66,10 +71,10 @@ describe("order branches", () => {
expect(branches).toEqual([branch3, branch1, branch2]);
});
it("should order special branches as follows: master > default > develop", () => {
const branches = [defaultBranch, developBranch, masterBranch];
it("should order special branches as follows: main > master > default > develop", () => {
const branches = [defaultBranch, mainBranch, developBranch, masterBranch];
orderBranches(branches);
expect(branches).toEqual([masterBranch, defaultBranch, developBranch]);
expect(branches).toEqual([mainBranch, masterBranch, defaultBranch, developBranch]);
});
it("should order special branches but starting with defaultBranch", () => {

View File

@@ -32,10 +32,14 @@ export function orderBranches(branches: Branch[]) {
return -20;
} else if (!a.defaultBranch && b.defaultBranch) {
return 20;
} else if (a.name === "master" && b.name !== "master") {
} else if (a.name === "main" && b.name !== "main") {
return -10;
} else if (a.name !== "master" && b.name === "master") {
} else if (a.name !== "main" && b.name === "main") {
return 10;
} else if (a.name === "master" && b.name !== "master") {
return -9;
} else if (a.name !== "master" && b.name === "master") {
return 9;
} else if (a.name === "default" && b.name !== "default") {
return -10;
} else if (a.name !== "default" && b.name === "default") {

View File

@@ -23,21 +23,25 @@
*/
import React from "react";
import { Link } from "react-router-dom";
import { CardColumnGroup, RepositoryEntry } from "@scm-manager/ui-components";
import { CardColumnGroup, Icon, RepositoryEntry } from "@scm-manager/ui-components";
import { RepositoryGroup } from "@scm-manager/ui-types";
import { Icon } from "@scm-manager/ui-components";
import { WithTranslation, withTranslation } from "react-i18next";
import styled from "styled-components";
type Props = WithTranslation & {
group: RepositoryGroup;
};
const SizedIcon = styled(Icon)`
font-size: 1.33rem;
`;
class RepositoryGroupEntry extends React.Component<Props> {
render() {
const { group, t } = this.props;
const settingsLink = group.namespace?._links?.permissions && (
<Link to={`/namespace/${group.name}/settings`}>
<Icon color={"is-link"} name={"cog"} title={t("repositoryOverview.settings.tooltip")} />
<SizedIcon color={"is-link"} name={"cog"} title={t("repositoryOverview.settings.tooltip")} />
</Link>
);
const namespaceHeader = (

View File

@@ -102,8 +102,12 @@ class Overview extends React.Component<Props> {
}
};
getNamespaceFilterPlaceholder = () => {
return this.props.t("overview.allNamespaces");
};
namespaceSelected = (newNamespace: string) => {
if (newNamespace === "") {
if (newNamespace === this.getNamespaceFilterPlaceholder()) {
this.props.history.push("/repos/");
} else {
this.props.history.push(`/repos/${newNamespace}/`);
@@ -112,8 +116,10 @@ class Overview extends React.Component<Props> {
render() {
const { error, loading, showCreateButton, namespace, namespaces, t } = this.props;
const namespacesToRender = namespaces ? ["", ...namespaces._embedded.namespaces.map(n => n.namespace).sort()] : [];
const namespaceFilterPlaceholder = this.getNamespaceFilterPlaceholder();
const namespacesToRender = namespaces
? [namespaceFilterPlaceholder, ...namespaces._embedded.namespaces.map(n => n.namespace).sort()]
: [];
return (
<Page title={t("overview.title")} subtitle={t("overview.subtitle")} loading={loading} error={error}>
@@ -127,6 +133,7 @@ class Overview extends React.Component<Props> {
link="repos"
label={t("overview.createButton")}
testId="repository-overview"
searchPlaceholder={t("overview.searchRepository")}
/>
</PageActions>
</Page>