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 { 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -285,6 +285,12 @@ export function importRepoFailure(err: Error): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function importRepoReset(): Action {
|
||||
return {
|
||||
type: IMPORT_REPO_RESET
|
||||
};
|
||||
}
|
||||
|
||||
// create repo
|
||||
|
||||
export function createRepo(
|
||||
|
||||
Reference in New Issue
Block a user