Merge branch 'master' into 13969-advanced-tab
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Tue, 30 Oct 2018 09:10:53 +0000 (10:10 +0100)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Tue, 30 Oct 2018 09:10:53 +0000 (10:10 +0100)
refs #13969

Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>

16 files changed:
src/models/collection.ts
src/models/container-request.ts
src/store/advanced-tab/advanced-tab.ts [new file with mode: 0644]
src/views-components/advanced-tab-dialog/advanced-tab-dialog.tsx [new file with mode: 0644]
src/views-components/advanced-tab-dialog/metadataTab.tsx [new file with mode: 0644]
src/views-components/context-menu/action-sets/collection-action-set.ts
src/views-components/context-menu/action-sets/collection-files-action-set.ts
src/views-components/context-menu/action-sets/collection-files-item-action-set.ts
src/views-components/context-menu/action-sets/collection-resource-action-set.ts
src/views-components/context-menu/action-sets/process-action-set.ts
src/views-components/context-menu/action-sets/project-action-set.ts
src/views-components/context-menu/action-sets/root-project-action-set.ts
src/views-components/context-menu/action-sets/trash-action-set.ts
src/views-components/context-menu/action-sets/trashed-collection-action-set.ts
src/views/workbench/workbench.tsx
src/views/workflow-panel/workflow-description-card.tsx

