UI Improvements
[arvados-workbench2.git] / src / store / groups-panel / groups-panel-actions.ts
index 3574ede95fe626734dc7de909bedab4b83d9cda6..b7cf48054531c3fb988ab19cc5071660e6fe258c 100644 (file)
@@ -15,6 +15,7 @@ import { getCommonResourceServiceError, CommonResourceServiceError } from '~/ser
 import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
 import { PermissionLevel, PermissionResource } from '~/models/permission';
 import { PermissionService } from '~/services/permission-service/permission-service';
+import { FilterBuilder } from '~/services/api/filter-builder';
 
 export const GROUPS_PANEL_ID = "groupsPanel";
 export const CREATE_GROUP_DIALOG = "createGroupDialog";
@@ -23,8 +24,6 @@ export const CREATE_GROUP_NAME_FIELD_NAME = 'name';
 export const CREATE_GROUP_USERS_FIELD_NAME = 'users';
 export const GROUP_ATTRIBUTES_DIALOG = 'groupAttributesDialog';
 export const GROUP_REMOVE_DIALOG = 'groupRemoveDialog';
-export const MEMBER_ATTRIBUTES_DIALOG = 'memberAttributesDialog';
-export const MEMBER_REMOVE_DIALOG = 'memberRemoveDialog';
 
 export const GroupsPanelActions = bindDataExplorerActions(GROUPS_PANEL_ID);
 
@@ -43,16 +42,9 @@ export const openGroupAttributes = (uuid: string) =>
         dispatch(dialogActions.OPEN_DIALOG({ id: GROUP_ATTRIBUTES_DIALOG, data }));
     };
 
-export const openGroupMemberAttributes = (uuid: string) =>
-    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        const { resources } = getState();
-        const data = getResource<PermissionResource>(uuid)(resources);
-        dispatch(dialogActions.OPEN_DIALOG({ id: MEMBER_ATTRIBUTES_DIALOG, data }));
-    };
-
 export const removeGroup = (uuid: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
+        dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...', kind: SnackbarKind.INFO }));
         await services.groupsService.delete(uuid);
         dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
         dispatch<any>(loadGroupsPanel());
@@ -71,27 +63,6 @@ export const openRemoveGroupDialog = (uuid: string) =>
         }));
     };
 
-export const removeGroupMember = (uuid: string) =>
-    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
-        await services.permissionService.delete(uuid);
-        dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
-        dispatch<any>(loadGroupsPanel());
-    };
-
-export const openRemoveGroupMemberDialog = (uuid: string) =>
-    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(dialogActions.OPEN_DIALOG({
-            id: MEMBER_REMOVE_DIALOG,
-            data: {
-                title: 'Remove member',
-                text: 'Are you sure you want to remove this member from this group?',
-                confirmButtonLabel: 'Remove',
-                uuid
-            }
-        }));
-    };
-
 export interface CreateGroupFormData {
     [CREATE_GROUP_NAME_FIELD_NAME]: string;
     [CREATE_GROUP_USERS_FIELD_NAME]?: Person[];
@@ -146,17 +117,14 @@ interface AddGroupMemberArgs {
     permissionService: PermissionService;
 }
 
+/**
+ * Group membership is determined by whether the group has can_read permission on an object. 
+ * If a group G can_read an object A, then we say A is a member of G.
+ * 
+ * [Permission model docs](https://doc.arvados.org/api/permission-model.html)
+ */
 export const addGroupMember = async ({ user, group, ...args }: AddGroupMemberArgs) => {
 
-
-
-    await createPermission({
-        head: { ...group },
-        tail: { ...user },
-        permissionLevel: PermissionLevel.CAN_MANAGE,
-        ...args,
-    });
-
     await createPermission({
         head: { ...user },
         tail: { ...group },
@@ -193,4 +161,65 @@ const createPermission = async ({ head, tail, permissionLevel, dispatch, permiss
 
     }
 
+};
+
+interface DeleteGroupMemberArgs {
+    user: { uuid: string, name: string };
+    group: { uuid: string, name: string };
+    dispatch: Dispatch;
+    permissionService: PermissionService;
+}
+
+export const deleteGroupMember = async ({ user, group, ...args }: DeleteGroupMemberArgs) => {
+
+    await deletePermission({
+        tail: group,
+        head: user,
+        ...args,
+    });
+
+};
+
+interface DeletePermissionLinkArgs {
+    head: { uuid: string, name: string };
+    tail: { uuid: string, name: string };
+    dispatch: Dispatch;
+    permissionService: PermissionService;
+}
+
+export const deletePermission = async ({ head, tail, dispatch, permissionService }: DeletePermissionLinkArgs) => {
+
+    try {
+
+        const permissionsResponse = await permissionService.list({
+
+            filters: new FilterBuilder()
+                .addEqual('tailUuid', tail.uuid)
+                .addEqual('headUuid', head.uuid)
+                .getFilters()
+
+        });
+
+        const [permission] = permissionsResponse.items;
+
+        if (permission) {
+
+            await permissionService.delete(permission.uuid);
+
+        } else {
+
+            throw new Error('Permission not found');
+
+        }
+
+
+    } catch (e) {
+
+        dispatch(snackbarActions.OPEN_SNACKBAR({
+            message: `Could not delete ${tail.name} -> ${head.name} relation`,
+            kind: SnackbarKind.ERROR,
+        }));
+
+    }
+
 };
\ No newline at end of file