X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/8e812c1e720af23a4fa50a492981940cddd4f7f3..40b55e355fe0a206a4cb3eec676e44d935b7d5ec:/src/views/collection-panel/collection-panel.tsx

diff --git a/src/views/collection-panel/collection-panel.tsx b/src/views/collection-panel/collection-panel.tsx
index 94a5af33..851008c0 100644
--- a/src/views/collection-panel/collection-panel.tsx
+++ b/src/views/collection-panel/collection-panel.tsx
@@ -3,25 +3,30 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from 'react';
+import { Dispatch } from 'redux';
 import {
-    StyleRulesCallback, WithStyles, withStyles,
-    IconButton, Grid, Tooltip, Typography, ExpansionPanel,
-    ExpansionPanelSummary, ExpansionPanelDetails
+    StyleRulesCallback,
+    WithStyles,
+    withStyles,
+    IconButton,
+    Grid,
+    Tooltip,
+    Typography,
+    Card
 } from '@material-ui/core';
 import { connect, DispatchProp } from "react-redux";
 import { RouteComponentProps } from 'react-router';
 import { ArvadosTheme } from 'common/custom-theme';
 import { RootState } from 'store/store';
-import { MoreOptionsIcon, CollectionIcon, ReadOnlyIcon, ExpandIcon, CollectionOldVersionIcon } from 'components/icon/icon';
+import { MoreOptionsIcon, CollectionIcon, ReadOnlyIcon, CollectionOldVersionIcon, RenameIcon } from 'components/icon/icon';
 import { DetailsAttribute } from 'components/details-attribute/details-attribute';
 import { CollectionResource, getCollectionUrl } from 'models/collection';
 import { CollectionPanelFiles } from 'views-components/collection-panel-files/collection-panel-files';
-import { CollectionTagForm } from './collection-tag-form';
-import { deleteCollectionTag, navigateToProcess, collectionPanelActions } from 'store/collection-panel/collection-panel-action';
+import { navigateToProcess, collectionPanelActions } from 'store/collection-panel/collection-panel-action';
 import { getResource } from 'store/resources/resources';
 import { openContextMenu, resourceUuidToContextMenuKind } from 'store/context-menu/context-menu-actions';
 import { formatDate, formatFileSize } from "common/formatters";
-import { openDetailsPanel } from 'store/details-panel/details-panel-action';
+import { openDetailsPanel, openResourcePropertiesDialog } from 'store/details-panel/details-panel-action';
 import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
 import { getPropertyChip } from 'views-components/resource-properties-form/property-chip';
 import { IllegalNamingWarning } from 'components/warning/warning';
