Extract permission types, create model and service
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Mon, 29 Oct 2018 07:19:20 +0000 (08:19 +0100)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Mon, 29 Oct 2018 07:19:20 +0000 (08:19 +0100)
Feature #14365

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

15 files changed:
src/models/link.ts
src/models/permission.ts [new file with mode: 0644]
src/services/link-service/link-service.ts
src/services/permission-service/permission-service.ts [new file with mode: 0644]
src/services/services.ts
src/store/sharing-dialog/sharing-dialog-actions.ts
src/store/sharing-dialog/sharing-dialog-types.ts [new file with mode: 0644]
src/views-components/sharing-dialog/permission-select.tsx
src/views-components/sharing-dialog/sharing-dialog.tsx
src/views-components/sharing-dialog/sharing-invitation-form-component.tsx
src/views-components/sharing-dialog/sharing-invitation-form.tsx
src/views-components/sharing-dialog/sharing-management-form-component.tsx
src/views-components/sharing-dialog/sharing-management-form.tsx
src/views-components/sharing-dialog/sharing-public-access-form-component.tsx
src/views-components/sharing-dialog/sharing-public-access-form.tsx

index da9dfd030b39217f7649d6d896f9cfd3ad639a5e..9d1711d8316c3e327d1f8e2edf1b59cd267a852c 100644 (file)
@@ -14,5 +14,6 @@ export interface LinkResource extends Resource {
 
 export enum LinkClass {
     STAR = 'star',
-    TAG = 'tag'
+    TAG = 'tag',
+    PERMISSION = 'permission',
 }
\ No newline at end of file
diff --git a/src/models/permission.ts b/src/models/permission.ts
new file mode 100644 (file)
index 0000000..f340c50
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { LinkResource, LinkClass } from './link';
+
+export interface PermissionResource extends LinkResource {
+    linkClass: LinkClass.PERMISSION;
+}
+
+export enum PermissionLevel {
+    NONE = 'none',
+    CAN_READ = 'can_read',
+    CAN_WRITE = 'can_write',
+    CAN_MANAGE = 'can_manage',
+}
index 2701279e7c5cee5dfabc6f8bf2d52babea51fc06..d1b806751e74206545360b624995ad4e9df82d7c 100644 (file)
@@ -7,7 +7,7 @@ import { LinkResource } from "~/models/link";
 import { AxiosInstance } from "axios";
 import { ApiActions } from "~/services/api/api-actions";
 
-export class LinkService extends CommonResourceService<LinkResource> {
+export class LinkService<Resource extends LinkResource = LinkResource> extends CommonResourceService<Resource> {
     constructor(serverApi: AxiosInstance, actions: ApiActions) {
         super(serverApi, "links", actions);
     }
diff --git a/src/services/permission-service/permission-service.ts b/src/services/permission-service/permission-service.ts
new file mode 100644 (file)
index 0000000..95666de
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { LinkService } from "~/services/link-service/link-service";
+import { PermissionResource } from "~/models/permission";
+import { ListArguments, ListResults } from '~/services/common-service/common-resource-service';
+import { joinFilters, FilterBuilder } from '../api/filter-builder';
+import { LinkClass } from '../../models/link';
+
+export class PermissionService extends LinkService<PermissionResource> {
+
+    list(args: ListArguments = {}): Promise<ListResults<PermissionResource>> {
+        const { filters, ...other } = args;
+        const classFilter = new FilterBuilder().addEqual('class', LinkClass.PERMISSION).getFilters();
+        const newArgs = {
+            ...other,
+            filters: joinFilters(filters, classFilter),
+        };
+        return super.list(newArgs);
+    }
+
+}
index 806fcae1f11b07276691967fd0560b54dd0f9269..5adf10b387891b0fecd1efddcfbdade21badb4e5 100644 (file)
@@ -23,6 +23,7 @@ import { LogService } from './log-service/log-service';
 import { ApiActions } from "~/services/api/api-actions";
 import { WorkflowService } from "~/services/workflow-service/workflow-service";
 import { SearchService } from '~/services/search-service/search-service';
+import { PermissionService } from "~/services/permission-service/permission-service";
 
 export type ServiceRepository = ReturnType<typeof createServices>;
 
@@ -39,6 +40,7 @@ export const createServices = (config: Config, actions: ApiActions) => {
     const keepService = new KeepService(apiClient, actions);
     const linkService = new LinkService(apiClient, actions);
     const logService = new LogService(apiClient, actions);
+    const permissionService = new PermissionService(apiClient, actions);
     const projectService = new ProjectService(apiClient, actions);
     const userService = new UserService(apiClient, actions);
     const workflowService = new WorkflowService(apiClient, actions);
@@ -64,6 +66,7 @@ export const createServices = (config: Config, actions: ApiActions) => {
         keepService,
         linkService,
         logService,
+        permissionService,
         projectService,
         searchService,
         tagService,
index efd53295124d0fbb36bface2a05912e1f7009236..10518bdac1feac9af39f3ef0a4145b3d1e7dd41e 100644 (file)
@@ -4,8 +4,7 @@
 
 import { dialogActions } from "~/store/dialog/dialog-actions";
 import { withDialog } from "~/store/dialog/with-dialog";
-
-export const SHARING_DIALOG_NAME = 'SHARING_DIALOG_NAME';
+import { SHARING_DIALOG_NAME } from "./sharing-dialog-types";
 
 export const openSharingDialog = (resourceUuid: string) =>
     dialogActions.OPEN_DIALOG({ id: SHARING_DIALOG_NAME, data: resourceUuid });
diff --git a/src/store/sharing-dialog/sharing-dialog-types.ts b/src/store/sharing-dialog/sharing-dialog-types.ts
new file mode 100644 (file)
index 0000000..e8f0794
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { PermissionLevel } from '~/models/permission';
+import { SharingManagementForm } from '../../views-components/sharing-dialog/sharing-management-form';
+
+export const SHARING_DIALOG_NAME = 'SHARING_DIALOG_NAME';
+export const SHARING_PUBLIC_ACCESS_FORM_NAME = 'SHARING_PUBLIC_ACCESS_FORM_NAME';
+export const SHARING_MANAGEMENT_FORM_NAME = 'SHARING_MANAGEMENT_FORM_NAME';
+export const SHARING_INVITATION_FORM_NAME = 'SHARING_INVITATION_FORM_NAME';
+
+export interface SharingPublicAccessFormData {
+    enabled: boolean;
+    permission: PermissionLevel;
+}
+
+export interface SharingManagementFormData {
+    permissions: SharingManagementFormDataRow[];
+}
+
+export interface SharingManagementFormDataRow {
+    email: string;
+    permission: PermissionLevel;
+}
+
+export interface SharingInvitationFormData {
+    permissions: PermissionLevel;
+    invitedPeople: SharingInvitationFormPersonData[];
+}
+
+export interface SharingInvitationFormPersonData {
+    email: string;
+    name: string;
+    uuid: string;
+}
\ No newline at end of file
index 0b839d586fbd7e721b20630ec535451ce90783da..07a1662d0f013dca754b48c20240218f88d1140c 100644 (file)
@@ -10,6 +10,7 @@ import Computer from '@material-ui/icons/Computer';
 import { WithStyles } from '@material-ui/core/styles';
 import { SelectProps } from '@material-ui/core/Select';
 import { SelectItem } from './select-item';
+import { PermissionLevel } from '../../models/permission';
 
 export enum PermissionSelectValue {
     READ = 'Read',
@@ -17,6 +18,32 @@ export enum PermissionSelectValue {
     MANAGE = 'Manage',
 }
 
+export const parsePermissionLevel = (value: PermissionSelectValue) => {
+    switch (value) {
+        case PermissionSelectValue.READ:
+            return PermissionLevel.CAN_READ;
+        case PermissionSelectValue.WRITE:
+            return PermissionLevel.CAN_WRITE;
+        case PermissionSelectValue.MANAGE:
+            return PermissionLevel.CAN_MANAGE;
+        default:
+            return PermissionLevel.NONE;
+    }
+};
+
+export const formatPermissionLevel = (value: PermissionLevel) => {
+    switch (value) {
+        case PermissionLevel.CAN_READ:
+            return PermissionSelectValue.READ;
+        case PermissionLevel.CAN_WRITE:
+            return PermissionSelectValue.WRITE;
+        case PermissionLevel.CAN_MANAGE:
+            return PermissionSelectValue.MANAGE;
+        default:
+            return PermissionSelectValue.READ;
+    }
+};
+
 type PermissionSelectClasses = 'value';
 
 const PermissionSelectStyles: StyleRulesCallback<PermissionSelectClasses> = theme => ({
index 63ee19a74bd50d3cedb93056d45cd0ab49db4082..b6c956e3fa777ef6aa9e899c8193bf374b0453df 100644 (file)
@@ -13,10 +13,13 @@ import { RootState } from '~/store/store';
 import SharingDialogComponent, { SharingDialogDataProps, SharingDialogActionProps } from './sharing-dialog-component';
 import { SharingDialogContent } from './sharing-dialog-content';
 import { connectAdvancedViewSwitch, AdvancedViewSwitchInjectedProps } from './advanced-view-switch';
+import { isDirty } from 'redux-form';
 
-const mapStateToProps = (_: RootState, { advancedViewOpen, ...props }: WithDialogProps<string> & AdvancedViewSwitchInjectedProps): SharingDialogDataProps => ({
+const mapStateToProps = (state: RootState, { advancedViewOpen, ...props }: WithDialogProps<string> & AdvancedViewSwitchInjectedProps): SharingDialogDataProps => ({
     ...props,
-    saveEnabled: false,
+    saveEnabled: isDirty('SHARING_PUBLIC_ACCESS_FORM')(state) ||
+        isDirty('SHARING_MANAGEMENT_FORM')(state) ||
+        isDirty('SHARING_INVITATION_FORM')(state),
     advancedEnabled: !advancedViewOpen,
     children: <SharingDialogContent {...{ advancedViewOpen }} />,
 });
index c8db68dcf65180c78291b8e944a44285c714af4a..eafa480b518d9b50d90a5567eb4716a6318d1aa8 100644 (file)
@@ -5,7 +5,7 @@
 import * as React from 'react';
 import { Field, WrappedFieldProps, FieldArray, WrappedFieldArrayProps } from 'redux-form';
 import { Grid, FormControl, InputLabel } from '@material-ui/core';
-import { PermissionSelect } from './permission-select';
+import { PermissionSelect, parsePermissionLevel, formatPermissionLevel } from './permission-select';
 import { PeopleSelect, Person } from './people-select';
 
 export default () =>
@@ -33,8 +33,10 @@ const InvitedPeopleFieldComponent = ({ fields }: WrappedFieldArrayProps<Person>)
 
 const PermissionSelectField = () =>
     <Field
-        name='permission'
-        component={PermissionSelectComponent} />;
+        name='permissions'
+        component={PermissionSelectComponent}
+        format={formatPermissionLevel}
+        parse={parsePermissionLevel} />;
 
 const PermissionSelectComponent = ({ input }: WrappedFieldProps) =>
     <FormControl fullWidth>
index ca801ae0e0bb19ec0d0ab8c5705d20ae555854b7..d8e86f93a3ddd991383ff03bdb8965ae11154457 100644 (file)
@@ -6,13 +6,15 @@ import { reduxForm } from 'redux-form';
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import SharingInvitationFormComponent from './sharing-invitation-form-component';
-import { PermissionSelectValue } from './permission-select';
+import { SHARING_INVITATION_FORM_NAME } from '~/store/sharing-dialog/sharing-dialog-types';
+import { PermissionLevel } from '~/models/permission';
 
 export const SharingInvitationForm = compose(
     connect(() => ({
         initialValues: {
-            permission: PermissionSelectValue.READ
+            permissions: PermissionLevel.CAN_READ,
+            invitedPeople: [],
         }
     })),
-    reduxForm({ form: 'SIMPLE_SHARING_FORM' })
+    reduxForm({ form: SHARING_INVITATION_FORM_NAME })
 )(SharingInvitationFormComponent);
\ No newline at end of file
index 51e69f88581b73eaec3bb3293bf15ba86417869d..ad8f65fbe104fa05fa4a30f7a9a46f25aeed516c 100644 (file)
@@ -5,7 +5,7 @@
 import * as React from 'react';
 import { Grid, StyleRulesCallback, Divider, IconButton, Typography } from '@material-ui/core';
 import { Field, WrappedFieldProps, WrappedFieldArrayProps, FieldArray, FieldsProps } from 'redux-form';
-import { PermissionSelect } from './permission-select';
+import { PermissionSelect, formatPermissionLevel, parsePermissionLevel } from './permission-select';
 import { WithStyles } from '@material-ui/core/styles';
 import withStyles from '@material-ui/core/styles/withStyles';
 import { CloseIcon } from '~/components/icon/icon';
@@ -37,7 +37,11 @@ const PermissionManagementRow = withStyles(permissionManagementRowStyles)(
                     <Typography noWrap variant='subheading'>{fields.get(index).email}</Typography>
                 </Grid>
                 <Grid item xs={4} container wrap='nowrap'>
-                    <Field name={`${field}.permissions`} component={PermissionSelectComponent} />
+                    <Field
+                        name={`${field}.permissions`}
+                        component={PermissionSelectComponent}
+                        format={formatPermissionLevel}
+                        parse={parsePermissionLevel} />
                     <IconButton onClick={() => fields.remove(index)}>
                         <CloseIcon />
                     </IconButton>
index 9c707beb1cbeac394f7e488e0ed04bc45e0fa7eb..d4081a4a16924a31930e8ff46063eb1710550777 100644 (file)
@@ -6,15 +6,23 @@ import { reduxForm } from 'redux-form';
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import SharingManagementFormComponent from './sharing-management-form-component';
+import { SHARING_MANAGEMENT_FORM_NAME } from '~/store/sharing-dialog/sharing-dialog-types';
+import { PermissionLevel } from '~/models/permission';
 
 export const SharingManagementForm = compose(
     connect(() => ({
         initialValues: {
             permissions: [
-                { email: 'chrystian.klingenberg@contractors.roche.com', permissions: 'Read' },
-                { email: 'artur.janicki@contractors.roche.com', permissions: 'Write' },
+                {
+                    email: 'chrystian.klingenberg@contractors.roche.com',
+                    permissions: PermissionLevel.CAN_MANAGE,
+                },
+                {
+                    email: 'artur.janicki@contractors.roche.com',
+                    permissions: PermissionLevel.CAN_WRITE,
+                },
             ],
         }
     })),
-    reduxForm({ form: 'SHARING_MANAGEMENT_FORM' })
+    reduxForm({ form: SHARING_MANAGEMENT_FORM_NAME })
 )(SharingManagementFormComponent);
\ No newline at end of file
index b931cac8fa1ac6cfce3da2cb55210175e65a09dc..6f70c2df876ba43bebfc394a0be29202768fd68c 100644 (file)
@@ -5,7 +5,7 @@
 import * as React from 'react';
 import { Grid, StyleRulesCallback, Divider, Switch, Typography } from '@material-ui/core';
 import { Field, WrappedFieldProps, formValues, formValueSelector } from 'redux-form';
-import { PermissionSelect } from './permission-select';
+import { PermissionSelect, formatPermissionLevel, parsePermissionLevel } from './permission-select';
 import { WithStyles } from '@material-ui/core/styles';
 import withStyles from '@material-ui/core/styles/withStyles';
 import { connect } from 'react-redux';
@@ -25,7 +25,12 @@ const SharingPublicAccessForm = withStyles(sharingPublicAccessStyles)(
                     <Typography variant='subheading'>Public access</Typography>
                 </Grid>
                 <Grid item xs={4} container wrap='nowrap'>
-                    <Field name='permissions' component={PermissionSelectComponent} />
+                    <Field
+                        name='permissions'
+                        component={PermissionSelectComponent}
+                        format={formatPermissionLevel}
+                        parse={parsePermissionLevel}
+                    />
                     <Field name='enabled' component={PublicAccessSwitch} />
                 </Grid>
             </Grid>
index 42a2dec93b4fc8cb07cb877fdca868725d80d303..bf64ba32771433dfaf5c8b7a8adb77be18ea0731 100644 (file)
@@ -6,12 +6,14 @@ import { reduxForm } from 'redux-form';
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import SharingPublicAccessFormComponent from './sharing-public-access-form-component';
+import { SHARING_PUBLIC_ACCESS_FORM_NAME } from '~/store/sharing-dialog/sharing-dialog-types';
+import { PermissionLevel } from '~/models/permission';
 export const SharingPublicAccessForm = compose(
     connect(() => ({
         initialValues: {
             enabled: false,
-            permissions: 'Read',
+            permissions: PermissionLevel.CAN_READ,
         }
     })),
-    reduxForm({ form: 'SHARING_PUBLIC_ACCESS_FORM' })
+    reduxForm({ form: SHARING_PUBLIC_ACCESS_FORM_NAME })
 )(SharingPublicAccessFormComponent);
\ No newline at end of file