export enum LinkClass {
STAR = 'star',
- TAG = 'tag'
+ TAG = 'tag',
+ PERMISSION = 'permission',
}
\ No newline at end of file
--- /dev/null
+// 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',
+}
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);
}
--- /dev/null
+// 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);
+ }
+
+}
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>;
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);
keepService,
linkService,
logService,
+ permissionService,
projectService,
searchService,
tagService,
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 });
--- /dev/null
+// 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
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',
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 => ({
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 }} />,
});
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 () =>
const PermissionSelectField = () =>
<Field
- name='permission'
- component={PermissionSelectComponent} />;
+ name='permissions'
+ component={PermissionSelectComponent}
+ format={formatPermissionLevel}
+ parse={parsePermissionLevel} />;
const PermissionSelectComponent = ({ input }: WrappedFieldProps) =>
<FormControl fullWidth>
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
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';
<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>
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
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';
<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>
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