X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/c6e1fef352129f214501b70ab70611fb05660e91..e63239560b1393a8b306a4353719d4fe85698f04:/src/store/sharing-dialog/sharing-dialog-actions.ts?ds=sidebyside diff --git a/src/store/sharing-dialog/sharing-dialog-actions.ts b/src/store/sharing-dialog/sharing-dialog-actions.ts index f118c70f..4c0b8825 100644 --- a/src/store/sharing-dialog/sharing-dialog-actions.ts +++ b/src/store/sharing-dialog/sharing-dialog-actions.ts @@ -2,24 +2,28 @@ // // SPDX-License-Identifier: AGPL-3.0 -import { dialogActions } from "~/store/dialog/dialog-actions"; -import { withDialog } from "~/store/dialog/with-dialog"; -import { SHARING_DIALOG_NAME, SharingPublicAccessFormData, SHARING_PUBLIC_ACCESS_FORM_NAME, SHARING_INVITATION_FORM_NAME, SharingManagementFormData, SharingInvitationFormData } from './sharing-dialog-types'; +import { dialogActions } from "store/dialog/dialog-actions"; +import { withDialog } from "store/dialog/with-dialog"; +import { SHARING_DIALOG_NAME, SharingPublicAccessFormData, SHARING_PUBLIC_ACCESS_FORM_NAME, SHARING_INVITATION_FORM_NAME, SharingManagementFormData, SharingInvitationFormData, VisibilityLevel, getSharingMangementFormData, getSharingPublicAccessFormData } from './sharing-dialog-types'; import { Dispatch } from 'redux'; -import { ServiceRepository } from "~/services/services"; -import { FilterBuilder } from '~/services/api/filter-builder'; -import { initialize, getFormValues, isDirty, reset } from 'redux-form'; -import { SHARING_MANAGEMENT_FORM_NAME } from '~/store/sharing-dialog/sharing-dialog-types'; -import { RootState } from '~/store/store'; -import { getDialog } from '~/store/dialog/dialog-reducer'; -import { PermissionLevel } from '~/models/permission'; -import { getPublicGroupUuid } from "~/store/workflow-panel/workflow-panel-actions"; -import { PermissionResource } from '~/models/permission'; +import { ServiceRepository } from "services/services"; +import { FilterBuilder } from 'services/api/filter-builder'; +import { initialize, getFormValues, reset } from 'redux-form'; +import { SHARING_MANAGEMENT_FORM_NAME } from 'store/sharing-dialog/sharing-dialog-types'; +import { RootState } from 'store/store'; +import { getDialog } from 'store/dialog/dialog-reducer'; +import { PermissionLevel } from 'models/permission'; +import { getPublicGroupUuid } from "store/workflow-panel/workflow-panel-actions"; +import { PermissionResource } from 'models/permission'; import { differenceWith } from "lodash"; +import { withProgress } from "store/progress-indicator/with-progress"; +import { progressIndicatorActions } from 'store/progress-indicator/progress-indicator-actions'; +import { snackbarActions, SnackbarKind } from "../snackbar/snackbar-actions"; +import { extractUuidKind, ResourceKind } from "models/resource"; -export const openSharingDialog = (resourceUuid: string) => +export const openSharingDialog = (resourceUuid: string, refresh?: () => void) => (dispatch: Dispatch) => { - dispatch(dialogActions.OPEN_DIALOG({ id: SHARING_DIALOG_NAME, data: resourceUuid })); + dispatch(dialogActions.OPEN_DIALOG({ id: SHARING_DIALOG_NAME, data: {resourceUuid, refresh} })); dispatch(loadSharingDialog); }; @@ -27,47 +31,80 @@ export const closeSharingDialog = () => dialogActions.CLOSE_DIALOG({ id: SHARING_DIALOG_NAME }); export const connectSharingDialog = withDialog(SHARING_DIALOG_NAME); +export const connectSharingDialogProgress = withProgress(SHARING_DIALOG_NAME); -export const saveSharingDialogChanges = async (dispatch: Dispatch) => { - await Promise.all([ - dispatch(savePublicPermissionChanges), - dispatch(saveManagementChanges), - dispatch(sendInvitations), - ]); + +export const saveSharingDialogChanges = async (dispatch: Dispatch, getState: () => RootState) => { + dispatch(progressIndicatorActions.START_WORKING(SHARING_DIALOG_NAME)); + await dispatch(savePublicPermissionChanges); + await dispatch(saveManagementChanges); + await dispatch(sendInvitations); dispatch(reset(SHARING_INVITATION_FORM_NAME)); await dispatch(loadSharingDialog); + + const dialog = getDialog(getState().dialog, SHARING_DIALOG_NAME); + if (dialog && dialog.data.refresh) { + dialog.data.refresh(); + } +}; + +export const sendSharingInvitations = async (dispatch: Dispatch, getState: () => RootState) => { + dispatch(progressIndicatorActions.START_WORKING(SHARING_DIALOG_NAME)); + await dispatch(sendInvitations); + dispatch(closeSharingDialog()); + dispatch(snackbarActions.OPEN_SNACKBAR({ + message: 'Resource has been shared', + kind: SnackbarKind.SUCCESS, + })); + dispatch(progressIndicatorActions.STOP_WORKING(SHARING_DIALOG_NAME)); + + const dialog = getDialog(getState().dialog, SHARING_DIALOG_NAME); + if (dialog && dialog.data.refresh) { + dialog.data.refresh(); + } }; -export const hasChanges = (state: RootState) => - isDirty(SHARING_PUBLIC_ACCESS_FORM_NAME)(state) || - isDirty(SHARING_MANAGEMENT_FORM_NAME)(state) || - isDirty(SHARING_INVITATION_FORM_NAME)(state); +interface SharingDialogData { + resourceUuid: string; + refresh: () => void; +} const loadSharingDialog = async (dispatch: Dispatch, getState: () => RootState, { permissionService }: ServiceRepository) => { - const dialog = getDialog(getState().dialog, SHARING_DIALOG_NAME); - + const dialog = getDialog(getState().dialog, SHARING_DIALOG_NAME); if (dialog) { - const { items } = await permissionService.listResourcePermissions(dialog.data); - dispatch(initializePublicAccessForm(items)); - await dispatch(initializeManagementForm(items)); + dispatch(progressIndicatorActions.START_WORKING(SHARING_DIALOG_NAME)); + try { + const { items } = await permissionService.listResourcePermissions(dialog.data.resourceUuid); + dispatch(initializePublicAccessForm(items)); + await dispatch(initializeManagementForm(items)); + dispatch(progressIndicatorActions.STOP_WORKING(SHARING_DIALOG_NAME)); + } catch (e) { + dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'You do not have access to share this item', hideDuration: 2000, kind: SnackbarKind.ERROR })); + dispatch(dialogActions.CLOSE_DIALOG({ id: SHARING_DIALOG_NAME })); + dispatch(progressIndicatorActions.STOP_WORKING(SHARING_DIALOG_NAME)); + } } }; const initializeManagementForm = (permissionLinks: PermissionResource[]) => - async (dispatch: Dispatch, getState: () => RootState, { userService }: ServiceRepository) => { + async (dispatch: Dispatch, getState: () => RootState, { userService, groupsService }: ServiceRepository) => { const filters = new FilterBuilder() .addIn('uuid', permissionLinks.map(({ tailUuid }) => tailUuid)) .getFilters(); - const { items: users } = await userService.list({ filters }); + const { items: users } = await userService.list({ filters, count: "none" }); + const { items: groups } = await groupsService.list({ filters, count: "none" }); const getEmail = (tailUuid: string) => { const user = users.find(({ uuid }) => uuid === tailUuid); + const group = groups.find(({ uuid }) => uuid === tailUuid); return user ? user.email - : tailUuid; + : group + ? group.name + : tailUuid; }; const managementPermissions = permissionLinks @@ -95,13 +132,13 @@ const initializePublicAccessForm = (permissionLinks: PermissionResource[]) => const publicAccessFormData: SharingPublicAccessFormData = publicPermission ? { - enabled: publicPermission.name !== PermissionLevel.NONE, - permissions: publicPermission.name as PermissionLevel, + visibility: VisibilityLevel.PUBLIC, permissionUuid: publicPermission.uuid, } : { - enabled: false, - permissions: PermissionLevel.CAN_READ, + visibility: permissionLinks.length > 0 + ? VisibilityLevel.SHARED + : VisibilityLevel.PRIVATE, permissionUuid: '', }; @@ -111,26 +148,26 @@ const initializePublicAccessForm = (permissionLinks: PermissionResource[]) => const savePublicPermissionChanges = async (_: Dispatch, getState: () => RootState, { permissionService }: ServiceRepository) => { const state = getState(); const { user } = state.auth; - const dialog = getDialog(state.dialog, SHARING_DIALOG_NAME); + const dialog = getDialog(state.dialog, SHARING_DIALOG_NAME); if (dialog && user) { - const { permissionUuid, enabled, permissions } = getFormValues(SHARING_PUBLIC_ACCESS_FORM_NAME)(state) as SharingPublicAccessFormData; + const { permissionUuid, visibility } = getSharingPublicAccessFormData(state); if (permissionUuid) { - if (enabled) { + if (visibility === VisibilityLevel.PUBLIC) { await permissionService.update(permissionUuid, { - name: enabled ? permissions : PermissionLevel.NONE + name: PermissionLevel.CAN_READ }); } else { await permissionService.delete(permissionUuid); } - } else if (enabled) { + } else if (visibility === VisibilityLevel.PUBLIC) { await permissionService.create({ ownerUuid: user.uuid, - headUuid: dialog.data, + headUuid: dialog.data.resourceUuid, tailUuid: getPublicGroupUuid(state), - name: permissions, + name: PermissionLevel.CAN_READ, }); } } @@ -142,42 +179,67 @@ const saveManagementChanges = async (_: Dispatch, getState: () => RootState, { p const dialog = getDialog(state.dialog, SHARING_DIALOG_NAME); if (dialog && user) { - const { initialPermissions, permissions } = getFormValues(SHARING_MANAGEMENT_FORM_NAME)(state) as SharingManagementFormData; + const { initialPermissions, permissions } = getSharingMangementFormData(state); + const { visibility } = getSharingPublicAccessFormData(state); - const cancelledPermissions = differenceWith( - initialPermissions, - permissions, - (a, b) => a.permissionUuid === b.permissionUuid - ); - await Promise.all(cancelledPermissions.map(({ permissionUuid }) => - permissionService.delete(permissionUuid) - )); + if (visibility === VisibilityLevel.PRIVATE) { + + for (const permission of initialPermissions) { + await permissionService.delete(permission.permissionUuid); + } - await Promise.all(permissions.map(({ permissionUuid, permissions }) => - permissionService.update(permissionUuid, { name: permissions }) - )); + } else { + const cancelledPermissions = differenceWith( + initialPermissions, + permissions, + (a, b) => a.permissionUuid === b.permissionUuid + ); + + for (const { permissionUuid } of cancelledPermissions) { + await permissionService.delete(permissionUuid); + } + + for (const permission of permissions) { + await permissionService.update(permission.permissionUuid, { name: permission.permissions }); + } + + } } }; -const sendInvitations = async (_: Dispatch, getState: () => RootState, { permissionService }: ServiceRepository) => { +const sendInvitations = async (_: Dispatch, getState: () => RootState, { permissionService, userService }: ServiceRepository) => { const state = getState(); const { user } = state.auth; - const dialog = getDialog(state.dialog, SHARING_DIALOG_NAME); + const dialog = getDialog(state.dialog, SHARING_DIALOG_NAME); if (dialog && user) { - const invitations = getFormValues(SHARING_INVITATION_FORM_NAME)(state) as SharingInvitationFormData; - const promises = invitations.invitedPeople + const getGroupsFromForm = invitations.invitedPeople.filter((invitation) => extractUuidKind(invitation.uuid) === ResourceKind.GROUP); + const getUsersFromForm = invitations.invitedPeople.filter((invitation) => extractUuidKind(invitation.uuid) === ResourceKind.USER); + + const invitationDataUsers = getUsersFromForm .map(person => ({ ownerUuid: user.uuid, - headUuid: dialog.data, + headUuid: dialog.data.resourceUuid, tailUuid: person.uuid, name: invitations.permissions - })) - .map(data => permissionService.create(data)); + })); - await Promise.all(promises); + const invitationsDataGroups = getGroupsFromForm.map( + group => ({ + ownerUuid: user.uuid, + headUuid: dialog.data.resourceUuid, + tailUuid: group.uuid, + name: invitations.permissions + }) + ); + + const data = invitationDataUsers.concat(invitationsDataGroups); + + for (const invitation of data) { + await permissionService.create(invitation); + } } };