refactor UI

This commit is contained in:
Eduard Heimbuch
2020-11-25 15:08:30 +01:00
parent 4e1e51d1b9
commit d1dc2e04e2
5 changed files with 132 additions and 105 deletions

View File

@@ -25,12 +25,10 @@ import React, { FC, useEffect, useState } from "react";
import styled from "styled-components";
import { useTranslation } from "react-i18next";
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 * as validator from "./repositoryValidation";
import { CUSTOM_NAMESPACE_STRATEGY } from "../../modules/repos";
import { useLocation } from "react-router-dom";
import RepositoryFormSwitcher from "./RepositoryFormSwitcher";
const CheckboxWrapper = styled.div`
margin-top: 2em;
@@ -63,6 +61,7 @@ type Props = {
namespaceStrategy?: string;
loading?: boolean;
indexResources?: any;
creationMode?: "CREATE" | "IMPORT";
};
type RepositoryCreation = Repository & {
@@ -77,7 +76,8 @@ const RepositoryForm: FC<Props> = ({
repositoryTypes,
namespaceStrategy,
loading,
indexResources
indexResources,
creationMode
}) => {
const [repo, setRepo] = useState<RepositoryCreation>({
name: "",
@@ -96,7 +96,6 @@ const RepositoryForm: FC<Props> = ({
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const location = useLocation();
const [t] = useTranslation("repos");
useEffect(() => {
@@ -105,6 +104,9 @@ const RepositoryForm: FC<Props> = ({
}
}, [repository]);
const isImportMode = () => creationMode === "IMPORT";
const isCreateMode = () => creationMode === "CREATE";
const isValid = () => {
return !(
namespaceValidationError ||
@@ -112,16 +114,16 @@ const RepositoryForm: FC<Props> = ({
contactValidationError ||
!repo.name ||
(namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY && !repo.namespace) ||
(isImportPage() && !importUrl)
(isImportMode() && !importUrl)
);
};
const submit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (isValid()) {
if (importRepository && isImportPage()) {
if (importRepository && isImportMode()) {
importRepository({ ...repo, url: importUrl, username, password });
} else if (createRepository && isCreatePage()) {
} else if (createRepository && isCreateMode()) {
createRepository(repo, initRepository);
} else if (modifyRepository) {
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[]) => {
if (repositoryTypes) {
return repositoryTypes.map(repositoryType => {
@@ -195,7 +183,7 @@ const RepositoryForm: FC<Props> = ({
};
const renderUrlImportFields = () => {
if (!isImportPage()) {
if (!isImportMode()) {
return null;
}
@@ -264,7 +252,7 @@ const RepositoryForm: FC<Props> = ({
helpText={t("help.typeHelpText")}
/>
</SelectWrapper>
{!isImportPage() && (
{!isImportMode() && (
<CheckboxWrapper>
<Checkbox
label={t("repositoryForm.initializeRepository")}
@@ -310,7 +298,7 @@ const RepositoryForm: FC<Props> = ({
const disabled = !isModifiable() && isEditMode();
const getSubmitButtonTranslationKey = () =>
isImportPage() ? "repositoryForm.submitImport" : "repositoryForm.submitCreate";
isImportMode() ? "repositoryForm.submitImport" : "repositoryForm.submitCreate";
const submitButton = disabled ? null : (
<Level
@@ -320,9 +308,6 @@ const RepositoryForm: FC<Props> = ({
return (
<>
{!isEditMode() && (
<RepositoryFormSwitcher repository={repository} createMode={isImportPage() ? "IMPORT" : "CREATE"} />
)}
<form onSubmit={submit}>
{renderCreateOnlyFields()}
<InputField

View File

@@ -25,51 +25,37 @@
import React, { FC } from "react";
import styled from "styled-components";
import { useTranslation } from "react-i18next";
import { Button, ButtonAddons, Level, Subtitle } from "@scm-manager/ui-components";
import { Repository } from "@scm-manager/ui-types";
import { Button, ButtonAddons, Level } from "@scm-manager/ui-components";
type Props = {
repository?: Repository;
createMode: "CREATE" | "IMPORT";
creationMode: "CREATE" | "IMPORT";
};
const TopLevel = styled(Level)`
margin-top: -2rem;
`;
const SmallButton = styled(Button)`
border-radius: 4px;
font-size: 1rem;
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 isImportMode = () => {
return createMode === "IMPORT";
return creationMode === "IMPORT";
};
const isCreateMode = () => {
return createMode === "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 creationMode === "CREATE";
};
return (
<TopLevel
left={renderSubtitle()}
right={
<ButtonAddons>
<SmallButton

View File

@@ -32,7 +32,7 @@ import {
RepositoryImport,
RepositoryType
} 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 {
fetchRepositoryTypesIfNeeded,
getFetchRepositoryTypesFailure,
@@ -40,12 +40,14 @@ import {
isFetchRepositoryTypesPending
} from "../modules/repositoryTypes";
import RepositoryForm from "../components/form";
import RepositoryFormSwitcher from "../components/form/RepositoryFormSwitcher";
import {
createRepo,
createRepoReset,
getCreateRepoFailure,
getImportRepoFailure,
importRepoFromUrl,
importRepoReset,
isCreateRepoPending,
isImportRepoPending
} from "../modules/repos";
@@ -56,32 +58,35 @@ import {
getNamespaceStrategies,
isFetchNamespaceStrategiesPending
} from "../../admin/modules/namespaceStrategies";
import { RouteComponentProps, withRouter } from "react-router-dom";
import { compose } from "redux";
type Props = WithTranslation & {
repositoryTypes: RepositoryType[];
namespaceStrategies: NamespaceStrategies;
pageLoading: boolean;
createLoading: boolean;
importLoading: boolean;
error: Error;
repoLink: string;
indexResources: any;
type Props = WithTranslation &
RouteComponentProps & {
repositoryTypes: RepositoryType[];
namespaceStrategies: NamespaceStrategies;
pageLoading: boolean;
createLoading: boolean;
importLoading: boolean;
error: Error;
repoLink: string;
indexResources: any;
// dispatch functions
fetchNamespaceStrategiesIfNeeded: () => void;
fetchRepositoryTypesIfNeeded: () => void;
createRepo: (
link: string,
repository: RepositoryCreation,
initRepository: boolean,
callback: (repo: Repository) => void
) => void;
importRepoFromUrl: (link: string, repository: RepositoryImport, callback: (repo: Repository) => void) => void;
resetForm: () => void;
// dispatch functions
fetchNamespaceStrategiesIfNeeded: () => void;
fetchRepositoryTypesIfNeeded: () => void;
createRepo: (
link: string,
repository: RepositoryCreation,
initRepository: boolean,
callback: (repo: Repository) => void
) => void;
importRepoFromUrl: (link: string, repository: RepositoryImport, callback: (repo: Repository) => void) => void;
resetForm: () => void;
// context props
history: History;
};
// context props
history: History;
};
class AddRepository extends React.Component<Props> {
componentDidMount() {
@@ -96,6 +101,34 @@ class AddRepository extends React.Component<Props> {
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() {
const {
pageLoading,
@@ -112,26 +145,35 @@ class AddRepository extends React.Component<Props> {
} = this.props;
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 ? (
<>
<Subtitle subtitle={t("import.pending.subtitle")}/>
<Notification type="info">{t("import.pending.infoText")}</Notification>
<Loading />
</>
) : (
<RepositoryForm
repositoryTypes={repositoryTypes}
loading={createLoading}
namespaceStrategy={namespaceStrategies.current}
createRepository={(repo, initRepository) => {
createRepo(repoLink, repo, initRepository, (repo: Repository) => this.repoCreated(repo));
}}
importRepository={repo => {
importRepoFromUrl(repoLink, repo, (repo: Repository) => this.repoCreated(repo));
}}
indexResources={indexResources}
/>
<>
{!error && <RepositoryFormSwitcher creationMode={this.isImportPage() ? "IMPORT" : "CREATE"} />}
<RepositoryForm
repositoryTypes={repositoryTypes}
loading={createLoading}
namespaceStrategy={namespaceStrategies.current}
createRepository={(repo, initRepository) => {
createRepo(repoLink, repo, initRepository, (repo: Repository) => this.repoCreated(repo));
}}
importRepository={repo => {
importRepoFromUrl(repoLink, repo, (repo: Repository) => this.repoCreated(repo));
}}
indexResources={indexResources}
creationMode={this.isImportPage() ? "IMPORT" : "CREATE"}
/>
</>
)}
</Page>
);
@@ -180,8 +222,13 @@ const mapDispatchToProps = (dispatch: any) => {
},
resetForm: () => {
dispatch(createRepoReset());
dispatch(importRepoReset());
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(AddRepository));
export default compose(
withRouter,
withTranslation("repos"),
connect(mapStateToProps, mapDispatchToProps)
)(AddRepository);

View File

@@ -28,25 +28,27 @@ import RepositoryForm from "../components/form";
import { Repository, Links } from "@scm-manager/ui-types";
import { getModifyRepoFailure, isModifyRepoPending, modifyRepo, modifyRepoReset } from "../modules/repos";
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 { compose } from "redux";
import RepositoryDangerZone from "./RepositoryDangerZone";
import { getLinks } from "../../modules/indexResource";
import { urls } from "@scm-manager/ui-components";
import { TranslationProps, withTranslation } from "react-i18next";
type Props = RouteComponentProps & {
loading: boolean;
error: Error;
indexLinks: Links;
type Props = TranslationProps &
RouteComponentProps & {
loading: boolean;
error: Error;
indexLinks: Links;
modifyRepo: (p1: Repository, p2: () => void) => void;
modifyRepoReset: (p: Repository) => void;
modifyRepo: (p1: Repository, p2: () => void) => void;
modifyRepoReset: (p: Repository) => void;
// context props
repository: Repository;
history: History;
};
// context props
repository: Repository;
history: History;
};
class EditRepo extends React.Component<Props> {
componentDidMount() {
@@ -60,7 +62,7 @@ class EditRepo extends React.Component<Props> {
};
render() {
const { loading, error, repository, indexLinks } = this.props;
const { loading, error, repository, indexLinks, t } = this.props;
const url = urls.matchedUrl(this.props);
@@ -71,6 +73,7 @@ class EditRepo extends React.Component<Props> {
return (
<>
<Subtitle subtitle={t("repositoryForm.subtitle")} />
<ErrorNotification error={error} />
<RepositoryForm
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));

View File

@@ -285,6 +285,12 @@ export function importRepoFailure(err: Error): Action {
};
}
export function importRepoReset(): Action {
return {
type: IMPORT_REPO_RESET
};
}
// create repo
export function createRepo(