X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/72ed766fa1a94853a1c57d0f43390a81e3d92c90..377e37a3c0c4f376cffb44709640a112df180323:/src/store/context-menu/context-menu-actions.ts diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts index 1f766bd3..9a5b3099 100644 --- a/src/store/context-menu/context-menu-actions.ts +++ b/src/store/context-menu/context-menu-actions.ts @@ -8,7 +8,6 @@ import { ContextMenuKind } from '~/views-components/context-menu/context-menu'; import { Dispatch } from 'redux'; import { RootState } from '~/store/store'; import { getResource, getResourceWithEditableStatus } from '../resources/resources'; -import { ProjectResource } from '~/models/project'; import { UserResource } from '~/models/user'; import { isSidePanelTreeCategory } from '~/store/side-panel-tree/side-panel-tree-actions'; import { extractUuidKind, ResourceKind, EditableResource } from '~/models/resource'; @@ -18,6 +17,12 @@ import { SshKeyResource } from '~/models/ssh-key'; import { VirtualMachinesResource } from '~/models/virtual-machines'; import { KeepServiceResource } from '~/models/keep-services'; import { ProcessResource } from '~/models/process'; +import { CollectionResource } from '~/models/collection'; +import { GroupClass, GroupResource } from '~/models/group'; +import { GroupContentsResource } from '~/services/groups-service/groups-service'; +import { getProjectPanelCurrentUuid } from '~/store/project-panel/project-panel-action'; +import { matchProjectRoute } from '~/routes/routes'; +import { RouterState } from "react-router-redux"; export const contextMenuActions = unionize({ OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(), @@ -156,9 +161,8 @@ export const openRootProjectContextMenu = (event: React.MouseEvent, export const openProjectContextMenu = (event: React.MouseEvent, resourceUuid: string) => (dispatch: Dispatch, getState: () => RootState) => { - const { isAdmin, uuid: userUuid } = getState().auth.user!; - const res = getResourceWithEditableStatus(resourceUuid, userUuid)(getState().resources); - const menuKind = resourceKindToContextMenuKind(resourceUuid, isAdmin, (res || {} as EditableResource).isEditable); + const res = getResource(resourceUuid)(getState().resources); + const menuKind = dispatch(resourceUuidToContextMenuKind(resourceUuid)); if (res && menuKind) { dispatch(openContextMenu(event, { name: res.name, @@ -166,7 +170,7 @@ export const openProjectContextMenu = (event: React.MouseEvent, res kind: res.kind, menuKind, ownerUuid: res.ownerUuid, - isTrashed: res.isTrashed + isTrashed: ('isTrashed' in res) ? res.isTrashed: false, })); } }; @@ -200,24 +204,71 @@ export const openProcessContextMenu = (event: React.MouseEvent, pro } }; -export const resourceKindToContextMenuKind = (uuid: string, isAdmin?: boolean, isEditable?: boolean) => { - const kind = extractUuidKind(uuid); - switch (kind) { - case ResourceKind.PROJECT: - return !isAdmin ? - isEditable ? ContextMenuKind.PROJECT : ContextMenuKind.READONLY_PROJECT : - ContextMenuKind.PROJECT_ADMIN; - case ResourceKind.COLLECTION: - return !isAdmin ? - isEditable ? ContextMenuKind.COLLECTION_RESOURCE : ContextMenuKind.READONLY_COLLECTION : - ContextMenuKind.COLLECTION_ADMIN; - case ResourceKind.PROCESS: - return !isAdmin ? ContextMenuKind.PROCESS_RESOURCE : ContextMenuKind.PROCESS_ADMIN; - case ResourceKind.USER: - return ContextMenuKind.ROOT_PROJECT; - case ResourceKind.LINK: - return ContextMenuKind.LINK; - default: - return; +export const isProjectRoute = (router: RouterState) => { + if (router === undefined) { + return false; } + const pathname = router.location ? router.location.pathname : ''; + const matchProject = matchProjectRoute(pathname); + return Boolean(matchProject); }; + +export const resourceUuidToContextMenuKind = (uuid: string) => + (dispatch: Dispatch, getState: () => RootState) => { + const { isAdmin: isAdminUser, uuid: userUuid } = getState().auth.user!; + const kind = extractUuidKind(uuid); + const resource = getResourceWithEditableStatus(uuid, userUuid)(getState().resources); + + // When viewing the contents of a filter group, all contents should be treated as read only. + let inFilterGroup = false; + const { router } = getState(); + if (isProjectRoute(router)) { + const projectUuid = getProjectPanelCurrentUuid(getState()); + if (projectUuid !== undefined) { + const project = getResource(projectUuid)(getState().resources); + if (project) { + if (project.groupClass === GroupClass.FILTER) { + inFilterGroup = true; + } + } + } + } + + const isEditable = (isAdminUser || (resource || {} as EditableResource).isEditable) && !inFilterGroup; + switch (kind) { + case ResourceKind.PROJECT: + return (isAdminUser && !inFilterGroup) + ? (resource && resource.groupClass === GroupClass.PROJECT) + ? ContextMenuKind.PROJECT_ADMIN + : ContextMenuKind.READONLY_PROJECT + : isEditable + ? ContextMenuKind.PROJECT + : ContextMenuKind.READONLY_PROJECT; + case ResourceKind.COLLECTION: + const c = getResource(uuid)(getState().resources); + if (c === undefined) { return; } + const isOldVersion = c.uuid !== c.currentVersionUuid; + const isTrashed = c.isTrashed; + return isOldVersion + ? ContextMenuKind.OLD_VERSION_COLLECTION + : (isTrashed && isEditable) + ? ContextMenuKind.TRASHED_COLLECTION + : (isAdminUser && !inFilterGroup) + ? ContextMenuKind.COLLECTION_ADMIN + : isEditable + ? ContextMenuKind.COLLECTION + : ContextMenuKind.READONLY_COLLECTION; + case ResourceKind.PROCESS: + return (isAdminUser && !inFilterGroup) + ? ContextMenuKind.PROCESS_ADMIN + : inFilterGroup + ? ContextMenuKind.READONLY_PROCESS_RESOURCE + : ContextMenuKind.PROCESS_RESOURCE; + case ResourceKind.USER: + return ContextMenuKind.ROOT_PROJECT; + case ResourceKind.LINK: + return ContextMenuKind.LINK; + default: + return; + } + };