@@ -33,9 +38,12 @@ import { COLLECTION_PANEL_LOAD_FILES, loadCollectionFiles, COLLECTION_PANEL_LOAD
 import { Link } from 'react-router-dom';
 import { Link as ButtonLink } from '@material-ui/core';
 import { ResourceOwnerWithName, ResponsiblePerson } from 'views-components/data-explorer/renderers';
+import { MPVContainer, MPVPanelContent, MPVPanelState } from 'components/multi-panel-view/multi-panel-view';
 
 type CssRules = 'root'
     | 'button'
+    | 'infoCard'
+    | 'propertiesCard'
     | 'filesCard'
     | 'iconHeader'
     | 'tag'
@@ -49,16 +57,21 @@ type CssRules = 'root'
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     root: {
-        display: 'flex',
-        flexFlow: 'column',
-        height: 'calc(100vh - 130px)', // (100% viewport height) - (top bar + breadcrumbs)
+        width: '100%',
     },
     button: {
         cursor: 'pointer'
     },
+    infoCard: {
+        paddingLeft: theme.spacing.unit * 2,
+        paddingRight: theme.spacing.unit * 2,
+        paddingBottom: theme.spacing.unit * 2,
+    },
+    propertiesCard: {
+        padding: 0,
+    },
     filesCard: {
-        marginBottom: theme.spacing.unit * 2,
-        flex: 1,
+        padding: 0,
     },
     iconHeader: {
         fontSize: '1.875rem',
@@ -120,7 +133,7 @@ export const CollectionPanel = withStyles(styles)(
                 isWritable = true;
             } else {
                 const itemOwner = getResource<GroupResource | UserResource>(item.ownerUuid)(state.resources);
-                if (itemOwner) {
+                if (itemOwner && itemOwner.writableBy) {
                     isWritable = itemOwner.writableBy.indexOf(currentUserUUID || '') >= 0;
                 }
             }
@@ -133,10 +146,14 @@ export const CollectionPanel = withStyles(styles)(
         class extends React.Component<CollectionPanelProps> {
             render() {
                 const { classes, item, dispatch, isWritable, isOldVersion, isLoadingFiles, tooManyFiles } = this.props;
+                const panelsData: MPVPanelState[] = [
+                    {name: "Details"},
+                    {name: "Files"},
+                ];
                 return item
-                    ? <div className={classes.root}>
-                        <ExpansionPanel data-cy='collection-info-panel' defaultExpanded>
-                            <ExpansionPanelSummary expandIcon={<ExpandIcon />}>
+                    ? <MPVContainer className={classes.root} spacing={8} direction="column" justify-content="flex-start" wrap="nowrap" panelStates={panelsData}>
+                        <MPVPanelContent xs="auto" data-cy='collection-info-panel'>
+                            <Card className={classes.infoCard}>
                                 <Grid container justify="space-between">
                                     <Grid item xs={11}><span>
                                         <IconButton onClick={this.openCollectionDetails}>
@@ -165,8 +182,6 @@ export const CollectionPanel = withStyles(styles)(
                                         </Tooltip>
                                     </Grid>
                                 </Grid>
-                            </ExpansionPanelSummary>
-                            <ExpansionPanelDetails>
                                 <Grid container justify="space-between">
                                     <Grid item xs={12}>
                                         <Typography variant="caption">
@@ -185,67 +200,38 @@ export const CollectionPanel = withStyles(styles)(
                                         }
                                     </Grid>
                                 </Grid>
-                            </ExpansionPanelDetails>
-                        </ExpansionPanel>
-
-                        <ExpansionPanel data-cy='collection-properties-panel' defaultExpanded>
-                            <ExpansionPanelSummary expandIcon={<ExpandIcon />}>
-                                {"Properties"}
-                            </ExpansionPanelSummary>
-                            <ExpansionPanelDetails>
-                                <Grid container>
-                                    {isWritable && <Grid item xs={12}>
-                                        <CollectionTagForm />
-                                    </Grid>}
-                                    <Grid item xs={12}>
-                                        {Object.keys(item.properties).length > 0
-                                            ? Object.keys(item.properties).map(k =>
-                                                Array.isArray(item.properties[k])
-                                                    ? item.properties[k].map((v: string) =>
-                                                        getPropertyChip(
-                                                            k, v,
-                                                            isWritable
-                                                                ? this.handleDelete(k, v)
-                                                                : undefined,
-                                                            classes.tag))
-                                                    : getPropertyChip(
-                                                        k, item.properties[k],
-                                                        isWritable
-                                                            ? this.handleDelete(k, item.properties[k])
-                                                            : undefined,
-                                                        classes.tag)
-                                            )
-                                            : <div className={classes.centeredLabel}>No properties set on this collection.</div>
-                                        }
-                                    </Grid>
-                                </Grid>
-                            </ExpansionPanelDetails>
-                        </ExpansionPanel>
-                        <div className={classes.filesCard}>
-                            <CollectionPanelFiles
-                                isWritable={isWritable}
-                                isLoading={isLoadingFiles}
-                                tooManyFiles={tooManyFiles}
-                                loadFilesFunc={() => {
-                                    dispatch(collectionPanelActions.LOAD_BIG_COLLECTIONS(true));
-                                    dispatch<any>(loadCollectionFiles(this.props.item.uuid));
-                                }
-                                } />
-                        </div>
-                    </div>
+                            </Card>
+                        </MPVPanelContent>
+                        <MPVPanelContent xs>
+                            <Card className={classes.filesCard}>
+                                <CollectionPanelFiles
+                                    isWritable={isWritable}
+                                    isLoading={isLoadingFiles}
+                                    tooManyFiles={tooManyFiles}
+                                    loadFilesFunc={() => {
+                                        dispatch(collectionPanelActions.LOAD_BIG_COLLECTIONS(true));
+                                        dispatch<any>(loadCollectionFiles(this.props.item.uuid));
+                                    }
+                                    } />
+                            </Card>
+                        </MPVPanelContent>
+                    </MPVContainer>
                     : null;
             }
 
             handleContextMenu = (event: React.MouseEvent<any>) => {
-                const { uuid, ownerUuid, name, description, kind } = this.props.item;
+                const { uuid, ownerUuid, name, description,
+                    kind, storageClassesDesired, properties } = this.props.item;
                 const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(uuid));
                 const resource = {
                     uuid,
                     ownerUuid,
                     name,
                     description,
+                    storageClassesDesired,
                     kind,
                     menuKind,
+                    properties,
                 };
                 // Avoid expanding/collapsing the panel
                 event.stopPropagation();
@@ -259,10 +245,6 @@ export const CollectionPanel = withStyles(styles)(
                     kind: SnackbarKind.SUCCESS
                 }))
 
-            handleDelete = (key: string, value: string) => () => {
-                this.props.dispatch<any>(deleteCollectionTag(key, value));
-            }
-
             openCollectionDetails = (e: React.MouseEvent<HTMLElement>) => {
                 const { item } = this.props;
                 if (item) {
@@ -279,9 +261,25 @@ export const CollectionPanel = withStyles(styles)(
     )
 );
 
-export const CollectionDetailsAttributes = (props: { item: CollectionResource, twoCol: boolean, classes?: Record<CssRules, string>, showVersionBrowser?: () => void }) => {
+interface CollectionDetailsActionProps {
+    onClick: () => void;
+}
+
+interface CollectionDetailsProps {
+    item: CollectionResource;
+    classes?: any;
+    twoCol?: boolean;
+    showVersionBrowser?: () => void;
+}
+
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+    onClick: () => dispatch<any>(openResourcePropertiesDialog()),
+});
+
+export const CollectionDetailsAttributes = connect(null, mapDispatchToProps)(
+(props: CollectionDetailsProps & CollectionDetailsActionProps) => {
     const item = props.item;
-    const classes = props.classes || { label: '', value: '', button: '' };
+    const classes = props.classes || { label: '', value: '', button: '', tag: '' };
     const isOldVersion = item && item.currentVersionUuid !== item.uuid;
     const mdSize = props.twoCol ? 6 : 12;
     const showVersionBrowser = props.showVersionBrowser;
@@ -341,5 +339,26 @@ export const CollectionDetailsAttributes = (props: { item: CollectionResource, t
             <DetailsAttribute classLabel={classes.label} classValue={classes.value}
                 label='Content size' value={formatFileSize(item.fileSizeTotal)} />
         </Grid>
+        <Grid item xs={12} md={mdSize}>
+            <DetailsAttribute classLabel={classes.label} classValue={classes.value}
+                label='Storage classes' value={item.storageClassesDesired.join(', ')} />
+        </Grid>
+        <Grid item xs={12} md={mdSize}>
+            <DetailsAttribute classLabel={classes.label} classValue={classes.value}
+                label='Properties'>
+                { !props.twoCol
+                    ? <div data-cy='property-editor-btn' onClick={props.onClick}>
+                        <RenameIcon className={classes.editIcon} />
+                    </div>
+                    : '' }
+            </DetailsAttribute>
+            { Object.keys(item.properties).length > 0
+                ? Object.keys(item.properties).map(k =>
+                        Array.isArray(item.properties[k])
+                        ? item.properties[k].map((v: string) =>
+                            getPropertyChip(k, v, undefined, classes.tag))
+                        : getPropertyChip(k, item.properties[k], undefined, classes.tag))
+                : <div className={classes.value}>No properties</div> }
+        </Grid>
     </Grid>;
-};
+});
