split AddRepository component into two separate components to simplify the state handling

This commit is contained in:
Eduard Heimbuch
2020-12-02 13:26:31 +01:00
parent 7db33d2e65
commit dffe466405
6 changed files with 81 additions and 76 deletions

View File

@@ -31,13 +31,13 @@ import Users from "../users/containers/Users";
import Login from "../containers/Login"; import Login from "../containers/Login";
import Logout from "../containers/Logout"; import Logout from "../containers/Logout";
import { ProtectedRoute, ErrorBoundary } from "@scm-manager/ui-components"; import { ErrorBoundary, ProtectedRoute } from "@scm-manager/ui-components";
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions"; import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
import CreateUser from "../users/containers/CreateUser"; import CreateUser from "../users/containers/CreateUser";
import SingleUser from "../users/containers/SingleUser"; import SingleUser from "../users/containers/SingleUser";
import RepositoryRoot from "../repos/containers/RepositoryRoot"; import RepositoryRoot from "../repos/containers/RepositoryRoot";
import AddRepository from "../repos/containers/AddRepository"; import CreateRepository from "../repos/containers/CreateRepository";
import Groups from "../groups/containers/Groups"; import Groups from "../groups/containers/Groups";
import SingleGroup from "../groups/containers/SingleGroup"; import SingleGroup from "../groups/containers/SingleGroup";
@@ -47,6 +47,7 @@ import Admin from "../admin/containers/Admin";
import Profile from "./Profile"; import Profile from "./Profile";
import NamespaceRoot from "../repos/namespaces/containers/NamespaceRoot"; import NamespaceRoot from "../repos/namespaces/containers/NamespaceRoot";
import ImportRepository from "../repos/containers/ImportRepository";
type Props = { type Props = {
me: Me; me: Me;
@@ -77,8 +78,8 @@ class Main extends React.Component<Props> {
<Route path="/logout" component={Logout} /> <Route path="/logout" component={Logout} />
<Redirect exact strict from="/repos" to="/repos/" /> <Redirect exact strict from="/repos" to="/repos/" />
<ProtectedRoute exact path="/repos/" component={Overview} authenticated={authenticated} /> <ProtectedRoute exact path="/repos/" component={Overview} authenticated={authenticated} />
<ProtectedRoute exact path="/repos/create" component={AddRepository} authenticated={authenticated} /> <ProtectedRoute exact path="/repos/create" component={CreateRepository} authenticated={authenticated} />
<ProtectedRoute exact path="/repos/import" component={AddRepository} authenticated={authenticated} /> <ProtectedRoute exact path="/repos/import" component={ImportRepository} authenticated={authenticated} />
<ProtectedRoute exact path="/repos/:namespace" component={Overview} authenticated={authenticated} /> <ProtectedRoute exact path="/repos/:namespace" component={Overview} authenticated={authenticated} />
<ProtectedRoute exact path="/repos/:namespace/:page" component={Overview} authenticated={authenticated} /> <ProtectedRoute exact path="/repos/:namespace/:page" component={Overview} authenticated={authenticated} />
<ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} /> <ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} />

View File

@@ -49,21 +49,21 @@ const ImportRepositoryFromUrl: FC<Props> = ({ url, setImportPending }) => {
}); });
const [valid, setValid] = useState({ namespaceAndName: false, contact: true, importUrl: false }); const [valid, setValid] = useState({ namespaceAndName: false, contact: true, importUrl: false });
const isValid = () => {
return Object.values(valid).every(v => v);
};
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | undefined>(); const [error, setError] = useState<Error | undefined>();
const history = useHistory(); const history = useHistory();
const [t] = useTranslation("repos"); const [t] = useTranslation("repos");
const isValid = () => Object.values(valid).every(v => v);
const handleImportLoading = (loading: boolean) => { const handleImportLoading = (loading: boolean) => {
setLoading(loading);
setImportPending(loading); setImportPending(loading);
setLoading(loading);
}; };
const submit = (event: FormEvent<HTMLFormElement>) => { const submit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault(); event.preventDefault();
setError(undefined);
const currentPath = history.location.pathname; const currentPath = history.location.pathname;
handleImportLoading(true); handleImportLoading(true);
apiClient apiClient

View File

@@ -45,7 +45,6 @@ import {
} from "../../admin/modules/namespaceStrategies"; } from "../../admin/modules/namespaceStrategies";
import { RouteComponentProps, withRouter } from "react-router-dom"; import { RouteComponentProps, withRouter } from "react-router-dom";
import { compose } from "redux"; import { compose } from "redux";
import ImportRepository from "./ImportRepository";
type Props = WithTranslation & type Props = WithTranslation &
RouteComponentProps & { RouteComponentProps & {
@@ -72,19 +71,7 @@ type Props = WithTranslation &
history: History; history: History;
}; };
type State = { class CreateRepository extends React.Component<Props> {
importPending: boolean;
};
class AddRepository extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
importPending: false
};
}
componentDidMount() { componentDidMount() {
this.props.resetForm(); this.props.resetForm();
this.props.fetchRepositoryTypesIfNeeded(); this.props.fetchRepositoryTypesIfNeeded();
@@ -95,30 +82,6 @@ class AddRepository extends React.Component<Props, State> {
this.props.history.push("/repo/" + repo.namespace + "/" + repo.name); this.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 = () => {
if (this.isCreatePage()) {
return "create.subtitle";
} else if (this.isImportPage() && this.state.importPending) {
return "import.pending.subtitle";
} else {
return "import.subtitle";
}
};
render() { render() {
const { const {
pageLoading, pageLoading,
@@ -135,29 +98,21 @@ class AddRepository extends React.Component<Props, State> {
return ( return (
<Page <Page
title={t("create.title")} title={t("create.title")}
subtitle={t(this.getSubtitle())} subtitle={t("create.subtitle")}
afterTitle={<RepositoryFormSwitcher creationMode={this.isImportPage() ? "IMPORT" : "CREATE"} />} afterTitle={<RepositoryFormSwitcher creationMode={"CREATE"} />}
loading={pageLoading} loading={pageLoading}
error={error} error={error}
showContentOnError={true} showContentOnError={true}
> >
{this.isImportPage() && ( <RepositoryForm
<ImportRepository repositoryTypes={repositoryTypes}
repositoryTypes={repositoryTypes} loading={createLoading}
setPending={(importPending: boolean) => this.setState({ importPending })} namespaceStrategy={namespaceStrategies.current}
/> createRepository={(repo, initRepository) => {
)} createRepo(repoLink, repo, initRepository, (repo: Repository) => this.repoCreated(repo));
{this.isCreatePage() && ( }}
<RepositoryForm indexResources={indexResources}
repositoryTypes={repositoryTypes} />
loading={createLoading}
namespaceStrategy={namespaceStrategies.current}
createRepository={(repo, initRepository) => {
createRepo(repoLink, repo, initRepository, (repo: Repository) => this.repoCreated(repo));
}}
indexResources={indexResources}
/>
)}
</Page> </Page>
); );
} }
@@ -205,4 +160,4 @@ export default compose(
withRouter, withRouter,
withTranslation("repos"), withTranslation("repos"),
connect(mapStateToProps, mapDispatchToProps) connect(mapStateToProps, mapDispatchToProps)
)(AddRepository); )(CreateRepository);

View File

@@ -29,22 +29,41 @@ import { useTranslation } from "react-i18next";
import ImportRepositoryTypeSelect from "../components/ImportRepositoryTypeSelect"; import ImportRepositoryTypeSelect from "../components/ImportRepositoryTypeSelect";
import ImportTypeSelect from "../components/ImportTypeSelect"; import ImportTypeSelect from "../components/ImportTypeSelect";
import ImportRepositoryFromUrl from "../components/ImportRepositoryFromUrl"; import ImportRepositoryFromUrl from "../components/ImportRepositoryFromUrl";
import { Loading, Notification } from "@scm-manager/ui-components"; import { Loading, Notification, Page } from "@scm-manager/ui-components";
import RepositoryFormSwitcher from "../components/form/RepositoryFormSwitcher";
import {
fetchRepositoryTypesIfNeeded,
getFetchRepositoryTypesFailure,
getRepositoryTypes,
isFetchRepositoryTypesPending
} from "../modules/repositoryTypes";
import { connect } from "react-redux";
import { fetchNamespaceStrategiesIfNeeded } from "../../admin/modules/namespaceStrategies";
type Props = { type Props = {
repositoryTypes: RepositoryType[]; repositoryTypes: RepositoryType[];
setPending: (pending: boolean) => void; pageLoading: boolean;
error?: Error;
fetchRepositoryTypesIfNeeded: () => void;
fetchNamespaceStrategiesIfNeeded: () => void;
}; };
const ImportRepository: FC<Props> = ({ repositoryTypes, setPending }) => { const ImportRepository: FC<Props> = ({
repositoryTypes,
pageLoading,
error,
fetchRepositoryTypesIfNeeded,
fetchNamespaceStrategiesIfNeeded
}) => {
const [importPending, setImportPending] = useState(false); const [importPending, setImportPending] = useState(false);
const [repositoryType, setRepositoryType] = useState<RepositoryType | undefined>(); const [repositoryType, setRepositoryType] = useState<RepositoryType | undefined>();
const [importType, setImportType] = useState(""); const [importType, setImportType] = useState("");
const [t] = useTranslation("repos"); const [t] = useTranslation("repos");
useEffect(() => { useEffect(() => {
setPending(importPending); fetchRepositoryTypesIfNeeded();
}, [importPending]); fetchNamespaceStrategiesIfNeeded();
}, [repositoryTypes]);
const changeRepositoryType = (repositoryType: RepositoryType) => { const changeRepositoryType = (repositoryType: RepositoryType) => {
setRepositoryType(repositoryType); setRepositoryType(repositoryType);
@@ -65,7 +84,14 @@ const ImportRepository: FC<Props> = ({ repositoryTypes, setPending }) => {
}; };
return ( return (
<div> <Page
title={t("create.title")}
subtitle={t("import.subtitle")}
afterTitle={<RepositoryFormSwitcher creationMode={"IMPORT"} />}
loading={pageLoading}
error={error}
showContentOnError={true}
>
{importPending && ( {importPending && (
<> <>
<Notification type="info">{t("import.pending.infoText")}</Notification> <Notification type="info">{t("import.pending.infoText")}</Notification>
@@ -92,8 +118,31 @@ const ImportRepository: FC<Props> = ({ repositoryTypes, setPending }) => {
</> </>
)} )}
{importType && renderImportComponent()} {importType && renderImportComponent()}
</div> </Page>
); );
}; };
export default ImportRepository; const mapStateToProps = (state: any) => {
const repositoryTypes = getRepositoryTypes(state);
const pageLoading = isFetchRepositoryTypesPending(state);
const error = getFetchRepositoryTypesFailure(state);
return {
repositoryTypes,
pageLoading,
error
};
};
const mapDispatchToProps = (dispatch: any) => {
return {
fetchRepositoryTypesIfNeeded: () => {
dispatch(fetchRepositoryTypesIfNeeded());
},
fetchNamespaceStrategiesIfNeeded: () => {
dispatch(fetchNamespaceStrategiesIfNeeded());
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ImportRepository);

View File

@@ -289,7 +289,7 @@
}, },
"D6SHRfqQw1": { "D6SHRfqQw1": {
"displayName": "Repository Import fehlgeschlagen", "displayName": "Repository Import fehlgeschlagen",
"description": "Das Repository konnte nicht importiert werden. Entweder wurden die Zugangsdaten (Benutzername/Passwort) nicht gesetzt oder sind fehlerhaft. Bitte prüfen Sie Ihre Eingaben." "description": "Das Repository konnte nicht importiert werden. Möglicherweise wurden die Zugangsdaten (Benutzername/Passwort) nicht gesetzt oder sind fehlerhaft. Bitte prüfen Sie Ihre Eingaben."
} }
}, },
"namespaceStrategies": { "namespaceStrategies": {

View File

@@ -289,7 +289,7 @@
}, },
"D6SHRfqQw1": { "D6SHRfqQw1": {
"displayName": "Repository import failed", "displayName": "Repository import failed",
"description": "The repository could not be imported. Either the credentials (username/password) are wrong or missing. Please check your inputs." "description": "The repository could not be imported. It's likely that either the credentials (username/password) are wrong or missing. Please check your inputs."
} }
}, },
"namespaceStrategies": { "namespaceStrategies": {