21224: set project card to only display 3 buttons Arvados-DCO-1.1-Signed-off-by:...
[arvados.git] / services / workbench2 / src / views-components / project-details-card / project-details-card.tsx
index 8a3c2da4c92e7d3ccd1a284146447ca7b85e4d2d..49884e45dee7eec241bd78ba170c6038d2351acc 100644 (file)
@@ -16,10 +16,6 @@ import { UserResourceAccountStatus } from 'views-components/data-explorer/render
 import { FavoriteStar, PublicFavoriteStar } from 'views-components/favorite-star/favorite-star';
 import { FreezeIcon } from 'components/icon/icon';
 import { Resource } from 'models/resource';
-import { ContextMenuResource } from 'store/context-menu/context-menu-actions';
-import { openContextMenu, resourceUuidToContextMenuKind } from 'store/context-menu/context-menu-actions';
-import { CollectionResource } from 'models/collection';
-import { ContextMenuKind } from 'views-components/context-menu/context-menu';
 import { Dispatch } from 'redux';
 import { loadDetailsPanel } from 'store/details-panel/details-panel-action';
 import { ExpandChevronRight } from 'components/expand-chevron-right/expand-chevron-right';
@@ -31,6 +27,7 @@ type CssRules =
     | 'root'
     | 'cardHeaderContainer'
     | 'cardHeader'
+    | 'projectToolbar'
     | 'descriptionToggle'
     | 'showMore'
     | 'noDescription'
@@ -41,6 +38,7 @@ type CssRules =
     | 'faveIcon'
     | 'frozenIcon'
     | 'accountStatusSection'
+    | 'chipSection'
     | 'tag'
     | 'description';
 
@@ -58,6 +56,8 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     noDescription: {
         color: theme.palette.grey['600'],
         fontStyle: 'italic',
+        padding: '0  0 0.5rem 1rem',
+        marginTop: '-0.5rem',
     },
     userNameContainer: {
         display: 'flex',
@@ -74,6 +74,10 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         minWidth: '30rem',
         padding: '0.2rem 0.4rem 0.2rem 1rem',
     },
+    projectToolbar: {
+        //shows only the first 3 buttons
+        width: '12rem !important',
+    },
     descriptionToggle: {
         display: 'flex',
         flexDirection: 'row',
@@ -83,7 +87,8 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     cardContent: {
         display: 'flex',
         flexDirection: 'column',
-        marginTop: '-1.75rem',
+        paddingTop: 0,
+        paddingLeft: '0.1rem',
     },
     nameSection: {
         display: 'flex',
@@ -95,16 +100,16 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         flexDirection: 'row',
         alignItems: 'center',
         margin: 0,
+        minHeight: '2.7rem',
     },
     faveIcon: {
         fontSize: '0.8rem',
-        margin: 'auto 0 0.5rem 0.3rem',
+        margin: 'auto 0 1rem 0.3rem',
         color: theme.palette.text.primary,
     },
     frozenIcon: {
         fontSize: '0.5rem',
         marginLeft: '0.3rem',
-        marginTop: '0.1rem',
         height: '1rem',
         color: theme.palette.text.primary,
     },
@@ -114,9 +119,12 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         alignItems: 'center',
         paddingLeft: '1rem',
     },
+    chipSection: {
+        marginBottom: '-2rem',
+    },
     tag: {
-        marginRight: '1rem',
-        marginTop: '1rem',
+        marginRight: '0.75rem',
+        marginBottom: '0.5rem',
     },
     description: {
         maxWidth: '95%',
@@ -144,35 +152,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
         dispatch<any>(setSelectedResourceUuid(uuid));
         dispatch<any>(deselectAllOthers(uuid));
     },
