mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 14:35:45 +01:00
Bugfix/link not found (#1296)
Redirect to login page if anonymous tries to access a page without permission Co-authored-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com> Co-authored-by: Sebastian Sdorra <sebastian.sdorra@cloudogu.com>
This commit is contained in:
committed by
GitHub
parent
bd81d973ec
commit
b4c5f49858
@@ -29,6 +29,7 @@ import { withI18next } from "storybook-addon-i18next";
|
|||||||
import "!style-loader!css-loader!sass-loader!../../ui-styles/src/scm.scss";
|
import "!style-loader!css-loader!sass-loader!../../ui-styles/src/scm.scss";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
|
import withRedux from "./withRedux";
|
||||||
|
|
||||||
|
|
||||||
let i18n = i18next;
|
let i18n = i18next;
|
||||||
@@ -70,4 +71,6 @@ addDecorator(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
addDecorator(withRedux);
|
||||||
|
|
||||||
configure(require.context("../src", true, /\.stories\.tsx?$/), module);
|
configure(require.context("../src", true, /\.stories\.tsx?$/), module);
|
||||||
|
|||||||
41
scm-ui/ui-components/.storybook/withRedux.js
Normal file
41
scm-ui/ui-components/.storybook/withRedux.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import {createStore} from "redux";
|
||||||
|
import { Provider } from 'react-redux'
|
||||||
|
|
||||||
|
const reducer = (state, action) => {
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
const withRedux = (storyFn) => {
|
||||||
|
return React.createElement(Provider, {
|
||||||
|
store: createStore(reducer, {}),
|
||||||
|
children: storyFn()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default withRedux;
|
||||||
@@ -21,14 +21,24 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { ReactNode } from "react";
|
import React, { ComponentType, ReactNode } from "react";
|
||||||
import ErrorNotification from "./ErrorNotification";
|
import ErrorNotification from "./ErrorNotification";
|
||||||
|
import { MissingLinkError } from "./errors";
|
||||||
|
import { withContextPath } from "./urls";
|
||||||
|
import { withRouter, RouteComponentProps } from "react-router-dom";
|
||||||
|
import ErrorPage from "./ErrorPage";
|
||||||
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
import { compose } from "redux";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
type Props = {
|
type ExportedProps = {
|
||||||
fallback?: React.ComponentType<any>;
|
fallback?: React.ComponentType<any>;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
loginLink?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Props = WithTranslation & RouteComponentProps & ExportedProps;
|
||||||
|
|
||||||
type ErrorInfo = {
|
type ErrorInfo = {
|
||||||
componentStack: string;
|
componentStack: string;
|
||||||
};
|
};
|
||||||
@@ -44,16 +54,44 @@ class ErrorBoundary extends React.Component<Props, State> {
|
|||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
componentDidUpdate(prevProps: Readonly<Props>) {
|
||||||
// Catch errors in any components below and re-render with error message
|
// we must reset the error if the url has changed
|
||||||
this.setState({
|
if (this.state.error && prevProps.location !== this.props.location) {
|
||||||
error,
|
this.setState({ error: undefined, errorInfo: undefined });
|
||||||
errorInfo
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
error,
|
||||||
|
errorInfo
|
||||||
|
},
|
||||||
|
() => this.redirectToLogin(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectToLogin = (error: Error) => {
|
||||||
|
const { loginLink } = this.props;
|
||||||
|
if (error instanceof MissingLinkError) {
|
||||||
|
if (loginLink) {
|
||||||
|
window.location.assign(withContextPath("/login"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
renderError = () => {
|
renderError = () => {
|
||||||
|
const { t } = this.props;
|
||||||
|
const { error } = this.state;
|
||||||
|
|
||||||
let FallbackComponent = this.props.fallback;
|
let FallbackComponent = this.props.fallback;
|
||||||
|
|
||||||
|
if (error instanceof MissingLinkError) {
|
||||||
|
return (
|
||||||
|
<ErrorPage error={error} title={t("errorNotification.prefix")} subtitle={t("errorNotification.forbidden")} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!FallbackComponent) {
|
if (!FallbackComponent) {
|
||||||
FallbackComponent = ErrorNotification;
|
FallbackComponent = ErrorNotification;
|
||||||
}
|
}
|
||||||
@@ -69,4 +107,17 @@ class ErrorBoundary extends React.Component<Props, State> {
|
|||||||
return this.props.children;
|
return this.props.children;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default ErrorBoundary;
|
|
||||||
|
const mapStateToProps = (state: any) => {
|
||||||
|
const loginLink = state.indexResources?.links?.login?.href;
|
||||||
|
|
||||||
|
return {
|
||||||
|
loginLink
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default compose<ComponentType<ExportedProps>>(
|
||||||
|
withRouter,
|
||||||
|
withTranslation("commons"),
|
||||||
|
connect(mapStateToProps)
|
||||||
|
)(ErrorBoundary);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { Route, Redirect, withRouter, RouteComponentProps, RouteProps } from "react-router-dom";
|
import { Redirect, Route, RouteComponentProps, RouteProps, withRouter } from "react-router-dom";
|
||||||
|
|
||||||
type Props = RouteComponentProps &
|
type Props = RouteComponentProps &
|
||||||
RouteProps & {
|
RouteProps & {
|
||||||
@@ -30,7 +30,16 @@ type Props = RouteComponentProps &
|
|||||||
};
|
};
|
||||||
|
|
||||||
class ProtectedRoute extends Component<Props> {
|
class ProtectedRoute extends Component<Props> {
|
||||||
renderRoute = (Component: any, authenticated?: boolean) => {
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
error: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRoute = (Component: any) => {
|
||||||
|
const { authenticated } = this.props;
|
||||||
|
|
||||||
return (routeProps: any) => {
|
return (routeProps: any) => {
|
||||||
if (authenticated) {
|
if (authenticated) {
|
||||||
return <Component {...routeProps} />;
|
return <Component {...routeProps} />;
|
||||||
@@ -50,8 +59,8 @@ class ProtectedRoute extends Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { component, authenticated, ...routeProps } = this.props;
|
const { component, ...routeProps } = this.props;
|
||||||
return <Route {...routeProps} render={this.renderRoute(component, authenticated)} />;
|
return <Route {...routeProps} render={this.renderRoute(component)} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,10 @@ export class ConflictError extends BackendError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MissingLinkError extends Error {
|
||||||
|
name = "MissingLinkError";
|
||||||
|
}
|
||||||
|
|
||||||
export function createBackendError(content: BackendErrorContent, statusCode: number) {
|
export function createBackendError(content: BackendErrorContent, statusCode: number) {
|
||||||
switch (statusCode) {
|
switch (statusCode) {
|
||||||
case 404:
|
case 404:
|
||||||
|
|||||||
@@ -29,12 +29,13 @@ import { Redirect, Route, RouteComponentProps, Switch } from "react-router-dom";
|
|||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { Links } from "@scm-manager/ui-types";
|
import { Links } from "@scm-manager/ui-types";
|
||||||
import {
|
import {
|
||||||
|
CustomQueryFlexWrappedColumns,
|
||||||
NavLink,
|
NavLink,
|
||||||
Page,
|
Page,
|
||||||
CustomQueryFlexWrappedColumns,
|
|
||||||
PrimaryContentColumn,
|
PrimaryContentColumn,
|
||||||
SecondaryNavigationColumn,
|
|
||||||
SecondaryNavigation,
|
SecondaryNavigation,
|
||||||
|
SecondaryNavigationColumn,
|
||||||
|
StateMenuContextProvider,
|
||||||
SubNavigation
|
SubNavigation
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import { getAvailablePluginsLink, getInstalledPluginsLink, getLinks } from "../../modules/indexResource";
|
import { getAvailablePluginsLink, getInstalledPluginsLink, getLinks } from "../../modules/indexResource";
|
||||||
@@ -44,7 +45,6 @@ import GlobalConfig from "./GlobalConfig";
|
|||||||
import RepositoryRoles from "../roles/containers/RepositoryRoles";
|
import RepositoryRoles from "../roles/containers/RepositoryRoles";
|
||||||
import SingleRepositoryRole from "../roles/containers/SingleRepositoryRole";
|
import SingleRepositoryRole from "../roles/containers/SingleRepositoryRole";
|
||||||
import CreateRepositoryRole from "../roles/containers/CreateRepositoryRole";
|
import CreateRepositoryRole from "../roles/containers/CreateRepositoryRole";
|
||||||
import { StateMenuContextProvider } from "@scm-manager/ui-components";
|
|
||||||
|
|
||||||
type Props = RouteComponentProps &
|
type Props = RouteComponentProps &
|
||||||
WithTranslation & {
|
WithTranslation & {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { WithTranslation, withTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Config, NamespaceStrategies } from "@scm-manager/ui-types";
|
import { Config, NamespaceStrategies } from "@scm-manager/ui-types";
|
||||||
import { ErrorNotification, Loading, Title } from "@scm-manager/ui-components";
|
import { ErrorNotification, Loading, Title } from "@scm-manager/ui-components";
|
||||||
import { getConfigLink } from "../../modules/indexResource";
|
import { mustGetConfigLink } from "../../modules/indexResource";
|
||||||
import {
|
import {
|
||||||
fetchConfig,
|
fetchConfig,
|
||||||
getConfig,
|
getConfig,
|
||||||
@@ -186,7 +186,7 @@ const mapStateToProps = (state: any) => {
|
|||||||
|
|
||||||
const config = getConfig(state);
|
const config = getConfig(state);
|
||||||
const configUpdatePermission = getConfigUpdatePermission(state);
|
const configUpdatePermission = getConfigUpdatePermission(state);
|
||||||
const configLink = getConfigLink(state);
|
const configLink = mustGetConfigLink(state);
|
||||||
const namespaceStrategies = getNamespaceStrategies(state);
|
const namespaceStrategies = getNamespaceStrategies(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import * as React from "react";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { compose } from "redux";
|
import { compose } from "redux";
|
||||||
import { PendingPlugins, PluginCollection } from "@scm-manager/ui-types";
|
import { PendingPlugins, Plugin, PluginCollection } from "@scm-manager/ui-types";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
@@ -45,16 +45,15 @@ import {
|
|||||||
} from "../modules/plugins";
|
} from "../modules/plugins";
|
||||||
import PluginsList from "../components/PluginList";
|
import PluginsList from "../components/PluginList";
|
||||||
import {
|
import {
|
||||||
getAvailablePluginsLink,
|
getPendingPluginsLink,
|
||||||
getInstalledPluginsLink,
|
mustGetAvailablePluginsLink,
|
||||||
getPendingPluginsLink
|
mustGetInstalledPluginsLink
|
||||||
} from "../../../modules/indexResource";
|
} from "../../../modules/indexResource";
|
||||||
import PluginTopActions from "../components/PluginTopActions";
|
import PluginTopActions from "../components/PluginTopActions";
|
||||||
import PluginBottomActions from "../components/PluginBottomActions";
|
import PluginBottomActions from "../components/PluginBottomActions";
|
||||||
import ExecutePendingActionModal from "../components/ExecutePendingActionModal";
|
import ExecutePendingActionModal from "../components/ExecutePendingActionModal";
|
||||||
import CancelPendingActionModal from "../components/CancelPendingActionModal";
|
import CancelPendingActionModal from "../components/CancelPendingActionModal";
|
||||||
import UpdateAllActionModal from "../components/UpdateAllActionModal";
|
import UpdateAllActionModal from "../components/UpdateAllActionModal";
|
||||||
import { Plugin } from "@scm-manager/ui-types";
|
|
||||||
import ShowPendingModal from "../components/ShowPendingModal";
|
import ShowPendingModal from "../components/ShowPendingModal";
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
@@ -319,8 +318,8 @@ const mapStateToProps = (state: any) => {
|
|||||||
const collection = getPluginCollection(state);
|
const collection = getPluginCollection(state);
|
||||||
const loading = isFetchPluginsPending(state);
|
const loading = isFetchPluginsPending(state);
|
||||||
const error = getFetchPluginsFailure(state);
|
const error = getFetchPluginsFailure(state);
|
||||||
const availablePluginsLink = getAvailablePluginsLink(state);
|
const availablePluginsLink = mustGetAvailablePluginsLink(state);
|
||||||
const installedPluginsLink = getInstalledPluginsLink(state);
|
const installedPluginsLink = mustGetInstalledPluginsLink(state);
|
||||||
const pendingPluginsLink = getPendingPluginsLink(state);
|
const pendingPluginsLink = getPendingPluginsLink(state);
|
||||||
const pendingPlugins = getPendingPlugins(state);
|
const pendingPlugins = getPendingPlugins(state);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { History } from "history";
|
|||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { RepositoryRole } from "@scm-manager/ui-types";
|
import { RepositoryRole } from "@scm-manager/ui-types";
|
||||||
import { ErrorPage, Loading, Title } from "@scm-manager/ui-components";
|
import { ErrorPage, Loading, Title } from "@scm-manager/ui-components";
|
||||||
import { getRepositoryRolesLink } from "../../../modules/indexResource";
|
import { mustGetRepositoryRolesLink } from "../../../modules/indexResource";
|
||||||
import { fetchRoleByName, getFetchRoleFailure, getRoleByName, isFetchRolePending } from "../modules/roles";
|
import { fetchRoleByName, getFetchRoleFailure, getRoleByName, isFetchRolePending } from "../modules/roles";
|
||||||
import PermissionRoleDetail from "../components/PermissionRoleDetails";
|
import PermissionRoleDetail from "../components/PermissionRoleDetails";
|
||||||
import EditRepositoryRole from "./EditRepositoryRole";
|
import EditRepositoryRole from "./EditRepositoryRole";
|
||||||
@@ -107,7 +107,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
const role = getRoleByName(state, roleName);
|
const role = getRoleByName(state, roleName);
|
||||||
const loading = isFetchRolePending(state, roleName);
|
const loading = isFetchRolePending(state, roleName);
|
||||||
const error = getFetchRoleFailure(state, roleName);
|
const error = getFetchRoleFailure(state, roleName);
|
||||||
const repositoryRolesLink = getRepositoryRolesLink(state);
|
const repositoryRolesLink = mustGetRepositoryRolesLink(state);
|
||||||
return {
|
return {
|
||||||
repositoryRolesLink,
|
repositoryRolesLink,
|
||||||
roleName,
|
roleName,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ 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 } from "@scm-manager/ui-components";
|
import { ProtectedRoute, ErrorBoundary } 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";
|
||||||
@@ -68,6 +68,7 @@ class Main extends React.Component<Props> {
|
|||||||
url = "/login";
|
url = "/login";
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
<div className="main">
|
<div className="main">
|
||||||
<Switch>
|
<Switch>
|
||||||
<Redirect exact from="/" to={url} />
|
<Redirect exact from="/" to={url} />
|
||||||
@@ -80,13 +81,13 @@ class Main extends React.Component<Props> {
|
|||||||
<ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} />
|
<ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} />
|
||||||
<Redirect exact strict from="/users" to="/users/" />
|
<Redirect exact strict from="/users" to="/users/" />
|
||||||
<ProtectedRoute exact path="/users/" component={Users} authenticated={authenticated} />
|
<ProtectedRoute exact path="/users/" component={Users} authenticated={authenticated} />
|
||||||
<ProtectedRoute authenticated={authenticated} path="/users/create" component={CreateUser} />
|
<ProtectedRoute path="/users/create" component={CreateUser} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/users/:page" component={Users} authenticated={authenticated} />
|
<ProtectedRoute exact path="/users/:page" component={Users} authenticated={authenticated} />
|
||||||
<ProtectedRoute authenticated={authenticated} path="/user/:name" component={SingleUser} />
|
<ProtectedRoute path="/user/:name" component={SingleUser} authenticated={authenticated} />
|
||||||
<Redirect exact strict from="/groups" to="/groups/" />
|
<Redirect exact strict from="/groups" to="/groups/" />
|
||||||
<ProtectedRoute exact path="/groups/" component={Groups} authenticated={authenticated} />
|
<ProtectedRoute exact path="/groups/" component={Groups} authenticated={authenticated} />
|
||||||
<ProtectedRoute authenticated={authenticated} path="/group/:name" component={SingleGroup} />
|
<ProtectedRoute path="/group/:name" component={SingleGroup} authenticated={authenticated} />
|
||||||
<ProtectedRoute authenticated={authenticated} path="/groups/create" component={CreateGroup} />
|
<ProtectedRoute path="/groups/create" component={CreateGroup} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/groups/:page" component={Groups} authenticated={authenticated} />
|
<ProtectedRoute exact path="/groups/:page" component={Groups} authenticated={authenticated} />
|
||||||
<ProtectedRoute path="/admin" component={Admin} authenticated={authenticated} />
|
<ProtectedRoute path="/admin" component={Admin} authenticated={authenticated} />
|
||||||
<ProtectedRoute path="/me" component={Profile} authenticated={authenticated} />
|
<ProtectedRoute path="/me" component={Profile} authenticated={authenticated} />
|
||||||
@@ -94,13 +95,14 @@ class Main extends React.Component<Props> {
|
|||||||
name="main.route"
|
name="main.route"
|
||||||
renderAll={true}
|
renderAll={true}
|
||||||
props={{
|
props={{
|
||||||
authenticated,
|
|
||||||
me,
|
me,
|
||||||
links
|
links,
|
||||||
|
authenticated
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ import { compose } from "redux";
|
|||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { History } from "history";
|
import { History } from "history";
|
||||||
import { DisplayedUser, Group } from "@scm-manager/ui-types";
|
import { DisplayedUser, Group } from "@scm-manager/ui-types";
|
||||||
import { Page } from "@scm-manager/ui-components";
|
import { apiClient, Page } from "@scm-manager/ui-components";
|
||||||
import { getGroupsLink, getUserAutoCompleteLink } from "../../modules/indexResource";
|
import { getUserAutoCompleteLink, mustGetGroupsLink } from "../../modules/indexResource";
|
||||||
import { createGroup, createGroupReset, getCreateGroupFailure, isCreateGroupPending } from "../modules/groups";
|
import { createGroup, createGroupReset, getCreateGroupFailure, isCreateGroupPending } from "../modules/groups";
|
||||||
import GroupForm from "../components/GroupForm";
|
import GroupForm from "../components/GroupForm";
|
||||||
import { apiClient } from "@scm-manager/ui-components";
|
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
createGroup: (link: string, group: Group, callback?: () => void) => void;
|
createGroup: (link: string, group: Group, callback?: () => void) => void;
|
||||||
@@ -97,7 +96,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
const mapStateToProps = (state: any) => {
|
const mapStateToProps = (state: any) => {
|
||||||
const loading = isCreateGroupPending(state);
|
const loading = isCreateGroupPending(state);
|
||||||
const error = getCreateGroupFailure(state);
|
const error = getCreateGroupFailure(state);
|
||||||
const createLink = getGroupsLink(state);
|
const createLink = mustGetGroupsLink(state);
|
||||||
const autocompleteLink = getUserAutoCompleteLink(state);
|
const autocompleteLink = getUserAutoCompleteLink(state);
|
||||||
return {
|
return {
|
||||||
createLink,
|
createLink,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import {
|
|||||||
PageActions,
|
PageActions,
|
||||||
urls
|
urls
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import { getGroupsLink } from "../../modules/indexResource";
|
import { mustGetGroupsLink } from "../../modules/indexResource";
|
||||||
import {
|
import {
|
||||||
fetchGroupsByPage,
|
fetchGroupsByPage,
|
||||||
getFetchGroupsFailure,
|
getFetchGroupsFailure,
|
||||||
@@ -128,7 +128,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
const page = urls.getPageFromMatch(match);
|
const page = urls.getPageFromMatch(match);
|
||||||
const canAddGroups = isPermittedToCreateGroups(state);
|
const canAddGroups = isPermittedToCreateGroups(state);
|
||||||
const list = selectListAsCollection(state);
|
const list = selectListAsCollection(state);
|
||||||
const groupLink = getGroupsLink(state);
|
const groupLink = mustGetGroupsLink(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
groups,
|
groups,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import {
|
|||||||
SubNavigation,
|
SubNavigation,
|
||||||
StateMenuContextProvider
|
StateMenuContextProvider
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import { getGroupsLink } from "../../modules/indexResource";
|
import { getGroupsLink, mustGetGroupsLink } from "../../modules/indexResource";
|
||||||
import { fetchGroupByName, getFetchGroupFailure, getGroupByName, isFetchGroupPending } from "../modules/groups";
|
import { fetchGroupByName, getFetchGroupFailure, getGroupByName, isFetchGroupPending } from "../modules/groups";
|
||||||
import { Details } from "./../components/table";
|
import { Details } from "./../components/table";
|
||||||
import { EditGroupNavLink, SetPermissionsNavLink } from "./../components/navLinks";
|
import { EditGroupNavLink, SetPermissionsNavLink } from "./../components/navLinks";
|
||||||
@@ -138,7 +138,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
const group = getGroupByName(state, name);
|
const group = getGroupByName(state, name);
|
||||||
const loading = isFetchGroupPending(state, name);
|
const loading = isFetchGroupPending(state, name);
|
||||||
const error = getFetchGroupFailure(state, name);
|
const error = getFetchGroupFailure(state, name);
|
||||||
const groupLink = getGroupsLink(state);
|
const groupLink = mustGetGroupsLink(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
import * as types from "./types";
|
import * as types from "./types";
|
||||||
|
|
||||||
import { apiClient } from "@scm-manager/ui-components";
|
import { apiClient, MissingLinkError } from "@scm-manager/ui-components";
|
||||||
import { Action, IndexResources, Link } from "@scm-manager/ui-types";
|
import { Action, IndexResources, Link } from "@scm-manager/ui-types";
|
||||||
import { isPending } from "./pending";
|
import { isPending } from "./pending";
|
||||||
import { getFailure } from "./failure";
|
import { getFailure } from "./failure";
|
||||||
@@ -123,6 +123,14 @@ export function getLink(state: object, name: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mustGetLink(state: object, name: string) {
|
||||||
|
const link = getLink(state, name);
|
||||||
|
if (link) {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
throw new MissingLinkError(`No link in state for link name: '${name}'`);
|
||||||
|
}
|
||||||
|
|
||||||
export function getLinkCollection(state: object, name: string): Link[] {
|
export function getLinkCollection(state: object, name: string): Link[] {
|
||||||
// @ts-ignore Right types not available
|
// @ts-ignore Right types not available
|
||||||
if (state.indexResources.links && state.indexResources.links[name]) {
|
if (state.indexResources.links && state.indexResources.links[name]) {
|
||||||
@@ -145,10 +153,18 @@ export function getAvailablePluginsLink(state: object) {
|
|||||||
return getLink(state, "availablePlugins");
|
return getLink(state, "availablePlugins");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mustGetAvailablePluginsLink(state: object) {
|
||||||
|
return mustGetLink(state, "availablePlugins");
|
||||||
|
}
|
||||||
|
|
||||||
export function getInstalledPluginsLink(state: object) {
|
export function getInstalledPluginsLink(state: object) {
|
||||||
return getLink(state, "installedPlugins");
|
return getLink(state, "installedPlugins");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mustGetInstalledPluginsLink(state: object) {
|
||||||
|
return mustGetLink(state, "installedPlugins");
|
||||||
|
}
|
||||||
|
|
||||||
export function getPendingPluginsLink(state: object) {
|
export function getPendingPluginsLink(state: object) {
|
||||||
return getLink(state, "pendingPlugins");
|
return getLink(state, "pendingPlugins");
|
||||||
}
|
}
|
||||||
@@ -169,10 +185,18 @@ export function getUsersLink(state: object) {
|
|||||||
return getLink(state, "users");
|
return getLink(state, "users");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mustGetUsersLink(state: object) {
|
||||||
|
return mustGetLink(state, "users");
|
||||||
|
}
|
||||||
|
|
||||||
export function getRepositoryRolesLink(state: object) {
|
export function getRepositoryRolesLink(state: object) {
|
||||||
return getLink(state, "repositoryRoles");
|
return getLink(state, "repositoryRoles");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mustGetRepositoryRolesLink(state: object) {
|
||||||
|
return mustGetLink(state, "repositoryRoles");
|
||||||
|
}
|
||||||
|
|
||||||
export function getRepositoryVerbsLink(state: object) {
|
export function getRepositoryVerbsLink(state: object) {
|
||||||
return getLink(state, "repositoryVerbs");
|
return getLink(state, "repositoryVerbs");
|
||||||
}
|
}
|
||||||
@@ -181,10 +205,18 @@ export function getGroupsLink(state: object) {
|
|||||||
return getLink(state, "groups");
|
return getLink(state, "groups");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mustGetGroupsLink(state: object) {
|
||||||
|
return mustGetLink(state, "groups");
|
||||||
|
}
|
||||||
|
|
||||||
export function getConfigLink(state: object) {
|
export function getConfigLink(state: object) {
|
||||||
return getLink(state, "config");
|
return getLink(state, "config");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mustGetConfigLink(state: object) {
|
||||||
|
return mustGetLink(state, "config");
|
||||||
|
}
|
||||||
|
|
||||||
export function getRepositoriesLink(state: object) {
|
export function getRepositoriesLink(state: object) {
|
||||||
return getLink(state, "repositories");
|
return getLink(state, "repositories");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { WithTranslation, withTranslation } from "react-i18next";
|
|||||||
import { History } from "history";
|
import { History } from "history";
|
||||||
import { User } from "@scm-manager/ui-types";
|
import { User } from "@scm-manager/ui-types";
|
||||||
import { Page } from "@scm-manager/ui-components";
|
import { Page } from "@scm-manager/ui-components";
|
||||||
import { getUsersLink } from "../../modules/indexResource";
|
import { mustGetUsersLink } from "../../modules/indexResource";
|
||||||
import { createUser, createUserReset, getCreateUserFailure, isCreateUserPending } from "../modules/users";
|
import { createUser, createUserReset, getCreateUserFailure, isCreateUserPending } from "../modules/users";
|
||||||
import UserForm from "../components/UserForm";
|
import UserForm from "../components/UserForm";
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
const mapStateToProps = (state: any) => {
|
const mapStateToProps = (state: any) => {
|
||||||
const loading = isCreateUserPending(state);
|
const loading = isCreateUserPending(state);
|
||||||
const error = getCreateUserFailure(state);
|
const error = getCreateUserFailure(state);
|
||||||
const usersLink = getUsersLink(state);
|
const usersLink = mustGetUsersLink(state);
|
||||||
return {
|
return {
|
||||||
usersLink,
|
usersLink,
|
||||||
loading,
|
loading,
|
||||||
|
|||||||
@@ -43,10 +43,9 @@ import EditUser from "./EditUser";
|
|||||||
import { fetchUserByName, getFetchUserFailure, getUserByName, isFetchUserPending } from "../modules/users";
|
import { fetchUserByName, getFetchUserFailure, getUserByName, isFetchUserPending } from "../modules/users";
|
||||||
import { EditUserNavLink, SetPasswordNavLink, SetPermissionsNavLink, SetPublicKeysNavLink } from "./../components/navLinks";
|
import { EditUserNavLink, SetPasswordNavLink, SetPermissionsNavLink, SetPublicKeysNavLink } from "./../components/navLinks";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { getUsersLink } from "../../modules/indexResource";
|
import { mustGetUsersLink } from "../../modules/indexResource";
|
||||||
import SetUserPassword from "../components/SetUserPassword";
|
import SetUserPassword from "../components/SetUserPassword";
|
||||||
import SetPermissions from "../../permissions/components/SetPermissions";
|
import SetPermissions from "../../permissions/components/SetPermissions";
|
||||||
import AddPublicKey from "../components/publicKeys/AddPublicKey";
|
|
||||||
import SetPublicKeys from "../components/publicKeys/SetPublicKeys";
|
import SetPublicKeys from "../components/publicKeys/SetPublicKeys";
|
||||||
|
|
||||||
type Props = RouteComponentProps &
|
type Props = RouteComponentProps &
|
||||||
@@ -148,7 +147,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
const user = getUserByName(state, name);
|
const user = getUserByName(state, name);
|
||||||
const loading = isFetchUserPending(state, name);
|
const loading = isFetchUserPending(state, name);
|
||||||
const error = getFetchUserFailure(state, name);
|
const error = getFetchUserFailure(state, name);
|
||||||
const usersLink = getUsersLink(state);
|
const usersLink = mustGetUsersLink(state);
|
||||||
return {
|
return {
|
||||||
usersLink,
|
usersLink,
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import {
|
|||||||
PageActions,
|
PageActions,
|
||||||
urls
|
urls
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import { getUsersLink } from "../../modules/indexResource";
|
import { mustGetUsersLink } from "../../modules/indexResource";
|
||||||
import {
|
import {
|
||||||
fetchUsersByPage,
|
fetchUsersByPage,
|
||||||
getFetchUsersFailure,
|
getFetchUsersFailure,
|
||||||
@@ -129,7 +129,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
|
|||||||
const page = urls.getPageFromMatch(match);
|
const page = urls.getPageFromMatch(match);
|
||||||
const canAddUsers = isPermittedToCreateUsers(state);
|
const canAddUsers = isPermittedToCreateUsers(state);
|
||||||
const list = selectListAsCollection(state);
|
const list = selectListAsCollection(state);
|
||||||
const usersLink = getUsersLink(state);
|
const usersLink = mustGetUsersLink(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users,
|
users,
|
||||||
|
|||||||
Reference in New Issue
Block a user