From 3f809e0be2a712d1e576f1b2acf4aff73e0f16b0 Mon Sep 17 00:00:00 2001 From: Michal Klobukowski Date: Mon, 29 Oct 2018 08:19:20 +0100 Subject: [PATCH] Extract permission types, create model and service Feature #14365 Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski --- src/models/link.ts | 3 +- src/models/permission.ts | 16 +++++++++ src/services/link-service/link-service.ts | 2 +- .../permission-service/permission-service.ts | 23 ++++++++++++ src/services/services.ts | 3 ++ .../sharing-dialog/sharing-dialog-actions.ts | 3 +- .../sharing-dialog/sharing-dialog-types.ts | 36 +++++++++++++++++++ .../sharing-dialog/permission-select.tsx | 27 ++++++++++++++ .../sharing-dialog/sharing-dialog.tsx | 7 ++-- .../sharing-invitation-form-component.tsx | 8 +++-- .../sharing-invitation-form.tsx | 8 +++-- .../sharing-management-form-component.tsx | 8 +++-- .../sharing-management-form.tsx | 14 ++++++-- .../sharing-public-access-form-component.tsx | 9 +++-- .../sharing-public-access-form.tsx | 6 ++-- 15 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 src/models/permission.ts create mode 100644 src/services/permission-service/permission-service.ts create mode 100644 src/store/sharing-dialog/sharing-dialog-types.ts diff --git a/src/models/link.ts b/src/models/link.ts index da9dfd03..9d1711d8 100644 --- a/src/models/link.ts +++ b/src/models/link.ts @@ -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 index 00000000..f340c502 --- /dev/null +++ b/src/models/permission.ts @@ -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', +} diff --git a/src/services/link-service/link-service.ts b/src/services/link-service/link-service.ts index 2701279e..d1b80675 100644 --- a/src/services/link-service/link-service.ts +++ b/src/services/link-service/link-service.ts @@ -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 { +export class LinkService extends CommonResourceService { 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 index 00000000..95666de0 --- /dev/null +++ b/src/services/permission-service/permission-service.ts @@ -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 { + + list(args: ListArguments = {}): Promise> { + const { filters, ...other } = args; + const classFilter = new FilterBuilder().addEqual('class', LinkClass.PERMISSION).getFilters(); + const newArgs = { + ...other, + filters: joinFilters(filters, classFilter), + }; + return super.list(newArgs); + } + +} diff --git a/src/services/services.ts b/src/services/services.ts index 806fcae1..5adf10b3 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -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; @@ -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, diff --git a/src/store/sharing-dialog/sharing-dialog-actions.ts b/src/store/sharing-dialog/sharing-dialog-actions.ts index efd53295..10518bda 100644 --- a/src/store/sharing-dialog/sharing-dialog-actions.ts +++ b/src/store/sharing-dialog/sharing-dialog-actions.ts @@ -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 index 00000000..e8f07948 --- /dev/null +++ b/src/store/sharing-dialog/sharing-dialog-types.ts @@ -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 diff --git a/src/views-components/sharing-dialog/permission-select.tsx b/src/views-components/sharing-dialog/permission-select.tsx index 0b839d58..07a1662d 100644 --- a/src/views-components/sharing-dialog/permission-select.tsx +++ b/src/views-components/sharing-dialog/permission-select.tsx @@ -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 = theme => ({ diff --git a/src/views-components/sharing-dialog/sharing-dialog.tsx b/src/views-components/sharing-dialog/sharing-dialog.tsx index 63ee19a7..b6c956e3 100644 --- a/src/views-components/sharing-dialog/sharing-dialog.tsx +++ b/src/views-components/sharing-dialog/sharing-dialog.tsx @@ -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 & AdvancedViewSwitchInjectedProps): SharingDialogDataProps => ({ +const mapStateToProps = (state: RootState, { advancedViewOpen, ...props }: WithDialogProps & 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: , }); diff --git a/src/views-components/sharing-dialog/sharing-invitation-form-component.tsx b/src/views-components/sharing-dialog/sharing-invitation-form-component.tsx index c8db68dc..eafa480b 100644 --- a/src/views-components/sharing-dialog/sharing-invitation-form-component.tsx +++ b/src/views-components/sharing-dialog/sharing-invitation-form-component.tsx @@ -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) const PermissionSelectField = () => ; + name='permissions' + component={PermissionSelectComponent} + format={formatPermissionLevel} + parse={parsePermissionLevel} />; const PermissionSelectComponent = ({ input }: WrappedFieldProps) => diff --git a/src/views-components/sharing-dialog/sharing-invitation-form.tsx b/src/views-components/sharing-dialog/sharing-invitation-form.tsx index ca801ae0..d8e86f93 100644 --- a/src/views-components/sharing-dialog/sharing-invitation-form.tsx +++ b/src/views-components/sharing-dialog/sharing-invitation-form.tsx @@ -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 diff --git a/src/views-components/sharing-dialog/sharing-management-form-component.tsx b/src/views-components/sharing-dialog/sharing-management-form-component.tsx index 51e69f88..ad8f65fb 100644 --- a/src/views-components/sharing-dialog/sharing-management-form-component.tsx +++ b/src/views-components/sharing-dialog/sharing-management-form-component.tsx @@ -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)( {fields.get(index).email} - + fields.remove(index)}> diff --git a/src/views-components/sharing-dialog/sharing-management-form.tsx b/src/views-components/sharing-dialog/sharing-management-form.tsx index 9c707beb..d4081a4a 100644 --- a/src/views-components/sharing-dialog/sharing-management-form.tsx +++ b/src/views-components/sharing-dialog/sharing-management-form.tsx @@ -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 diff --git a/src/views-components/sharing-dialog/sharing-public-access-form-component.tsx b/src/views-components/sharing-dialog/sharing-public-access-form-component.tsx index b931cac8..6f70c2df 100644 --- a/src/views-components/sharing-dialog/sharing-public-access-form-component.tsx +++ b/src/views-components/sharing-dialog/sharing-public-access-form-component.tsx @@ -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)( Public access - + diff --git a/src/views-components/sharing-dialog/sharing-public-access-form.tsx b/src/views-components/sharing-dialog/sharing-public-access-form.tsx index 42a2dec9..bf64ba32 100644 --- a/src/views-components/sharing-dialog/sharing-public-access-form.tsx +++ b/src/views-components/sharing-dialog/sharing-public-access-form.tsx @@ -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 -- 2.39.5