Add UI for namespace permissions

This commit is contained in:
René Pfeuffer
2020-09-17 07:49:37 +02:00
parent f9c096f9e7
commit 6b9079fd68
8 changed files with 386 additions and 86 deletions

View File

@@ -0,0 +1,9 @@
{
"namespaceRoot": {
"menu": {
"navigationLabel": "Namespace",
"settingsNavLink": "Settings",
"permissionsNavLink": "Permissions"
}
}
}

View File

@@ -46,6 +46,7 @@ import CreateGroup from "../groups/containers/CreateGroup";
import Admin from "../admin/containers/Admin";
import Profile from "./Profile";
import NamespaceRoot from "../repos/namespaces/containers/NamespaceRoot";
type Props = {
me: Me;
@@ -80,6 +81,7 @@ class Main extends React.Component<Props> {
<ProtectedRoute exact path="/repos/:namespace" 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="/namespace/:namespaceName" component={NamespaceRoot} authenticated={authenticated} />
<Redirect exact strict from="/users" to="/users/" />
<ProtectedRoute exact path="/users/" component={Users} authenticated={authenticated} />
<ProtectedRoute path="/users/create" component={CreateUser} authenticated={authenticated} />

View File

@@ -25,7 +25,7 @@
import { apiClient } from "@scm-manager/ui-components";
import * as types from "../../modules/types";
import {
Action,
Action, Namespace,
NamespaceCollection,
Repository,
RepositoryCollection,
@@ -66,6 +66,11 @@ export const DELETE_REPO_PENDING = `${DELETE_REPO}_${types.PENDING_SUFFIX}`;
export const DELETE_REPO_SUCCESS = `${DELETE_REPO}_${types.SUCCESS_SUFFIX}`;
export const DELETE_REPO_FAILURE = `${DELETE_REPO}_${types.FAILURE_SUFFIX}`;
export const FETCH_NAMESPACE = "scm/repos/FETCH_NAMESPACE";
export const FETCH_NAMESPACE_PENDING = `${FETCH_NAMESPACE}_${types.PENDING_SUFFIX}`;
export const FETCH_NAMESPACE_SUCCESS = `${FETCH_NAMESPACE}_${types.SUCCESS_SUFFIX}`;
export const FETCH_NAMESPACE_FAILURE = `${FETCH_NAMESPACE}_${types.FAILURE_SUFFIX}`;
export const CONTENT_TYPE = "application/vnd.scmm-repository+json;v=2";
export const CUSTOM_NAMESPACE_STRATEGY = "CustomNamespaceStrategy";
@@ -388,6 +393,50 @@ export function deleteRepoFailure(repository: Repository, error: Error): Action
};
}
export function fetchNamespace(link: string, namespaceName: string) {
return function(dispatch: any) {
dispatch(fetchNamespacePending(namespaceName));
return apiClient
.get(link)
.then(response => response.json())
.then(namespace => {
dispatch(fetchNamespaceSuccess(namespace));
})
.catch(err => {
dispatch(fetchNamespaceFailure(namespaceName, err));
});
};
}
export function fetchNamespacePending(namespaceName: string): Action {
return {
type: FETCH_NAMESPACE_PENDING,
payload: {
namespaceName
},
itemId: namespaceName
};
}
export function fetchNamespaceSuccess(namespace: Namespace): Action {
return {
type: FETCH_NAMESPACE_SUCCESS,
payload: namespace,
itemId: namespace.namespace
};
}
export function fetchNamespaceFailure(namespaceName: string, error: Error): Action {
return {
type: FETCH_NAMESPACE_FAILURE,
payload: {
namespaceName,
error
},
itemId: namespaceName
};
}
// reducer
function createIdentifier(repository: Repository) {
@@ -425,6 +474,17 @@ const reducerByNames = (state: object, repository: Repository) => {
};
};
const reducerForNamespace = (state: object, namespace: Namespace) => {
const identifier = namespace.namespace;
return {
...state,
namespacesByNames: {
...state.namespacesByNames,
[identifier]: namespace
}
};
};
const reducerForNamespaces = (state: object, namespaces: NamespaceCollection) => {
return {
...state,
@@ -449,6 +509,8 @@ export default function reducer(
return reducerForNamespaces(state, action.payload);
case FETCH_REPO_SUCCESS:
return reducerByNames(state, action.payload);
case FETCH_NAMESPACE_SUCCESS:
return reducerForNamespace(state, action.payload);
default:
return state;
}
@@ -497,10 +559,17 @@ export function getFetchNamespacesFailure(state: object) {
return getFailure(state, FETCH_NAMESPACES);
}
export function getNamespace(state: object, namespace: string) {
if (state.namespaces) {
return state.namespaces[namespace];
}
export function isFetchNamespacePending(state: object) {
return isPending(state, FETCH_NAMESPACE);
}
export function getFetchNamespaceFailure(state: object) {
return getFailure(state, FETCH_NAMESPACE);
}
export function fetchNamespaceByName(link: string, namespaceName: string) {
const namespaceUrl = link.endsWith("/") ? link : link + "/";
return fetchNamespace(`${namespaceUrl}${namespaceName}`, namespaceName);
}
export function isFetchRepoPending(state: object, namespace: string, name: string) {
@@ -511,6 +580,12 @@ export function getFetchRepoFailure(state: object, namespace: string, name: stri
return getFailure(state, FETCH_REPO, namespace + "/" + name);
}
export function getNamespace(state: object, namespaceName: string) {
if (state.repos && state.repos.namespacesByNames) {
return state.repos.namespacesByNames[namespaceName];
}
}
export function isAbleToCreateRepos(state: object) {
return !!(state.repos && state.repos.list && state.repos.list._links && state.repos.list._links.create);
}
@@ -539,7 +614,12 @@ export function getDeleteRepoFailure(state: object, namespace: string, name: str
return getFailure(state, DELETE_REPO, namespace + "/" + name);
}
export function getPermissionsLink(state: object, namespace: string, name: string) {
const repo = getRepository(state, namespace, name);
export function getPermissionsLink(state: object, namespaceName: string, repoName?: string) {
if (repoName) {
const repo = getRepository(state, namespaceName, repoName);
return repo && repo._links ? repo._links.permissions.href : undefined;
} else {
const namespace = getNamespace(state, namespaceName);
return namespace && namespace._links ? namespace._links.permissions.href : undefined;
}
}

View File

@@ -0,0 +1,146 @@
/*
* 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 { WithTranslation, withTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Redirect, Route, RouteComponentProps, Switch } from "react-router-dom";
import { fetchNamespaceByName, getNamespace, isFetchNamespacePending } from "../../modules/repos";
import { getNamespacesLink } from "../../../modules/indexResource";
import { Namespace } from "@scm-manager/ui-types";
import {
CustomQueryFlexWrappedColumns,
ErrorPage,
Loading,
Page, PrimaryContentColumn,
SecondaryNavigation,
SecondaryNavigationColumn,
StateMenuContextProvider,
SubNavigation
} from "@scm-manager/ui-components";
import Permissions from "../../permissions/containers/Permissions";
import { ExtensionPoint } from "@scm-manager/ui-extensions";
import PermissionsNavLink from "./PermissionsNavLink";
type Props = RouteComponentProps &
WithTranslation & {
loading: boolean;
namespaceName: string;
namespacesLink: string;
namespace: Namespace;
// dispatch functions
fetchNamespace: (link: string, namespace: string) => void;
};
class NamespaceRoot extends React.Component<Props> {
componentDidMount() {
const { namespacesLink, namespaceName, fetchNamespace } = this.props;
fetchNamespace(namespacesLink, namespaceName);
}
stripEndingSlash = (url: string) => {
if (url.endsWith("/")) {
return url.substring(0, url.length - 1);
}
return url;
};
matchedUrl = () => {
return this.stripEndingSlash(this.props.match.url);
};
render() {
const { loading, error, namespaceName, namespace, t } = this.props;
const url = this.matchedUrl();
const extensionProps = {
namespace,
url
};
if (error) {
return (
<ErrorPage title={t("namespaceRoot.errorTitle")} subtitle={t("namespaceRoot.errorSubtitle")} error={error} />
);
}
if (!namespace || loading) {
return <Loading />;
}
return (
<StateMenuContextProvider>
<Page title={namespaceName}>
<CustomQueryFlexWrappedColumns>
<PrimaryContentColumn>
<Switch>
<Redirect exact from={`${url}/settings`} to={`${url}/settings/permissions`} />
<Route
path={`${url}/settings/permissions`}
render={() => {
return <Permissions namespace={namespaceName} />;
}}
/>
</Switch>
</PrimaryContentColumn>
<SecondaryNavigationColumn>
<SecondaryNavigation label={t("namespaceRoot.menu.navigationLabel")}>
<ExtensionPoint name="namespace.navigation.topLevel" props={extensionProps} renderAll={true} />
<ExtensionPoint name="namespace.route" props={extensionProps} renderAll={true} />
<SubNavigation
to={`${url}/settings`}
label={t("namespaceRoot.menu.settingsNavLink")}
title={t("namespaceRoot.menu.settingsNavLink")}
>
<PermissionsNavLink permissionUrl={`${url}/settings/permissions`} namespace={namespace} />
<ExtensionPoint name="namespace.setting" props={extensionProps} renderAll={true} />
</SubNavigation>
</SecondaryNavigation>
</SecondaryNavigationColumn>
</CustomQueryFlexWrappedColumns>
</Page>
</StateMenuContextProvider>
);
// return <h1>{`HALLO ${this.props.namespace}`}</h1>;
}
}
const mapStateToProps = (state: any, ownProps: Props) => {
const { namespaceName } = ownProps.match.params;
const namespacesLink = getNamespacesLink(state);
const namespace = getNamespace(state, namespaceName);
const loading = isFetchNamespacePending(state);
return { namespaceName, namespacesLink, loading, namespace };
};
const mapDispatchToProps = (dispatch: any) => {
return {
fetchNamespace: (link: string, namespaceName: string) => {
dispatch(fetchNamespaceByName(link, namespaceName));
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("namespaces")(NamespaceRoot));

View File

@@ -0,0 +1,47 @@
/*
* 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 { WithTranslation, withTranslation } from "react-i18next";
import { Namespace } from "@scm-manager/ui-types";
import { NavLink } from "@scm-manager/ui-components";
type Props = WithTranslation & {
permissionUrl: string;
namespace: Namespace;
};
class PermissionsNavLink extends React.Component<Props> {
hasPermissionsLink = () => {
return this.props.namespace._links.permissions;
};
render() {
if (!this.hasPermissionsLink()) {
return null;
}
const { permissionUrl, t } = this.props;
return <NavLink to={permissionUrl} label={t("namespaceRoot.menu.permissionsNavLink")} />;
}
}
export default withTranslation("namespaces")(PermissionsNavLink);

View File

@@ -57,13 +57,12 @@ import {
getRepositoryVerbsLink,
getUserAutoCompleteLink
} from "../../../modules/indexResource";
type Props = WithTranslation & {
availablePermissions: boolean;
availableRepositoryRoles: RepositoryRole[];
availableVerbs: string[];
namespace: string;
repoName: string;
repoName?: string;
loading: boolean;
error: Error;
permissions: PermissionCollection;
@@ -77,17 +76,17 @@ type Props = WithTranslation & {
// dispatch functions
fetchAvailablePermissionsIfNeeded: (repositoryRolesLink: string, repositoryVerbsLink: string) => void;
fetchPermissions: (link: string, namespace: string, repoName: string) => void;
fetchPermissions: (link: string, namespace: string, repoName?: string) => void;
createPermission: (
link: string,
permission: PermissionCreateEntry,
namespace: string,
repoName: string,
repoName?: string,
callback?: () => void
) => void;
createPermissionReset: (p1: string, p2: string) => void;
modifyPermissionReset: (p1: string, p2: string) => void;
deletePermissionReset: (p1: string, p2: string) => void;
createPermissionReset: (namespace: string, repoName?: string) => void;
modifyPermissionReset: (namespace: string, repoName?: string) => void;
deletePermissionReset: (namespace: string, repoName?: string) => void;
// context props
match: any;
@@ -241,7 +240,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
const mapDispatchToProps = (dispatch: any) => {
return {
fetchPermissions: (link: string, namespace: string, repoName: string) => {
fetchPermissions: (link: string, namespace: string, repoName?: string) => {
dispatch(fetchPermissions(link, namespace, repoName));
},
fetchAvailablePermissionsIfNeeded: (repositoryRolesLink: string, repositoryVerbsLink: string) => {
@@ -256,13 +255,13 @@ const mapDispatchToProps = (dispatch: any) => {
) => {
dispatch(createPermission(link, permission, namespace, repoName, callback));
},
createPermissionReset: (namespace: string, repoName: string) => {
createPermissionReset: (namespace: string, repoName?: string) => {
dispatch(createPermissionReset(namespace, repoName));
},
modifyPermissionReset: (namespace: string, repoName: string) => {
modifyPermissionReset: (namespace: string, repoName?: string) => {
dispatch(modifyPermissionReset(namespace, repoName));
},
deletePermissionReset: (namespace: string, repoName: string) => {
deletePermissionReset: (namespace: string, repoName?: string) => {
dispatch(deletePermissionReset(namespace, repoName));
}
};

View File

@@ -43,14 +43,14 @@ type Props = WithTranslation & {
availableRepositoryRoles: RepositoryRole[];
availableRepositoryVerbs: string[];
submitForm: (p: Permission) => void;
modifyPermission: (permission: Permission, namespace: string, name: string) => void;
modifyPermission: (permission: Permission, namespace: string, name?: string) => void;
permission: Permission;
namespace: string;
repoName: string;
repoName?: string;
match: any;
history: History;
loading: boolean;
deletePermission: (permission: Permission, namespace: string, name: string) => void;
deletePermission: (permission: Permission, namespace: string, name?: string) => void;
deleteLoading: boolean;
};

View File

@@ -131,7 +131,7 @@ export function fetchAvailableFailure(error: Error): Action {
// fetch permissions
export function fetchPermissions(link: string, namespace: string, repoName: string) {
export function fetchPermissions(link: string, namespace: string, repoName?: string) {
return function(dispatch: any) {
dispatch(fetchPermissionsPending(namespace, repoName));
return apiClient
@@ -146,26 +146,26 @@ export function fetchPermissions(link: string, namespace: string, repoName: stri
};
}
export function fetchPermissionsPending(namespace: string, repoName: string): Action {
export function fetchPermissionsPending(namespace: string, repoName?: string): Action {
return {
type: FETCH_PERMISSIONS_PENDING,
payload: {
namespace,
repoName
},
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
export function fetchPermissionsSuccess(permissions: any, namespace: string, repoName: string): Action {
export function fetchPermissionsSuccess(permissions: any, namespace: string, repoName?: string): Action {
return {
type: FETCH_PERMISSIONS_SUCCESS,
payload: permissions,
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
export function fetchPermissionsFailure(namespace: string, repoName: string, error: Error): Action {
export function fetchPermissionsFailure(namespace: string, repoName?: string, error: Error): Action {
return {
type: FETCH_PERMISSIONS_FAILURE,
payload: {
@@ -173,13 +173,13 @@ export function fetchPermissionsFailure(namespace: string, repoName: string, err
repoName,
error
},
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
// modify permission
export function modifyPermission(permission: Permission, namespace: string, repoName: string, callback?: () => void) {
export function modifyPermission(permission: Permission, namespace: string, repoName?: string, callback?: () => void) {
return function(dispatch: any) {
dispatch(modifyPermissionPending(permission, namespace, repoName));
return apiClient
@@ -196,7 +196,7 @@ export function modifyPermission(permission: Permission, namespace: string, repo
};
}
export function modifyPermissionPending(permission: Permission, namespace: string, repoName: string): Action {
export function modifyPermissionPending(permission: Permission, namespace: string, repoName?: string): Action {
return {
type: MODIFY_PERMISSION_PENDING,
payload: permission,
@@ -204,12 +204,12 @@ export function modifyPermissionPending(permission: Permission, namespace: strin
};
}
export function modifyPermissionSuccess(permission: Permission, namespace: string, repoName: string): Action {
export function modifyPermissionSuccess(permission: Permission, namespace: string, repoName?: string): Action {
return {
type: MODIFY_PERMISSION_SUCCESS,
payload: {
permission,
position: namespace + "/" + repoName
position: createPermissionStateKey(namespace, repoName)
},
itemId: createItemId(permission, namespace, repoName)
};
@@ -219,7 +219,7 @@ export function modifyPermissionFailure(
permission: Permission,
error: Error,
namespace: string,
repoName: string
repoName?: string
): Action {
return {
type: MODIFY_PERMISSION_FAILURE,
@@ -240,14 +240,14 @@ function newPermissions(oldPermissions: PermissionCollection, newPermission: Per
}
}
export function modifyPermissionReset(namespace: string, repoName: string) {
export function modifyPermissionReset(namespace: string, repoName?: string) {
return {
type: MODIFY_PERMISSION_RESET,
payload: {
namespace,
repoName
},
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
@@ -256,7 +256,7 @@ export function createPermission(
link: string,
permission: PermissionCreateEntry,
namespace: string,
repoName: string,
repoName?: string,
callback?: () => void
) {
return function(dispatch: Dispatch) {
@@ -281,48 +281,48 @@ export function createPermission(
export function createPermissionPending(
permission: PermissionCreateEntry,
namespace: string,
repoName: string
repoName?: string
): Action {
return {
type: CREATE_PERMISSION_PENDING,
payload: permission,
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
export function createPermissionSuccess(
permission: PermissionCreateEntry,
namespace: string,
repoName: string
repoName?: string
): Action {
return {
type: CREATE_PERMISSION_SUCCESS,
payload: {
permission,
position: namespace + "/" + repoName
position: createPermissionStateKey(namespace, repoName)
},
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
export function createPermissionFailure(error: Error, namespace: string, repoName: string): Action {
export function createPermissionFailure(error: Error, namespace: string, repoName?: string): Action {
return {
type: CREATE_PERMISSION_FAILURE,
payload: error,
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
export function createPermissionReset(namespace: string, repoName: string) {
export function createPermissionReset(namespace: string, repoName?: string) {
return {
type: CREATE_PERMISSION_RESET,
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
// delete permission
export function deletePermission(permission: Permission, namespace: string, repoName: string, callback?: () => void) {
export function deletePermission(permission: Permission, namespace: string, repoName?: string, callback?: () => void) {
return function(dispatch: any) {
dispatch(deletePermissionPending(permission, namespace, repoName));
return apiClient
@@ -339,7 +339,7 @@ export function deletePermission(permission: Permission, namespace: string, repo
};
}
export function deletePermissionPending(permission: Permission, namespace: string, repoName: string): Action {
export function deletePermissionPending(permission: Permission, namespace: string, repoName?: string): Action {
return {
type: DELETE_PERMISSION_PENDING,
payload: permission,
@@ -347,12 +347,12 @@ export function deletePermissionPending(permission: Permission, namespace: strin
};
}
export function deletePermissionSuccess(permission: Permission, namespace: string, repoName: string): Action {
export function deletePermissionSuccess(permission: Permission, namespace: string, repoName?: string): Action {
return {
type: DELETE_PERMISSION_SUCCESS,
payload: {
permission,
position: namespace + "/" + repoName
position: createPermissionStateKey(namespace, repoName)
},
itemId: createItemId(permission, namespace, repoName)
};
@@ -361,7 +361,7 @@ export function deletePermissionSuccess(permission: Permission, namespace: strin
export function deletePermissionFailure(
permission: Permission,
namespace: string,
repoName: string,
repoName?: string,
error: Error
): Action {
return {
@@ -374,14 +374,14 @@ export function deletePermissionFailure(
};
}
export function deletePermissionReset(namespace: string, repoName: string) {
export function deletePermissionReset(namespace: string, repoName?: string) {
return {
type: DELETE_PERMISSION_RESET,
payload: {
namespace,
repoName
},
itemId: namespace + "/" + repoName
itemId: createPermissionStateKey(namespace, repoName)
};
}
@@ -398,9 +398,9 @@ function deletePermissionFromState(oldPermissions: PermissionCollection, permiss
return newPermission;
}
function createItemId(permission: Permission, namespace: string, repoName: string) {
function createItemId(permission: Permission, namespace: string, repoName?: string) {
const groupPermission = permission.groupPermission ? "@" : "";
return namespace + "/" + repoName + "/" + groupPermission + permission.name;
return createPermissionStateKey(namespace, repoName) + "/" + groupPermission + permission.name;
}
// reducer
@@ -427,7 +427,7 @@ export default function reducer(
createPermission: !!action.payload._links.create
}
};
case MODIFY_PERMISSION_SUCCESS:
case MODIFY_PERMISSION_SUCCESS: {
const positionOfPermission = action.payload.position;
const newPermission = newPermissions(state[action.payload.position].entries, action.payload.permission);
return {
@@ -437,7 +437,8 @@ export default function reducer(
entries: newPermission
}
};
case CREATE_PERMISSION_SUCCESS:
}
case CREATE_PERMISSION_SUCCESS: {
// return state;
const position = action.payload.position;
const permissions = state[action.payload.position].entries;
@@ -449,9 +450,10 @@ export default function reducer(
entries: permissions
}
};
case DELETE_PERMISSION_SUCCESS:
}
case DELETE_PERMISSION_SUCCESS: {
const permissionPosition = action.payload.position;
const new_Permissions = deletePermissionFromState(
const newPermissions = deletePermissionFromState(
state[action.payload.position].entries,
action.payload.permission
);
@@ -459,9 +461,10 @@ export default function reducer(
...state,
[permissionPosition]: {
...state[permissionPosition],
entries: new_Permissions
entries: newPermissions
}
};
}
default:
return state;
}
@@ -490,9 +493,9 @@ function available(state: object) {
return {};
}
export function getPermissionsOfRepo(state: object, namespace: string, repoName: string) {
if (state.permissions && state.permissions[namespace + "/" + repoName]) {
return state.permissions[namespace + "/" + repoName].entries;
export function getPermissionsOfRepo(state: object, namespace: string, repoName?: string) {
if (state.permissions && state.permissions[createPermissionStateKey(namespace, repoName)]) {
return state.permissions[createPermissionStateKey(namespace, repoName)].entries;
}
}
@@ -500,52 +503,62 @@ export function isFetchAvailablePermissionsPending(state: object) {
return isPending(state, FETCH_AVAILABLE, "available");
}
export function isFetchPermissionsPending(state: object, namespace: string, repoName: string) {
return isPending(state, FETCH_PERMISSIONS, namespace + "/" + repoName);
export function isFetchPermissionsPending(state: object, namespace: string, repoName?: string) {
return isPending(state, FETCH_PERMISSIONS, createPermissionStateKey(namespace, repoName));
}
export function getFetchAvailablePermissionsFailure(state: object) {
return getFailure(state, FETCH_AVAILABLE, "available");
}
export function getFetchPermissionsFailure(state: object, namespace: string, repoName: string) {
return getFailure(state, FETCH_PERMISSIONS, namespace + "/" + repoName);
export function getFetchPermissionsFailure(state: object, namespace: string, repoName?: string) {
return getFailure(state, FETCH_PERMISSIONS, createPermissionStateKey(namespace, repoName));
}
export function isModifyPermissionPending(state: object, namespace: string, repoName: string, permission: Permission) {
return isPending(state, MODIFY_PERMISSION, createItemId(permission, namespace, repoName));
export function isModifyPermissionPending(state: object, namespace: string, repoName?: string, permission: Permission) {
return isPending(state, MODIFY_PERMISSION, createItemId(permission, createPermissionStateKey(namespace, repoName)));
}
export function getModifyPermissionFailure(state: object, namespace: string, repoName: string, permission: Permission) {
return getFailure(state, MODIFY_PERMISSION, createItemId(permission, namespace, repoName));
export function getModifyPermissionFailure(
state: object,
namespace: string,
repoName?: string,
permission: Permission
) {
return getFailure(state, MODIFY_PERMISSION, createItemId(permission, createPermissionStateKey(namespace, repoName)));
}
export function hasCreatePermission(state: object, namespace: string, repoName: string) {
if (state.permissions && state.permissions[namespace + "/" + repoName])
return state.permissions[namespace + "/" + repoName].createPermission;
export function hasCreatePermission(state: object, namespace: string, repoName?: string) {
if (state.permissions && state.permissions[createPermissionStateKey(namespace, repoName)])
return state.permissions[createPermissionStateKey(namespace, repoName)].createPermission;
else return null;
}
export function isCreatePermissionPending(state: object, namespace: string, repoName: string) {
return isPending(state, CREATE_PERMISSION, namespace + "/" + repoName);
export function isCreatePermissionPending(state: object, namespace: string, repoName?: string) {
return isPending(state, CREATE_PERMISSION, createPermissionStateKey(namespace, repoName));
}
export function getCreatePermissionFailure(state: object, namespace: string, repoName: string) {
return getFailure(state, CREATE_PERMISSION, namespace + "/" + repoName);
export function getCreatePermissionFailure(state: object, namespace: string, repoName?: string) {
return getFailure(state, CREATE_PERMISSION, createPermissionStateKey(namespace, repoName));
}
export function isDeletePermissionPending(state: object, namespace: string, repoName: string, permission: Permission) {
export function isDeletePermissionPending(state: object, namespace: string, repoName?: string, permission: Permission) {
return isPending(state, DELETE_PERMISSION, createItemId(permission, namespace, repoName));
}
export function getDeletePermissionFailure(state: object, namespace: string, repoName: string, permission: Permission) {
export function getDeletePermissionFailure(
state: object,
namespace: string,
repoName?: string,
permission: Permission
) {
return getFailure(state, DELETE_PERMISSION, createItemId(permission, namespace, repoName));
}
export function getDeletePermissionsFailure(state: object, namespace: string, repoName: string) {
export function getDeletePermissionsFailure(state: object, namespace: string, repoName?: string) {
const permissions =
state.permissions && state.permissions[namespace + "/" + repoName]
? state.permissions[namespace + "/" + repoName].entries
state.permissions && state.permissions[createPermissionStateKey(namespace, repoName)]
? state.permissions[createPermissionStateKey(namespace, repoName)].entries
: null;
if (permissions == null) return undefined;
for (let i = 0; i < permissions.length; i++) {
@@ -556,10 +569,10 @@ export function getDeletePermissionsFailure(state: object, namespace: string, re
return null;
}
export function getModifyPermissionsFailure(state: object, namespace: string, repoName: string) {
export function getModifyPermissionsFailure(state: object, namespace: string, repoName?: string) {
const permissions =
state.permissions && state.permissions[namespace + "/" + repoName]
? state.permissions[namespace + "/" + repoName].entries
state.permissions && state.permissions[createPermissionStateKey(namespace, repoName)]
? state.permissions[createPermissionStateKey(namespace, repoName)].entries
: null;
if (permissions == null) return undefined;
for (let i = 0; i < permissions.length; i++) {
@@ -570,6 +583,10 @@ export function getModifyPermissionsFailure(state: object, namespace: string, re
return null;
}
function createPermissionStateKey(namespace: string, repoName?: string) {
return namespace + (repoName ? "/" + repoName : "");
}
export function findVerbsForRole(availableRepositoryRoles: RepositoryRole[], roleName: string) {
const matchingRole = availableRepositoryRoles.find(role => roleName === role.name);
if (matchingRole) {