index f8e38f9a0fac227bd2cfeccd62654723f9c66ef5..a25afeb1281bd8d0e8d13bc1367d91afed03598a 100644 (file)
@@ -14,6 +14,10 @@ export interface CollectionResource extends TrashableResource {
     replicationDesired: number;
     replicationConfirmed: number;
     replicationConfirmedAt: string;
+    fileNames: string;
+    storageClassesDesired: string[];
+    storageClassesConfirmed: string[];
+    storageClassesConfirmedAt: string;
 }
 
 export const getCollectionUrl = (uuid: string) => {
index e65bed9fd3b729af13a0ee546efebfc250749215..f7342d23d77d32460d9bcb7140250107e90a420f 100644 (file)
@@ -38,4 +38,5 @@ export interface ContainerRequestResource extends Resource {
     logUuid: string | null;
     outputUuid: string | null;
     filters: string;
+    containerCount: number;
 }
diff --git a/src/store/advanced-tab/advanced-tab.ts b/src/store/advanced-tab/advanced-tab.ts
new file mode 100644 (file)
index 0000000..bcc0b85
--- /dev/null
@@ -0,0 +1,246 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { dialogActions } from '~/store/dialog/dialog-actions';
+import { RootState } from '~/store/store';
+import { Dispatch } from 'redux';
+import { ResourceKind, extractUuidKind } from '~/models/resource';
+import { getResource } from '~/store/resources/resources';
+import { GroupContentsResourcePrefix } from '~/services/groups-service/groups-service';
+import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
+import { ContainerRequestResource } from '~/models/container-request';
+import { CollectionResource } from '~/models/collection';
+import { ProjectResource } from '~/models/project';
+import { ServiceRepository } from '~/services/services';
+import { FilterBuilder } from '~/services/api/filter-builder';
+
+export const ADVANCED_TAB_DIALOG = 'advancedTabDialog';
+
+export interface AdvancedTabDialogData {
+    apiResponse: any;
+    metadata: any;
+    pythonHeader: string;
+    pythonExample: string;
+    cliGetHeader: string;
+    cliGetExample: string;
+    cliUpdateHeader: string;
+    cliUpdateExample: string;
+    curlHeader: string;
+    curlExample: string;
+}
+
+enum CollectionData {
+    COLLECTION = 'collection',
+    STORAGE_CLASSES_CONFIRMED = 'storage_classes_confirmed'
+}
+
+enum ProcessData {
+    CONTAINER_REQUEST = 'container_request',
+    OUTPUT_NAME = 'output_name'
+}
+
+enum ProjectData {
+    GROUP = 'group',
+    DELETE_AT = 'delete_at'
+}
+
+export const openAdvancedTabDialog = (uuid: string) =>
+    async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        const { resources } = getState();
+        const kind = extractUuidKind(uuid);
+        const data = getResource<any>(uuid)(resources);
+        const metadata = await services.linkService.list({
+            filters: new FilterBuilder()
+                .addEqual('headUuid', uuid)
+                .getFilters()
+        });
+        if (data) {
+            if (kind === ResourceKind.COLLECTION) {
+                const dataCollection: AdvancedTabDialogData = {
+                    apiResponse: collectionApiResponse(data),
+                    metadata,
+                    pythonHeader: pythonHeader(CollectionData.COLLECTION),
+                    pythonExample: pythonExample(data.uuid, GroupContentsResourcePrefix.COLLECTION),
+                    cliGetHeader: cliGetHeader(CollectionData.COLLECTION),
+                    cliGetExample: cliGetExample(data.uuid, GroupContentsResourcePrefix.COLLECTION),
+                    cliUpdateHeader: cliUpdateHeader(CollectionData.COLLECTION, CollectionData.STORAGE_CLASSES_CONFIRMED),
+                    cliUpdateExample: cliUpdateExample(data.uuid, CollectionData.COLLECTION, data.storageClassesConfirmed, CollectionData.STORAGE_CLASSES_CONFIRMED),
+                    curlHeader: curlHeader(CollectionData.COLLECTION, CollectionData.STORAGE_CLASSES_CONFIRMED),
+                    curlExample: curlExample(data.uuid, GroupContentsResourcePrefix.COLLECTION, data.storageClassesConfirmed, CollectionData.COLLECTION, CollectionData.STORAGE_CLASSES_CONFIRMED)
+                };
+                dispatch(dialogActions.OPEN_DIALOG({ id: ADVANCED_TAB_DIALOG, data: dataCollection }));
+            } else if (kind === ResourceKind.PROCESS) {
+                const dataProcess: AdvancedTabDialogData = {
+                    apiResponse: containerRequestApiResponse(data),
+                    metadata,
+                    pythonHeader: pythonHeader(ProcessData.CONTAINER_REQUEST),
+                    pythonExample: pythonExample(data.uuid, GroupContentsResourcePrefix.PROCESS),
+                    cliGetHeader: cliGetHeader(ProcessData.CONTAINER_REQUEST),
+                    cliGetExample: cliGetExample(data.uuid, GroupContentsResourcePrefix.PROCESS),
+                    cliUpdateHeader: cliUpdateHeader(ProcessData.CONTAINER_REQUEST, ProcessData.OUTPUT_NAME),
+                    cliUpdateExample: cliUpdateExample(data.uuid, ProcessData.CONTAINER_REQUEST, data.outputName, ProcessData.OUTPUT_NAME),
+                    curlHeader: curlHeader(ProcessData.CONTAINER_REQUEST, ProcessData.OUTPUT_NAME),
+                    curlExample: curlExample(data.uuid, GroupContentsResourcePrefix.PROCESS, data.outputName, ProcessData.CONTAINER_REQUEST, ProcessData.OUTPUT_NAME)
+                };
+                dispatch(dialogActions.OPEN_DIALOG({ id: ADVANCED_TAB_DIALOG, data: dataProcess }));
+            } else if (kind === ResourceKind.PROJECT) {
+                const dataProject: AdvancedTabDialogData = {
+                    apiResponse: groupRequestApiResponse(data),
+                    metadata,
+                    pythonHeader: pythonHeader(ProjectData.GROUP),
+                    pythonExample: pythonExample(data.uuid, GroupContentsResourcePrefix.PROJECT),
+                    cliGetHeader: cliGetHeader(ProjectData.GROUP),
+                    cliGetExample: cliGetExample(data.uuid, GroupContentsResourcePrefix.PROJECT),
+                    cliUpdateHeader: cliUpdateHeader(ProjectData.GROUP, ProjectData.DELETE_AT),
+                    cliUpdateExample: cliUpdateExample(data.uuid, ProjectData.GROUP, data.deleteAt, ProjectData.DELETE_AT),
+                    curlHeader: curlHeader(ProjectData.GROUP, ProjectData.DELETE_AT),
+                    curlExample: curlExample(data.uuid, GroupContentsResourcePrefix.PROJECT, data.deleteAt, ProjectData.GROUP, ProjectData.DELETE_AT)
+                };
+                dispatch(dialogActions.OPEN_DIALOG({ id: ADVANCED_TAB_DIALOG, data: dataProject }));
+            }
+        } else {
+            dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Could not open advanced tab for this resource.", hideDuration: 2000, kind: SnackbarKind.ERROR }));
+        }
+    };
+
+const pythonHeader = (resourceKind: string) =>
+    `An example python command to get a ${resourceKind} using its uuid:`;
+
+const pythonExample = (uuid: string, resourcePrefix: string) => {
+    const pythonExample = `import arvados
+
+ x = arvados.api().${resourcePrefix}().get(uuid='${uuid}').execute()`;
+
+    return pythonExample;
+};
+
+const cliGetHeader = (resourceKind: string) =>
+    `An example arv command to get a ${resourceKind} using its uuid:`;
+
+const cliGetExample = (uuid: string, resourcePrefix: string) => {
+    const cliGetExample = `arv ${resourcePrefix} get \\
+ --uuid ${uuid}`;
+
+    return cliGetExample;
+};
+
+const cliUpdateHeader = (resourceKind: string, resourceName: string) =>
+    `An example arv command to update the "${resourceName}" attribute for the current ${resourceKind}:`;
+
+const cliUpdateExample = (uuid: string, resourceKind: string, resource: string | string[], resourceName: string) => {
+    const CLIUpdateCollectionExample = `arv ${resourceKind} update \\ 
+ --uuid ${uuid} \\
+ --${resourceKind} '{"${resourceName}":${resource}}'`;
+
+    return CLIUpdateCollectionExample;
+};
+
+const curlHeader = (resourceKind: string, resource: string) =>
+    `An example curl command to update the "${resource}" attribute for the current ${resourceKind}:`;
+
+const curlExample = (uuid: string, resourcePrefix: string, resource: string | string[], resourceKind: string, resourceName: string) => {
+    const curlExample = `curl -X PUT \\
+ -H "Authorization: OAuth2 $ARVADOS_API_TOKEN" \\
+ --data-urlencode ${resourceKind}@/dev/stdin \\
+ https://$ARVADOS_API_HOST/arvados/v1/${resourcePrefix}/${uuid} \\
+ <<EOF
+{
+  "${resourceName}": ${resource}
+}
+EOF`;
+
+    return curlExample;
+};
+
+const stringify = (item: string | null | number | boolean) =>
+    JSON.stringify(item) || 'null';
+
+const stringifyObject = (item: any) =>
+    JSON.stringify(item, null, 2) || 'null';
+
+const containerRequestApiResponse = (apiResponse: ContainerRequestResource) => {
+    const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, description, properties, state, requestingContainerUuid, containerUuid,
+        containerCountMax, mounts, runtimeConstraints, containerImage, environment, cwd, command, outputPath, priority, expiresAt, filters, containerCount,
+        useExisting, schedulingParameters, outputUuid, logUuid, outputName, outputTtl } = apiResponse;
+    const response = `"uuid": "${uuid}",
+"owner_uuid": "${ownerUuid}",
+"created_at": "${createdAt}",
+"modified_at": ${stringify(modifiedAt)},
+"modified_by_client_uuid": ${stringify(modifiedByClientUuid)},
+"modified_by_user_uuid": ${stringify(modifiedByUserUuid)},
+"name": ${stringify(name)},
+"description": ${stringify(description)},
+"properties": ${stringifyObject(properties)},
+"state": ${stringify(state)},
+"requesting_container_uuid": ${stringify(requestingContainerUuid)},
+"container_uuid": ${stringify(containerUuid)},
+"container_count_max": ${stringify(containerCountMax)},
+"mounts": ${stringifyObject(mounts)},
+"runtime_constraints": ${stringifyObject(runtimeConstraints)},
+"container_image": "${stringify(containerImage)}",
+"environment": ${stringifyObject(environment)},
+"cwd": ${stringify(cwd)},
+"command": ${stringifyObject(command)},
+"output_path": ${stringify(outputPath)},
+"priority": ${stringify(priority)},
+"expires_at": ${stringify(expiresAt)},
+"filters": ${stringify(filters)},
+"container_count": ${stringify(containerCount)},
+"use_existing": ${stringify(useExisting)},
+"scheduling_parameters": ${stringifyObject(schedulingParameters)},
+"output_uuid": ${stringify(outputUuid)},
+"log_uuid": ${stringify(logUuid)},
+"output_name": ${stringify(outputName)},
+"output_ttl": ${stringify(outputTtl)}`;
+
+    return response;
+};
+
+const collectionApiResponse = (apiResponse: CollectionResource) => {
+    const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, description, properties, portableDataHash, replicationDesired,
+        replicationConfirmedAt, replicationConfirmed, manifestText, deleteAt, fileNames, trashAt, isTrashed, storageClassesDesired,
+        storageClassesConfirmed, storageClassesConfirmedAt } = apiResponse;
+    const response = `"uuid": "${uuid}",
+"owner_uuid": "${ownerUuid}",
+"created_at": "${createdAt}",
+"modified_by_client_uuid": ${stringify(modifiedByClientUuid)},
+"modified_by_user_uuid": ${stringify(modifiedByUserUuid)},
+"modified_at": ${stringify(modifiedAt)},
+"portable_data_hash": ${stringify(portableDataHash)},
+"replication_desired": ${stringify(replicationDesired)},
+"replication_confirmed_at": ${stringify(replicationConfirmedAt)},
+"replication_confirmed": ${stringify(replicationConfirmed)},
+"manifest_text": ${stringify(manifestText)},
+"name": ${stringify(name)},
+"description": ${stringify(description)},
+"properties": ${stringifyObject(properties)},
+"delete_at": ${stringify(deleteAt)},
+"file_names": ${stringify(fileNames)},
+"trash_at": ${stringify(trashAt)},
+"is_trashed": ${stringify(isTrashed)},
+"storage_classes_desired": ${JSON.stringify(storageClassesDesired, null, 2)},
+"storage_classes_confirmed": ${JSON.stringify(storageClassesConfirmed, null, 2)},
+"storage_classes_confirmed_at": ${stringify(storageClassesConfirmedAt)}`;
+
+    return response;
+};
+
+const groupRequestApiResponse = (apiResponse: ProjectResource) => {
+    const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, description, groupClass, trashAt, isTrashed, deleteAt, properties } = apiResponse;
+    const response = `"uuid": "${uuid}",
+"owner_uuid": "${ownerUuid}",
+"created_at": "${createdAt}",
+"modified_by_client_uuid": ${stringify(modifiedByClientUuid)},
+"modified_by_user_uuid": ${stringify(modifiedByUserUuid)},
+"modified_at": ${stringify(modifiedAt)},
+"name": ${stringify(name)},
+"description": ${stringify(description)},
+"group_class": ${stringify(groupClass)},
+"trash_at": ${stringify(trashAt)},
+"is_trashed": ${stringify(isTrashed)},
+"delete_at": ${stringify(deleteAt)},
+"properties": ${stringifyObject(properties)}`;
+
+    return response;
+};
\ No newline at end of file
diff --git a/src/views-components/advanced-tab-dialog/advanced-tab-dialog.tsx b/src/views-components/advanced-tab-dialog/advanced-tab-dialog.tsx
new file mode 100644 (file)
index 0000000..3b3ca6d
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { Dialog, DialogActions, Button, StyleRulesCallback, WithStyles, withStyles, DialogTitle, DialogContent, Tabs, Tab, DialogContentText } from '@material-ui/core';
+import { WithDialogProps } from '~/store/dialog/with-dialog';
+import { withDialog } from "~/store/dialog/with-dialog";
+import { compose } from 'redux';
+import { ADVANCED_TAB_DIALOG } from "~/store/advanced-tab/advanced-tab";
+import { DefaultCodeSnippet } from "~/components/default-code-snippet/default-code-snippet";
+import { MetadataTab } from '~/views-components/advanced-tab-dialog/metadataTab';
+
+type CssRules = 'content' | 'codeSnippet' | 'spacing';
+
+const styles: StyleRulesCallback<CssRules> = theme => ({
+    content: {
+        paddingTop: theme.spacing.unit * 3,
+        minHeight: '400px',
+        minWidth: '1232px'
+    },
+    codeSnippet: {
+        borderRadius: theme.spacing.unit * 0.5,
+        border: '1px solid',
+        borderColor: theme.palette.grey["400"],
+        maxHeight: '400px'
+    },
+    spacing: {
+        paddingBottom: theme.spacing.unit * 2
+    },
+});
+
+export const AdvancedTabDialog = compose(
+    withDialog(ADVANCED_TAB_DIALOG),
+    withStyles(styles),
+)(
+    class extends React.Component<WithDialogProps<any> & WithStyles<CssRules>>{
+        state = {
+            value: 0,
+        };
+
+        componentDidMount() {
+            this.setState({ value: 0 });
+        }
+
+        handleChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
+            this.setState({ value });
+        }
+        render() {
+            const { classes, open, closeDialog } = this.props;
+            const { value } = this.state;
+            const {
+                apiResponse,
+                metadata,
+                pythonHeader,
+                pythonExample,
+                cliGetHeader,
+                cliGetExample,
+                cliUpdateHeader,
+                cliUpdateExample,
+                curlHeader,
+                curlExample
+            } = this.props.data;
+            return <Dialog
+                open={open}
+                maxWidth="lg"
+                onClose={closeDialog}
+                onExit={() => this.setState({ value: 0 })} >
+                <DialogTitle>Advanced</DialogTitle>
+                <Tabs value={value} onChange={this.handleChange} fullWidth>
+                    <Tab label="API RESPONSE" />
+                    <Tab label="METADATA" />
+                    <Tab label="PYTHON EXAMPLE" />
+                    <Tab label="CLI EXAMPLE" />
+                    <Tab label="CURL EXAMPLE" />
+                </Tabs>
+                <DialogContent className={classes.content}>
+                    {value === 0 && <div>{dialogContentExample(apiResponse, classes)}</div>}
+                    {value === 1 && <div>{metadata.items.length > 0 ? <MetadataTab items={metadata.items}/>: dialogContentHeader('(No metadata links found)')}</div>}
+                    {value === 2 && dialogContent(pythonHeader, pythonExample, classes)}
+                    {value === 3 && <div>
+                        {dialogContent(cliGetHeader, cliGetExample, classes)}
+                        {dialogContent(cliUpdateHeader, cliUpdateExample, classes)}
+                    </div>}
+                    {value === 4 && dialogContent(curlHeader, curlExample, classes)}
+                </DialogContent>
+                <DialogActions>
+                    <Button variant='flat' color='primary' onClick={closeDialog}>
+                        Close
+                    </Button>
+                </DialogActions>
+            </Dialog>;
+        }
+    }
+);
+
+const dialogContent = (header: string, example: string, classes: any) =>
+    <div className={classes.spacing}>
+        {dialogContentHeader(header)}
+        {dialogContentExample(example, classes)}
+    </div>;
+
+const dialogContentHeader = (header: string) =>
+    <DialogContentText>
+        {header}
+    </DialogContentText>;
+
+const dialogContentExample = (example: string, classes: any) =>
+    <DefaultCodeSnippet
+        className={classes.codeSnippet}
+        lines={[example]} />;
\ No newline at end of file
diff --git a/src/views-components/advanced-tab-dialog/metadataTab.tsx b/src/views-components/advanced-tab-dialog/metadataTab.tsx
new file mode 100644 (file)
index 0000000..340149a
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { Table, TableHead, TableCell, TableRow, TableBody, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
+import { navigateTo } from "~/store/navigation/navigation-action";
+
+type CssRules = 'cell';
+
+const styles: StyleRulesCallback<CssRules> = theme => ({
+    cell: {
+        paddingRight: theme.spacing.unit * 2
+    }
+});
+
+interface MetadataTable {
+    uuid: string;
+    linkClass: string;
+    name: string;
+    tailUuid: string;
+    headUuid: string;
+    properties: any;
+}
+
+interface MetadataProps {
+    items: MetadataTable[];
+}
+
+export const MetadataTab = withStyles(styles)((props: MetadataProps & WithStyles<CssRules>) =>
+    <Table>
+        <TableHead>
+            <TableRow>
+                <TableCell>uuid</TableCell>
+                <TableCell>link_class</TableCell>
+                <TableCell>name</TableCell>
+                <TableCell>tail</TableCell>
+                <TableCell>head</TableCell>
+                <TableCell>properties</TableCell>
+            </TableRow>
+        </TableHead>
+        <TableBody>
+            {props.items.map((it, index) => {
+                return (
+                    <TableRow key={index}>
+                        <TableCell className={props.classes.cell}>{it.uuid}</TableCell>
+                        <TableCell className={props.classes.cell}>{it.linkClass}</TableCell>
+                        <TableCell className={props.classes.cell}>{it.name}</TableCell>
+                        <TableCell className={props.classes.cell}>{it.tailUuid}</TableCell>
+                        <TableCell className={props.classes.cell}>{it.headUuid}</TableCell>
+                        <TableCell className={props.classes.cell}>{JSON.stringify(it.properties, null, 2)}</TableCell>
+                    </TableRow>
+                );
+            })}
+        </TableBody>
+    </Table>
+);
\ No newline at end of file
index cff30fb166c9c60363ec1212b030ade0db586052..121fe17ab50947c48aadb74bf774ffddf9d99492 100644 (file)
@@ -13,14 +13,13 @@ import { openCollectionCopyDialog } from "~/store/collections/collection-copy-ac
 import { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action";
 import { toggleCollectionTrashed } from "~/store/trash/trash-actions";
 import { detailsPanelActions } from '~/store/details-panel/details-panel-action';
+import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
 
 export const collectionActionSet: ContextMenuActionSet = [[
     {
         icon: RenameIcon,
         name: "Edit collection",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openCollectionUpdateDialog(resource));
-        }
+        execute: (dispatch, resource) => dispatch<any>(openCollectionUpdateDialog(resource))
     },
     {
         icon: ShareIcon,
@@ -44,16 +43,13 @@ export const collectionActionSet: ContextMenuActionSet = [[
     },
     {
         component: ToggleTrashAction,
-        execute: (dispatch, resource) => {
-            dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
-        }
+        execute: (dispatch, resource) => dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!))
     },
     {
         icon: CopyIcon,
         name: "Copy to project",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openCollectionCopyDialog(resource));
-        }
+        execute: (dispatch, resource) => dispatch<any>(openCollectionCopyDialog(resource))
+
     },
     {
         icon: DetailsIcon,
@@ -70,9 +66,7 @@ export const collectionActionSet: ContextMenuActionSet = [[
     {
         icon: AdvancedIcon,
         name: "Advanced",
-        execute: (dispatch, resource) => {
-            // add code
-        }
+        execute: (dispatch, resource) => dispatch<any>(openAdvancedTabDialog(resource.uuid))
     },
     {
         icon: RemoveIcon,
index 5c4dab30e537f86ad4b079bf71e92339c1da895b..c86f1d7d617770f30979345ededb2066b898d9d6 100644 (file)
@@ -2,33 +2,23 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { ContextMenuActionSet } from "../context-menu-action-set";
+import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
 import { collectionPanelFilesAction, openMultipleFilesRemoveDialog } from "~/store/collection-panel/collection-panel-files/collection-panel-files-actions";
 import { openCollectionPartialCopyDialog } from '~/store/collections/collection-partial-copy-actions';
 
 export const collectionFilesActionSet: ContextMenuActionSet = [[{
     name: "Select all",
-    execute: (dispatch) => {
-        dispatch(collectionPanelFilesAction.SELECT_ALL_COLLECTION_FILES());
-    }
+    execute: dispatch => dispatch(collectionPanelFilesAction.SELECT_ALL_COLLECTION_FILES())
 }, {
     name: "Unselect all",
-    execute: (dispatch) => {
-        dispatch(collectionPanelFilesAction.UNSELECT_ALL_COLLECTION_FILES());
-    }
+    execute: dispatch => dispatch(collectionPanelFilesAction.UNSELECT_ALL_COLLECTION_FILES())
 }, {
     name: "Remove selected",
-    execute: (dispatch) => {
-        dispatch(openMultipleFilesRemoveDialog());
-    }
+    execute: dispatch => dispatch(openMultipleFilesRemoveDialog())
 }, {
     name: "Download selected",
-    execute: (dispatch, resource) => {
-        return;
-    }
+    execute: () => { return; }
 }, {
     name: "Create a new collection with selected",
-    execute: (dispatch) => {
-        dispatch<any>(openCollectionPartialCopyDialog());
-    }
+    execute: dispatch => dispatch<any>(openCollectionPartialCopyDialog())
 }]];
index b55648917329723d6cec917b8e73b53725695673..2baa52440162f48d68d3dcad64ad0f82a894f522 100644 (file)
@@ -11,16 +11,12 @@ import { openFileRemoveDialog, openRenameFileDialog } from '~/store/collection-p
 export const collectionFilesItemActionSet: ContextMenuActionSet = [[{
     name: "Rename",
     icon: RenameIcon,
-    execute: (dispatch, resource) => {
-        dispatch<any>(openRenameFileDialog({ name: resource.name, id: resource.uuid }));
-    }
+    execute: (dispatch, resource) => dispatch<any>(openRenameFileDialog({ name: resource.name, id: resource.uuid }))
 }, {
     component: DownloadCollectionFileAction,
     execute: () => { return; }
 }, {
     name: "Remove",
     icon: RemoveIcon,
-    execute: (dispatch, resource) => {
-        dispatch<any>(openFileRemoveDialog(resource.uuid));
-    }
+    execute: (dispatch, resource) => dispatch<any>(openFileRemoveDialog(resource.uuid))
 }]];
index 8665bc1b6b858a29f3e23ced0ba316b35298b5c4..c54d40e4cf6e853851a478cb8e2067e39061e793 100644 (file)
@@ -18,9 +18,7 @@ export const collectionResourceActionSet: ContextMenuActionSet = [[
     {
         icon: RenameIcon,
         name: "Edit collection",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openCollectionUpdateDialog(resource));
-        }
+        execute: (dispatch, resource) => dispatch<any>(openCollectionUpdateDialog(resource))
     },
     {
         icon: ShareIcon,
@@ -44,16 +42,12 @@ export const collectionResourceActionSet: ContextMenuActionSet = [[
     },
     {
         component: ToggleTrashAction,
-        execute: (dispatch, resource) => {
-            dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
-        }
+        execute: (dispatch, resource) => dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!))
     },
     {
         icon: CopyIcon,
         name: "Copy to project",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openCollectionCopyDialog(resource));
-        },
+        execute: (dispatch, resource) => dispatch<any>(openCollectionCopyDialog(resource))
     },
     {
         icon: DetailsIcon,
index 32488731862843e5f5645801ee65ba6f012b9d6d..9447567d1fb448f7db2c2c70bd11886080319926 100644 (file)
@@ -2,8 +2,8 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { ContextMenuActionSet } from "../context-menu-action-set";
-import { ToggleFavoriteAction } from "../actions/favorite-action";
+import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
+import { ToggleFavoriteAction } from "~/views-components/context-menu/actions/favorite-action";
 import { toggleFavorite } from "~/store/favorites/favorites-actions";
 import {
     RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, ProvenanceGraphIcon,
@@ -14,8 +14,9 @@ import { navigateToProcessLogs } from '~/store/navigation/navigation-action';
 import { openMoveProcessDialog } from '~/store/processes/process-move-actions';
 import { openProcessUpdateDialog } from "~/store/processes/process-update-actions";
 import { openCopyProcessDialog } from '~/store/processes/process-copy-actions';
-import { openProcessCommandDialog } from '../../../store/processes/process-command-actions';
+import { openProcessCommandDialog } from '~/store/processes/process-command-actions';
 import { detailsPanelActions } from '~/store/details-panel/details-panel-action';
+import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
 
 export const processActionSet: ContextMenuActionSet = [[
     {
@@ -72,9 +73,7 @@ export const processActionSet: ContextMenuActionSet = [[
     {
         icon: CommandIcon,
         name: "Command",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openProcessCommandDialog(resource.uuid));
-        }
+        execute: (dispatch, resource) => dispatch<any>(openProcessCommandDialog(resource.uuid))
     },
     {
         icon: DetailsIcon,
@@ -84,9 +83,7 @@ export const processActionSet: ContextMenuActionSet = [[
     {
         icon: LogIcon,
         name: "Log",
-        execute: (dispatch, resource) => {
-            dispatch<any>(navigateToProcessLogs(resource.uuid));
-        }
+        execute: (dispatch, resource) => dispatch<any>(navigateToProcessLogs(resource.uuid))
     },
     {
         icon: ProvenanceGraphIcon,
@@ -98,9 +95,7 @@ export const processActionSet: ContextMenuActionSet = [[
     {
         icon: AdvancedIcon,
         name: "Advanced",
-        execute: (dispatch, resource) => {
-            // add code
-        }
+        execute: (dispatch, resource) => dispatch<any>(openAdvancedTabDialog(resource.uuid))
     },
     {
         icon: RemoveIcon,
index 85848a2d6b3e9ec4ed09b258b0128b7b9167b96a..cc57a3f7475bccf50416f263c461a1a2b7b01017 100644 (file)
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { ContextMenuActionSet } from "../context-menu-action-set";
-import { NewProjectIcon, RenameIcon, CopyIcon, MoveToIcon, DetailsIcon } from '~/components/icon/icon';
+import { NewProjectIcon, RenameIcon, CopyIcon, MoveToIcon, DetailsIcon, AdvancedIcon } from '~/components/icon/icon';
 import { ToggleFavoriteAction } from "../actions/favorite-action";
 import { toggleFavorite } from "~/store/favorites/favorites-actions";
 import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
@@ -13,21 +13,18 @@ import { openProjectUpdateDialog } from '~/store/projects/project-update-actions
 import { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action";
 import { toggleProjectTrashed } from "~/store/trash/trash-actions";
 import { detailsPanelActions } from '~/store/details-panel/details-panel-action';
+import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
 
 export const projectActionSet: ContextMenuActionSet = [[
     {
         icon: NewProjectIcon,
         name: "New project",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openProjectCreateDialog(resource.uuid));
-        }
+        execute: (dispatch, resource) => dispatch<any>(openProjectCreateDialog(resource.uuid))
     },
     {
         icon: RenameIcon,
         name: "Edit project",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openProjectUpdateDialog(resource));
-        }
+        execute: (dispatch, resource) => dispatch<any>(openProjectUpdateDialog(resource))
     },
     {
         component: ToggleFavoriteAction,
@@ -39,9 +36,7 @@ export const projectActionSet: ContextMenuActionSet = [[
     },
     {
         component: ToggleTrashAction,
-        execute: (dispatch, resource) => {
-            dispatch<any>(toggleProjectTrashed(resource.uuid, resource.ownerUuid, resource.isTrashed!!));
-        }
+        execute: (dispatch, resource) => dispatch<any>(toggleProjectTrashed(resource.uuid, resource.ownerUuid, resource.isTrashed!!))
     },
     {
         icon: MoveToIcon,
@@ -59,5 +54,10 @@ export const projectActionSet: ContextMenuActionSet = [[
         icon: DetailsIcon,
         name: "View details",
         execute: dispatch => dispatch(detailsPanelActions.TOGGLE_DETAILS_PANEL())
-    }
+    },
+    {
+        icon: AdvancedIcon,
+        name: "Advanced",
+        execute: (dispatch, resource) => dispatch<any>(openAdvancedTabDialog(resource.uuid))
+    },
 ]];
index 386c5162f3c6ab9858c55f9b25468acbd98b353c..d80fc9dab45a9617b9bd162c5f127b144b9bbb95 100644 (file)
@@ -11,15 +11,11 @@ export const rootProjectActionSet: ContextMenuActionSet =  [[
     {
         icon: NewProjectIcon,
         name: "New project",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openProjectCreateDialog(resource.uuid));
-        }
+        execute: (dispatch, resource) =>  dispatch<any>(openProjectCreateDialog(resource.uuid))
     },
     {
         icon: CollectionIcon,
         name: "New Collection",
-        execute: (dispatch, resource) => {
-            dispatch<any>(openCollectionCreateDialog(resource.uuid));
-        }
+        execute: (dispatch, resource) => dispatch<any>(openCollectionCreateDialog(resource.uuid))
     }
 ]];
index fafd5feb2246fe5bf9900a7f2e9c9a3e4a7d0561..f81a9952a94ab054056732bb6c0a00accf859060 100644 (file)
@@ -9,8 +9,6 @@ import { toggleTrashed } from "~/store/trash/trash-actions";
 export const trashActionSet: ContextMenuActionSet = [[
     {
         component: ToggleTrashAction,
-        execute: (dispatch, resource) => {
-            dispatch<any>(toggleTrashed(resource.kind, resource.uuid, resource.ownerUuid, resource.isTrashed!!));
-        }
+        execute: (dispatch, resource) => dispatch<any>(toggleTrashed(resource.kind, resource.uuid, resource.ownerUuid, resource.isTrashed!!))
     },
 ]];
index c42da1e6f8c013ee7e06b0d406e87170e3a5a6dc..e11228b49eac0be4f8f09f680d09426ad32a0cba 100644 (file)
@@ -5,14 +5,14 @@
 import { ContextMenuActionSet } from "../context-menu-action-set";
 import { DetailsIcon, ProvenanceGraphIcon, AdvancedIcon, RestoreFromTrashIcon } from '~/components/icon/icon';
 import { toggleCollectionTrashed } from "~/store/trash/trash-actions";
+import { detailsPanelActions } from "~/store/details-panel/details-panel-action";
+import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
 
 export const trashedCollectionActionSet: ContextMenuActionSet = [[
     {
         icon: DetailsIcon,
         name: "View details",
-        execute: (dispatch, resource) => {
-            // add code
-        }
+        execute: dispatch => dispatch(detailsPanelActions.TOGGLE_DETAILS_PANEL())
     },
     {
         icon: ProvenanceGraphIcon,
@@ -24,15 +24,11 @@ export const trashedCollectionActionSet: ContextMenuActionSet = [[
     {
         icon: AdvancedIcon,
         name: "Advanced",
-        execute: (dispatch, resource) => {
-            // add code
-        }
+        execute: (dispatch, resource) => dispatch<any>(openAdvancedTabDialog(resource.uuid))
     },
     {
         icon: RestoreFromTrashIcon,
         name: "Restore",
-        execute: (dispatch, resource) => {
-            dispatch<any>(toggleCollectionTrashed(resource.uuid, true));
-        }
+        execute: (dispatch, resource) => dispatch<any>(toggleCollectionTrashed(resource.uuid, true))
     },
 ]];
index 788c96ae6b2552500ec3922fdd59748493f0347d..1e6538485ec8e538c975b5d2eeca84b4b607a8fc 100644 (file)
@@ -42,12 +42,7 @@ import { RunProcessPanel } from '~/views/run-process-panel/run-process-panel';
 import SplitterLayout from 'react-splitter-layout';
 import { WorkflowPanel } from '~/views/workflow-panel/workflow-panel';
 import { SearchResultsPanel } from '~/views/search-results-panel/search-results-panel';
-import { HomeTreePicker } from '~/views-components/projects-tree-picker/home-tree-picker';
-import { SharedTreePicker } from '~/views-components/projects-tree-picker/shared-tree-picker';
-import { FavoritesTreePicker } from '../../views-components/projects-tree-picker/favorites-tree-picker';
-import { ProjectsTreePicker } from '~/views-components/projects-tree-picker/projects-tree-picker';
-import { Chips } from '~/components/chips/chips';
-import { ChipsInput } from '../../components/chips-input/chips-input';
+import { AdvancedTabDialog } from '~/views-components/advanced-tab-dialog/advanced-tab-dialog';
 
 type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
 
@@ -114,6 +109,7 @@ export const WorkbenchPanel =
             <Grid item>
                 <DetailsPanel />
             </Grid>
+            <AdvancedTabDialog />
             <ContextMenu />
             <CopyCollectionDialog />
             <CopyProcessDialog />
index 70fdb6b3b64d4a6477bfcb2eef178b547bb162e8..b4b9f20ae42d6c7043a6d0343e6ff842780eb649 100644 (file)
@@ -14,8 +14,7 @@ import {
     TableHead,
     TableCell,
     TableBody,
-    TableRow,
-    Divider
+    TableRow
 } from '@material-ui/core';
 import { ArvadosTheme } from '~/common/custom-theme';
 import { WorkflowIcon } from '~/components/icon/icon';