X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/f83344568cb070f716527288abe88a4ec5b0c305..7eb16e136a720bdfda5a4d4782d9cce1d00f5ded:/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 65ddcff2..e00b65b3 100644 --- a/src/store/context-menu/context-menu-actions.ts +++ b/src/store/context-menu/context-menu-actions.ts @@ -2,22 +2,25 @@ // // SPDX-License-Identifier: AGPL-3.0 -import { unionize, ofType, UnionOf } from '~/common/unionize'; +import { unionize, ofType, UnionOf } from 'common/unionize'; import { ContextMenuPosition } from "./context-menu-reducer"; -import { ContextMenuKind } from '~/views-components/context-menu/context-menu'; +import { ContextMenuKind } from 'views-components/context-menu/context-menu'; import { Dispatch } from 'redux'; -import { RootState } from '~/store/store'; -import { getResource } 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 } from '~/models/resource'; -import { Process } from '~/store/processes/process'; -import { RepositoryResource } from '~/models/repositories'; -import { SshKeyResource } from '~/models/ssh-key'; -import { VirtualMachinesResource } from '~/models/virtual-machines'; -import { KeepServiceResource } from '~/models/keep-services'; -import { NodeResource } from '~/models/node'; +import { RootState } from 'store/store'; +import { getResource, getResourceWithEditableStatus } from '../resources/resources'; +import { UserResource } from 'models/user'; +import { isSidePanelTreeCategory } from 'store/side-panel-tree/side-panel-tree-actions'; +import { extractUuidKind, ResourceKind, EditableResource, Resource } from 'models/resource'; +import { Process } from 'store/processes/process'; +import { RepositoryResource } from 'models/repositories'; +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 { LinkResource } from 'models/link'; export const contextMenuActions = unionize({ OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(), @@ -32,9 +35,13 @@ export type ContextMenuResource = { ownerUuid: string; description?: string; kind: ResourceKind, - menuKind: ContextMenuKind; + menuKind: ContextMenuKind | string; isTrashed?: boolean; - index?: number + isEditable?: boolean; + outputUuid?: string; + workflowUuid?: string; + storageClassesDesired?: string[]; + properties?: { [key: string]: string | string[] }; }; export const isKeyboardClick = (event: React.MouseEvent) => event.nativeEvent.detail === 0; @@ -54,15 +61,20 @@ export const openContextMenu = (event: React.MouseEvent, resource: ); }; -export const openCollectionFilesContextMenu = (event: React.MouseEvent) => +export const openCollectionFilesContextMenu = (event: React.MouseEvent, isWritable: boolean) => (dispatch: Dispatch, getState: () => RootState) => { const isCollectionFileSelected = JSON.stringify(getState().collectionPanelFiles).includes('"selected":true'); dispatch(openContextMenu(event, { name: '', uuid: '', ownerUuid: '', + description: '', kind: ResourceKind.COLLECTION, - menuKind: isCollectionFileSelected ? ContextMenuKind.COLLECTION_FILES : ContextMenuKind.COLLECTION_FILES_NOT_SELECTED + menuKind: isCollectionFileSelected + ? isWritable + ? ContextMenuKind.COLLECTION_FILES + : ContextMenuKind.READONLY_COLLECTION_FILES + : ContextMenuKind.COLLECTION_FILES_NOT_SELECTED })); }; @@ -110,16 +122,17 @@ export const openKeepServiceContextMenu = (event: React.MouseEvent, })); }; -export const openComputeNodeContextMenu = (event: React.MouseEvent, computeNode: NodeResource) => - (dispatch: Dispatch) => { - dispatch(openContextMenu(event, { - name: '', - uuid: computeNode.uuid, - ownerUuid: computeNode.ownerUuid, - kind: ResourceKind.NODE, - menuKind: ContextMenuKind.NODE - })); - }; +export const openApiClientAuthorizationContextMenu = + (event: React.MouseEvent, resourceUuid: string) => + (dispatch: Dispatch) => { + dispatch(openContextMenu(event, { + name: '', + uuid: resourceUuid, + ownerUuid: '', + kind: ResourceKind.API_CLIENT_AUTHORIZATION, + menuKind: ContextMenuKind.API_CLIENT_AUTHORIZATION + })); + }; export const openRootProjectContextMenu = (event: React.MouseEvent, projectUuid: string) => (dispatch: Dispatch, getState: () => RootState) => { @@ -136,17 +149,19 @@ export const openRootProjectContextMenu = (event: React.MouseEvent, } }; -export const openProjectContextMenu = (event: React.MouseEvent, projectUuid: string) => +export const openProjectContextMenu = (event: React.MouseEvent, resourceUuid: string) => (dispatch: Dispatch, getState: () => RootState) => { - const res = getResource(projectUuid)(getState().resources); - if (res) { + const res = getResource(resourceUuid)(getState().resources); + const menuKind = dispatch(resourceUuidToContextMenuKind(resourceUuid)); + if (res && menuKind) { dispatch(openContextMenu(event, { name: res.name, uuid: res.uuid, kind: res.kind, - menuKind: ContextMenuKind.PROJECT, + menuKind, + description: res.description, ownerUuid: res.ownerUuid, - isTrashed: res.isTrashed + isTrashed: ('isTrashed' in res) ? res.isTrashed : false, })); } }; @@ -165,29 +180,104 @@ export const openSidePanelContextMenu = (event: React.MouseEvent, i export const openProcessContextMenu = (event: React.MouseEvent, process: Process) => (dispatch: Dispatch, getState: () => RootState) => { - const resource = { - uuid: process.containerRequest.uuid, - ownerUuid: process.containerRequest.ownerUuid, - kind: ResourceKind.PROCESS, - name: process.containerRequest.name, - description: process.containerRequest.description, - menuKind: ContextMenuKind.PROCESS - }; - dispatch(openContextMenu(event, resource)); + const res = getResource(process.containerRequest.uuid)(getState().resources); + if (res) { + dispatch(openContextMenu(event, { + uuid: res.uuid, + ownerUuid: res.ownerUuid, + kind: ResourceKind.PROCESS, + name: res.name, + description: res.description, + outputUuid: res.outputUuid || '', + workflowUuid: res.properties.template_uuid || '', + menuKind: ContextMenuKind.PROCESS_RESOURCE + })); + } }; -export const resourceKindToContextMenuKind = (uuid: string) => { - const kind = extractUuidKind(uuid); - switch (kind) { - case ResourceKind.PROJECT: - return ContextMenuKind.PROJECT; - case ResourceKind.COLLECTION: - return ContextMenuKind.COLLECTION_RESOURCE; - case ResourceKind.PROCESS: - return ContextMenuKind.PROCESS_RESOURCE; - case ResourceKind.USER: - return ContextMenuKind.ROOT_PROJECT; - default: - return; - } -}; +export const openPermissionEditContextMenu = (event: React.MouseEvent, link: LinkResource) => + (dispatch: Dispatch, getState: () => RootState) => { + if (link) { + dispatch(openContextMenu(event, { + name: link.name, + uuid: link.uuid, + kind: link.kind, + menuKind: ContextMenuKind.PERMISSION_EDIT, + ownerUuid: link.ownerUuid, + })); + } + }; + +export const openUserContextMenu = (event: React.MouseEvent, user: UserResource) => + (dispatch: Dispatch, getState: () => RootState) => { + dispatch(openContextMenu(event, { + name: '', + uuid: user.uuid, + ownerUuid: user.ownerUuid, + kind: user.kind, + menuKind: ContextMenuKind.USER + })); + }; + +export const resourceUuidToContextMenuKind = (uuid: string, readonly = false) => + (dispatch: Dispatch, getState: () => RootState) => { + const { isAdmin: isAdminUser, uuid: userUuid } = getState().auth.user!; + const kind = extractUuidKind(uuid); + const resource = getResourceWithEditableStatus(uuid, userUuid)(getState().resources); + + const isEditable = (isAdminUser || (resource || {} as EditableResource).isEditable) && !readonly; + switch (kind) { + case ResourceKind.PROJECT: + return (isAdminUser && !readonly) + ? (resource && resource.groupClass !== GroupClass.FILTER) + ? ContextMenuKind.PROJECT_ADMIN + : ContextMenuKind.FILTER_GROUP_ADMIN + : isEditable + ? (resource && resource.groupClass !== GroupClass.FILTER) + ? ContextMenuKind.PROJECT + : ContextMenuKind.FILTER_GROUP + : 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 && !readonly) + ? ContextMenuKind.COLLECTION_ADMIN + : isEditable + ? ContextMenuKind.COLLECTION + : ContextMenuKind.READONLY_COLLECTION; + case ResourceKind.PROCESS: + return (isAdminUser && !readonly) + ? ContextMenuKind.PROCESS_ADMIN + : readonly + ? ContextMenuKind.READONLY_PROCESS_RESOURCE + : ContextMenuKind.PROCESS_RESOURCE; + case ResourceKind.USER: + return ContextMenuKind.ROOT_PROJECT; + case ResourceKind.LINK: + return ContextMenuKind.LINK; + case ResourceKind.WORKFLOW: + return ContextMenuKind.WORKFLOW; + default: + return; + } + }; + +export const openSearchResultsContextMenu = (event: React.MouseEvent, uuid: string) => + (dispatch: Dispatch, getState: () => RootState) => { + const res = getResource(uuid)(getState().resources); + if (res) { + dispatch(openContextMenu(event, { + name: '', + uuid: res.uuid, + ownerUuid: '', + kind: res.kind, + menuKind: ContextMenuKind.SEARCH_RESULTS, + })); + } + };