mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-15 09:46:16 +01:00
refactor UI
This commit is contained in:
@@ -25,12 +25,10 @@ import React, { FC, useEffect, useState } from "react";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { Repository, RepositoryType, RepositoryImport } from "@scm-manager/ui-types";
|
import { Repository, RepositoryImport, RepositoryType } from "@scm-manager/ui-types";
|
||||||
import { Checkbox, InputField, Level, Select, SubmitButton, Textarea } from "@scm-manager/ui-components";
|
import { Checkbox, InputField, Level, Select, SubmitButton, Textarea } from "@scm-manager/ui-components";
|
||||||
import * as validator from "./repositoryValidation";
|
import * as validator from "./repositoryValidation";
|
||||||
import { CUSTOM_NAMESPACE_STRATEGY } from "../../modules/repos";
|
import { CUSTOM_NAMESPACE_STRATEGY } from "../../modules/repos";
|
||||||
import { useLocation } from "react-router-dom";
|
|
||||||
import RepositoryFormSwitcher from "./RepositoryFormSwitcher";
|
|
||||||
|
|
||||||
const CheckboxWrapper = styled.div`
|
const CheckboxWrapper = styled.div`
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
@@ -63,6 +61,7 @@ type Props = {
|
|||||||
namespaceStrategy?: string;
|
namespaceStrategy?: string;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
indexResources?: any;
|
indexResources?: any;
|
||||||
|
creationMode?: "CREATE" | "IMPORT";
|
||||||
};
|
};
|
||||||
|
|
||||||
type RepositoryCreation = Repository & {
|
type RepositoryCreation = Repository & {
|
||||||
@@ -77,7 +76,8 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
repositoryTypes,
|
repositoryTypes,
|
||||||
namespaceStrategy,
|
namespaceStrategy,
|
||||||
loading,
|
loading,
|
||||||
indexResources
|
indexResources,
|
||||||
|
creationMode
|
||||||
}) => {
|
}) => {
|
||||||
const [repo, setRepo] = useState<RepositoryCreation>({
|
const [repo, setRepo] = useState<RepositoryCreation>({
|
||||||
name: "",
|
name: "",
|
||||||
@@ -96,7 +96,6 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
const location = useLocation();
|
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -105,6 +104,9 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
}
|
}
|
||||||
}, [repository]);
|
}, [repository]);
|
||||||
|
|
||||||
|
const isImportMode = () => creationMode === "IMPORT";
|
||||||
|
const isCreateMode = () => creationMode === "CREATE";
|
||||||
|
|
||||||
const isValid = () => {
|
const isValid = () => {
|
||||||
return !(
|
return !(
|
||||||
namespaceValidationError ||
|
namespaceValidationError ||
|
||||||
@@ -112,16 +114,16 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
contactValidationError ||
|
contactValidationError ||
|
||||||
!repo.name ||
|
!repo.name ||
|
||||||
(namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY && !repo.namespace) ||
|
(namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY && !repo.namespace) ||
|
||||||
(isImportPage() && !importUrl)
|
(isImportMode() && !importUrl)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const submit = (event: React.FormEvent<HTMLFormElement>) => {
|
const submit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (isValid()) {
|
if (isValid()) {
|
||||||
if (importRepository && isImportPage()) {
|
if (importRepository && isImportMode()) {
|
||||||
importRepository({ ...repo, url: importUrl, username, password });
|
importRepository({ ...repo, url: importUrl, username, password });
|
||||||
} else if (createRepository && isCreatePage()) {
|
} else if (createRepository && isCreateMode()) {
|
||||||
createRepository(repo, initRepository);
|
createRepository(repo, initRepository);
|
||||||
} else if (modifyRepository) {
|
} else if (modifyRepository) {
|
||||||
modifyRepository(repo);
|
modifyRepository(repo);
|
||||||
@@ -151,20 +153,6 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveLocation = () => {
|
|
||||||
const currentUrl = location.pathname;
|
|
||||||
if (currentUrl.includes("/repos/create")) {
|
|
||||||
return "create";
|
|
||||||
}
|
|
||||||
if (currentUrl.includes("/repos/import")) {
|
|
||||||
return "import";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
const isImportPage = () => resolveLocation() === "import";
|
|
||||||
const isCreatePage = () => resolveLocation() === "create";
|
|
||||||
|
|
||||||
const createSelectOptions = (repositoryTypes?: RepositoryType[]) => {
|
const createSelectOptions = (repositoryTypes?: RepositoryType[]) => {
|
||||||
if (repositoryTypes) {
|
if (repositoryTypes) {
|
||||||
return repositoryTypes.map(repositoryType => {
|
return repositoryTypes.map(repositoryType => {
|
||||||
@@ -195,7 +183,7 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderUrlImportFields = () => {
|
const renderUrlImportFields = () => {
|
||||||
if (!isImportPage()) {
|
if (!isImportMode()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +252,7 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
helpText={t("help.typeHelpText")}
|
helpText={t("help.typeHelpText")}
|
||||||
/>
|
/>
|
||||||
</SelectWrapper>
|
</SelectWrapper>
|
||||||
{!isImportPage() && (
|
{!isImportMode() && (
|
||||||
<CheckboxWrapper>
|
<CheckboxWrapper>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={t("repositoryForm.initializeRepository")}
|
label={t("repositoryForm.initializeRepository")}
|
||||||
@@ -310,7 +298,7 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
const disabled = !isModifiable() && isEditMode();
|
const disabled = !isModifiable() && isEditMode();
|
||||||
|
|
||||||
const getSubmitButtonTranslationKey = () =>
|
const getSubmitButtonTranslationKey = () =>
|
||||||
isImportPage() ? "repositoryForm.submitImport" : "repositoryForm.submitCreate";
|
isImportMode() ? "repositoryForm.submitImport" : "repositoryForm.submitCreate";
|
||||||
|
|
||||||
const submitButton = disabled ? null : (
|
const submitButton = disabled ? null : (
|
||||||
<Level
|
<Level
|
||||||
@@ -320,9 +308,6 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!isEditMode() && (
|
|
||||||
<RepositoryFormSwitcher repository={repository} createMode={isImportPage() ? "IMPORT" : "CREATE"} />
|
|
||||||
)}
|
|
||||||
<form onSubmit={submit}>
|
<form onSubmit={submit}>
|
||||||
{renderCreateOnlyFields()}
|
{renderCreateOnlyFields()}
|
||||||
<InputField
|
<InputField
|
||||||
|
|||||||
@@ -25,51 +25,37 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Button, ButtonAddons, Level, Subtitle } from "@scm-manager/ui-components";
|
import { Button, ButtonAddons, Level } from "@scm-manager/ui-components";
|
||||||
import { Repository } from "@scm-manager/ui-types";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository?: Repository;
|
creationMode: "CREATE" | "IMPORT";
|
||||||
createMode: "CREATE" | "IMPORT";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const TopLevel = styled(Level)`
|
|
||||||
margin-top: -2rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SmallButton = styled(Button)`
|
const SmallButton = styled(Button)`
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const RepositoryFormSwitcher: FC<Props> = ({ repository, createMode }) => {
|
const TopLevel = styled(Level)`
|
||||||
|
margin-top: -2.75rem;
|
||||||
|
margin-bottom: 2.75rem !important; //TODO Try to remove important
|
||||||
|
height: 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RepositoryFormSwitcher: FC<Props> = ({ creationMode }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
|
|
||||||
const isImportMode = () => {
|
const isImportMode = () => {
|
||||||
return createMode === "IMPORT";
|
return creationMode === "IMPORT";
|
||||||
};
|
};
|
||||||
|
|
||||||
const isCreateMode = () => {
|
const isCreateMode = () => {
|
||||||
return createMode === "CREATE";
|
return creationMode === "CREATE";
|
||||||
};
|
|
||||||
|
|
||||||
const renderSubtitle = () => {
|
|
||||||
let subtitle;
|
|
||||||
if (repository) {
|
|
||||||
subtitle = "repositoryForm.subtitle";
|
|
||||||
} else if (isImportMode()) {
|
|
||||||
subtitle = "create.subtitle";
|
|
||||||
} else {
|
|
||||||
subtitle = "import.subtitle";
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Subtitle subtitle={t(subtitle)} />;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TopLevel
|
<TopLevel
|
||||||
left={renderSubtitle()}
|
|
||||||
right={
|
right={
|
||||||
<ButtonAddons>
|
<ButtonAddons>
|
||||||
<SmallButton
|
<SmallButton
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import {
|
|||||||
RepositoryImport,
|
RepositoryImport,
|
||||||
RepositoryType
|
RepositoryType
|
||||||
} from "@scm-manager/ui-types";
|
} from "@scm-manager/ui-types";
|
||||||
import { Loading, Page, Notification, Subtitle } from "@scm-manager/ui-components";
|
import { Loading, Notification, Page } from "@scm-manager/ui-components";
|
||||||
import {
|
import {
|
||||||
fetchRepositoryTypesIfNeeded,
|
fetchRepositoryTypesIfNeeded,
|
||||||
getFetchRepositoryTypesFailure,
|
getFetchRepositoryTypesFailure,
|
||||||
@@ -40,12 +40,14 @@ import {
|
|||||||
isFetchRepositoryTypesPending
|
isFetchRepositoryTypesPending
|
||||||
} from "../modules/repositoryTypes";
|
} from "../modules/repositoryTypes";
|
||||||
import RepositoryForm from "../components/form";
|
import RepositoryForm from "../components/form";
|
||||||
|
import RepositoryFormSwitcher from "../components/form/RepositoryFormSwitcher";
|
||||||
import {
|
import {
|
||||||
createRepo,
|
createRepo,
|
||||||
createRepoReset,
|
createRepoReset,
|
||||||
getCreateRepoFailure,
|
getCreateRepoFailure,
|
||||||
getImportRepoFailure,
|
getImportRepoFailure,
|
||||||
importRepoFromUrl,
|
importRepoFromUrl,
|
||||||
|
importRepoReset,
|
||||||
isCreateRepoPending,
|
isCreateRepoPending,
|
||||||
isImportRepoPending
|
isImportRepoPending
|
||||||
} from "../modules/repos";
|
} from "../modules/repos";
|
||||||
@@ -56,8 +58,11 @@ import {
|
|||||||
getNamespaceStrategies,
|
getNamespaceStrategies,
|
||||||
isFetchNamespaceStrategiesPending
|
isFetchNamespaceStrategiesPending
|
||||||
} from "../../admin/modules/namespaceStrategies";
|
} from "../../admin/modules/namespaceStrategies";
|
||||||
|
import { RouteComponentProps, withRouter } from "react-router-dom";
|
||||||
|
import { compose } from "redux";
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation &
|
||||||
|
RouteComponentProps & {
|
||||||
repositoryTypes: RepositoryType[];
|
repositoryTypes: RepositoryType[];
|
||||||
namespaceStrategies: NamespaceStrategies;
|
namespaceStrategies: NamespaceStrategies;
|
||||||
pageLoading: boolean;
|
pageLoading: boolean;
|
||||||
@@ -96,6 +101,34 @@ class AddRepository extends React.Component<Props> {
|
|||||||
history.push("/repo/" + repo.namespace + "/" + repo.name);
|
history.push("/repo/" + repo.namespace + "/" + repo.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
resolveLocation = () => {
|
||||||
|
const currentUrl = this.props.location.pathname;
|
||||||
|
if (currentUrl.includes("/repos/create")) {
|
||||||
|
return "create";
|
||||||
|
}
|
||||||
|
if (currentUrl.includes("/repos/import")) {
|
||||||
|
return "import";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
isImportPage = () => this.resolveLocation() === "import";
|
||||||
|
isCreatePage = () => this.resolveLocation() === "create";
|
||||||
|
|
||||||
|
getSubtitle = () => {
|
||||||
|
const { importLoading, t } = this.props;
|
||||||
|
let subtitle;
|
||||||
|
if (this.isCreatePage()) {
|
||||||
|
subtitle = t("create.subtitle");
|
||||||
|
} else if (!importLoading) {
|
||||||
|
subtitle = t("import.subtitle");
|
||||||
|
} else {
|
||||||
|
subtitle = t("import.pending.subtitle");
|
||||||
|
}
|
||||||
|
|
||||||
|
return subtitle;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
pageLoading,
|
pageLoading,
|
||||||
@@ -112,14 +145,21 @@ class AddRepository extends React.Component<Props> {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title={t("create.title")} loading={pageLoading} error={error} showContentOnError={true}>
|
<Page
|
||||||
|
title={t("create.title")}
|
||||||
|
subtitle={this.getSubtitle()}
|
||||||
|
loading={pageLoading}
|
||||||
|
error={error}
|
||||||
|
showContentOnError={true}
|
||||||
|
>
|
||||||
{importLoading ? (
|
{importLoading ? (
|
||||||
<>
|
<>
|
||||||
<Subtitle subtitle={t("import.pending.subtitle")}/>
|
|
||||||
<Notification type="info">{t("import.pending.infoText")}</Notification>
|
<Notification type="info">{t("import.pending.infoText")}</Notification>
|
||||||
<Loading />
|
<Loading />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
<>
|
||||||
|
{!error && <RepositoryFormSwitcher creationMode={this.isImportPage() ? "IMPORT" : "CREATE"} />}
|
||||||
<RepositoryForm
|
<RepositoryForm
|
||||||
repositoryTypes={repositoryTypes}
|
repositoryTypes={repositoryTypes}
|
||||||
loading={createLoading}
|
loading={createLoading}
|
||||||
@@ -131,7 +171,9 @@ class AddRepository extends React.Component<Props> {
|
|||||||
importRepoFromUrl(repoLink, repo, (repo: Repository) => this.repoCreated(repo));
|
importRepoFromUrl(repoLink, repo, (repo: Repository) => this.repoCreated(repo));
|
||||||
}}
|
}}
|
||||||
indexResources={indexResources}
|
indexResources={indexResources}
|
||||||
|
creationMode={this.isImportPage() ? "IMPORT" : "CREATE"}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
@@ -180,8 +222,13 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
},
|
},
|
||||||
resetForm: () => {
|
resetForm: () => {
|
||||||
dispatch(createRepoReset());
|
dispatch(createRepoReset());
|
||||||
|
dispatch(importRepoReset());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(AddRepository));
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
withTranslation("repos"),
|
||||||
|
connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
)(AddRepository);
|
||||||
|
|||||||
@@ -28,14 +28,16 @@ import RepositoryForm from "../components/form";
|
|||||||
import { Repository, Links } from "@scm-manager/ui-types";
|
import { Repository, Links } from "@scm-manager/ui-types";
|
||||||
import { getModifyRepoFailure, isModifyRepoPending, modifyRepo, modifyRepoReset } from "../modules/repos";
|
import { getModifyRepoFailure, isModifyRepoPending, modifyRepo, modifyRepoReset } from "../modules/repos";
|
||||||
import { History } from "history";
|
import { History } from "history";
|
||||||
import { ErrorNotification } from "@scm-manager/ui-components";
|
import { ErrorNotification, Subtitle } from "@scm-manager/ui-components";
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { compose } from "redux";
|
import { compose } from "redux";
|
||||||
import RepositoryDangerZone from "./RepositoryDangerZone";
|
import RepositoryDangerZone from "./RepositoryDangerZone";
|
||||||
import { getLinks } from "../../modules/indexResource";
|
import { getLinks } from "../../modules/indexResource";
|
||||||
import { urls } from "@scm-manager/ui-components";
|
import { urls } from "@scm-manager/ui-components";
|
||||||
|
import { TranslationProps, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
type Props = RouteComponentProps & {
|
type Props = TranslationProps &
|
||||||
|
RouteComponentProps & {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: Error;
|
error: Error;
|
||||||
indexLinks: Links;
|
indexLinks: Links;
|
||||||
@@ -60,7 +62,7 @@ class EditRepo extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loading, error, repository, indexLinks } = this.props;
|
const { loading, error, repository, indexLinks, t } = this.props;
|
||||||
|
|
||||||
const url = urls.matchedUrl(this.props);
|
const url = urls.matchedUrl(this.props);
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ class EditRepo extends React.Component<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Subtitle subtitle={t("repositoryForm.subtitle")} />
|
||||||
<ErrorNotification error={error} />
|
<ErrorNotification error={error} />
|
||||||
<RepositoryForm
|
<RepositoryForm
|
||||||
repository={this.props.repository}
|
repository={this.props.repository}
|
||||||
@@ -110,4 +113,4 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(EditRepo);
|
export default compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(withTranslation("repos")(EditRepo));
|
||||||
|
|||||||
@@ -285,6 +285,12 @@ export function importRepoFailure(err: Error): Action {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function importRepoReset(): Action {
|
||||||
|
return {
|
||||||
|
type: IMPORT_REPO_RESET
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// create repo
|
// create repo
|
||||||
|
|
||||||
export function createRepo(
|
export function createRepo(
|
||||||
|
|||||||
Reference in New Issue
Block a user