-    handleContextMenu: (event: React.MouseEvent<HTMLElement>, resource: any, isAdmin: boolean) => {
-        event.stopPropagation();
-        // When viewing the contents of a filter group, all contents should be treated as read only.
-        let readOnly = false;
-        if (resource.groupClass === 'filter') {
-            readOnly = true;
-        }
-        let menuKind = dispatch<any>(resourceUuidToContextMenuKind(resource.uuid, readOnly));
-        if (menuKind === ContextMenuKind.ROOT_PROJECT) {
-            menuKind = ContextMenuKind.USER_DETAILS;
-        }
-        if (menuKind && resource) {
-            dispatch<any>(
-                openContextMenu(event, {
-                    name: resource.name,
-                    uuid: resource.uuid,
-                    ownerUuid: resource.ownerUuid,
-                    isTrashed: 'isTrashed' in resource ? resource.isTrashed : false,
-                    kind: resource.kind,
-                    menuKind,
-                    isAdmin,
-                    isFrozen: !!resource.frozenByUuid,
-                    description: resource.description,
-                    storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
-                    properties: 'properties' in resource ? resource.properties : {},
-                })
-            );
-        }
-    },
+    
 });
 
 type DetailsCardProps = WithStyles<CssRules> & {
@@ -180,7 +160,6 @@ type DetailsCardProps = WithStyles<CssRules> & {
     frozenByFullName?: string;
     isAdmin: boolean;
     isSelected: boolean;
-    handleContextMenu: (event: React.MouseEvent<HTMLElement>, resource: ContextMenuResource, isAdmin: boolean) => void;
     handleCardClick: (resource: any) => void;
 };
 
@@ -188,7 +167,6 @@ type UserCardProps = WithStyles<CssRules> & {
     currentResource: UserResource;
     isAdmin: boolean;
     isSelected: boolean;
-    handleContextMenu: (event: React.MouseEvent<HTMLElement>, resource: ContextMenuResource, isAdmin: boolean) => void;
     handleCardClick: (resource: any) => void;
 };
 
@@ -205,7 +183,7 @@ export const ProjectDetailsCard = connect(
     mapDispatchToProps
 )(
     withStyles(styles)((props: DetailsCardProps) => {
-        const { classes, currentResource, frozenByFullName, handleContextMenu, handleCardClick, isAdmin, isSelected } = props;
+        const { classes, currentResource, frozenByFullName, handleCardClick, isAdmin, isSelected } = props;
         if (!currentResource) {
             return null;
         }
@@ -217,7 +195,6 @@ export const ProjectDetailsCard = connect(
                         currentResource={currentResource as UserResource}
                         isAdmin={isAdmin}
                         isSelected={isSelected}
-                        handleContextMenu={(ev) => handleContextMenu(ev, currentResource as any, isAdmin)}
                         handleCardClick={handleCardClick}
                     />
                 );
@@ -334,7 +311,7 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ classes, currentResource, fro
                         </section>
                     }
                 />
-                {isSelected && <MultiselectToolbar />}
+                {isSelected && <MultiselectToolbar injectedStyles={classes.projectToolbar} />}
             </Grid>
             <section onClick={(ev) => ev.stopPropagation()}>
                 {description ? (
@@ -352,9 +329,10 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ classes, currentResource, fro
                                 <Typography
                                     className={classes.description}
                                     data-cy='project-description'
-                                >
-                                    {description}
-                                </Typography>
+                                    //dangerouslySetInnerHTML is ok here only if description is sanitized,
+                                    //which it is before it is loaded into the redux store
+                                    dangerouslySetInnerHTML={{ __html: description }}
+                                />
                             </Collapse>
                         </section>
                     </section>
@@ -383,7 +361,7 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ classes, currentResource, fro
                                     data-cy='project-description'
                                 >
                                     <CardContent className={classes.cardContent}>
-                                        <Typography component='div'>
+                                        <Typography component='div' className={classes.chipSection}>
                                             {Object.keys(currentResource.properties).map((k) =>
                                                 Array.isArray(currentResource.properties[k])
                                                     ? currentResource.properties[k].map((v: string) => getPropertyChip(k, v, undefined, classes.tag))