X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/92a147d8e4fd5b02264c06ec432255777cb942c7..6f80d59b4d111454ce848f18c93aec8a891ff908:/services/workbench2/src/views-components/project-details-card/project-details-card.tsx diff --git a/services/workbench2/src/views-components/project-details-card/project-details-card.tsx b/services/workbench2/src/views-components/project-details-card/project-details-card.tsx index 0988d7c168..49884e45de 100644 --- a/services/workbench2/src/views-components/project-details-card/project-details-card.tsx +++ b/services/workbench2/src/views-components/project-details-card/project-details-card.tsx @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0 import React from 'react'; -import { StyleRulesCallback, Card, CardHeader, WithStyles, withStyles, Typography, CardContent, Tooltip, Collapse } from '@material-ui/core'; +import { StyleRulesCallback, Card, CardHeader, WithStyles, withStyles, Typography, CardContent, Tooltip, Collapse, Grid } from '@material-ui/core'; import { ArvadosTheme } from 'common/custom-theme'; import { RootState } from 'store/store'; import { connect } from 'react-redux'; @@ -14,23 +14,20 @@ import { ResourceKind } from 'models/resource'; import { UserResource } from 'models/user'; import { UserResourceAccountStatus } from 'views-components/data-explorer/renderers'; import { FavoriteStar, PublicFavoriteStar } from 'views-components/favorite-star/favorite-star'; -import { MoreVerticalIcon, FreezeIcon } from 'components/icon/icon'; +import { FreezeIcon } from 'components/icon/icon'; import { Resource } from 'models/resource'; -import { IconButton } from '@material-ui/core'; -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 classNames from 'classnames'; import { loadDetailsPanel } from 'store/details-panel/details-panel-action'; import { ExpandChevronRight } from 'components/expand-chevron-right/expand-chevron-right'; import { MultiselectToolbar } from 'components/multiselect-toolbar/MultiselectToolbar'; +import { setSelectedResourceUuid } from 'store/selected-resource/selected-resource-actions'; +import { deselectAllOthers } from 'store/multiselect/multiselect-actions'; type CssRules = | 'root' - | 'selected' + | 'cardHeaderContainer' | 'cardHeader' + | 'projectToolbar' | 'descriptionToggle' | 'showMore' | 'noDescription' @@ -40,7 +37,8 @@ type CssRules = | 'namePlate' | 'faveIcon' | 'frozenIcon' - | 'contextMenuSection' + | 'accountStatusSection' + | 'chipSection' | 'tag' | 'description'; @@ -50,26 +48,35 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ marginBottom: '1rem', flex: '0 0 auto', padding: 0, - border: '2px solid transparent', - }, - selected: { - border: '2px solid #ccc', + minHeight: '3rem', }, showMore: { cursor: 'pointer', - background: 'linear-gradient(to right, black, transparent)', - backgroundClip: 'text', - color: 'transparent', }, noDescription: { color: theme.palette.grey['600'], fontStyle: 'italic', + padding: '0 0 0.5rem 1rem', + marginTop: '-0.5rem', }, userNameContainer: { display: 'flex', + alignItems: 'center', + minHeight: '2.7rem', + }, + cardHeaderContainer: { + width: '100%', + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', }, cardHeader: { - padding: '0.2rem 0.4rem 0.1rem 1rem', + minWidth: '30rem', + padding: '0.2rem 0.4rem 0.2rem 1rem', + }, + projectToolbar: { + //shows only the first 3 buttons + width: '12rem !important', }, descriptionToggle: { display: 'flex', @@ -80,59 +87,59 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ cardContent: { display: 'flex', flexDirection: 'column', - marginTop: '-1.75rem', + paddingTop: 0, + paddingLeft: '0.1rem', }, nameSection: { display: 'flex', flexDirection: 'row', alignItems: 'center', - justifyContent: 'space-between', }, namePlate: { display: 'flex', flexDirection: 'row', alignItems: 'center', margin: 0, - paddingBottom: '0.5rem', + 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, }, - contextMenuSection: { + accountStatusSection: { display: 'flex', flexDirection: 'row', alignItems: 'center', - paddingTop: '0.25rem', + paddingLeft: '1rem', + }, + chipSection: { + marginBottom: '-2rem', }, tag: { - marginRight: '1rem', - marginTop: '1rem', + marginRight: '0.75rem', + marginBottom: '0.5rem', }, description: { - maxWidth: '90%', + maxWidth: '95%', marginTop: 0, }, }); -const mapStateToProps = (state: RootState) => { - const currentRoute = state.router.location?.pathname.split('/') || []; - const currentItemUuid = currentRoute[currentRoute.length - 1]; - const currentResource = getResource(currentItemUuid)(state.resources); - const frozenByUser = currentResource && getResource((currentResource as ProjectResource).frozenByUuid as string)(state.resources); +const mapStateToProps = ({ auth, selectedResourceUuid, resources, properties }: RootState) => { + const currentResource = getResource(properties.currentRouteUuid)(resources); + const frozenByUser = currentResource && getResource((currentResource as ProjectResource).frozenByUuid as string)(resources); const frozenByFullName = frozenByUser && (frozenByUser as Resource & { fullName: string }).fullName; - const isSelected = currentItemUuid === state.detailsPanel.resourceUuid && state.detailsPanel.isOpened === true; + const isSelected = selectedResourceUuid === properties.currentRouteUuid; return { - isAdmin: state.auth.user?.isAdmin, + isAdmin: auth.user?.isAdmin, currentResource, frozenByFullName, isSelected, @@ -142,36 +149,10 @@ const mapStateToProps = (state: RootState) => { const mapDispatchToProps = (dispatch: Dispatch) => ({ handleCardClick: (uuid: string) => { dispatch(loadDetailsPanel(uuid)); + dispatch(setSelectedResourceUuid(uuid)); + dispatch(deselectAllOthers(uuid)); }, - handleContextMenu: (event: React.MouseEvent, 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(resourceUuidToContextMenuKind(resource.uuid, readOnly)); - if (menuKind === ContextMenuKind.ROOT_PROJECT) { - menuKind = ContextMenuKind.USER_DETAILS; - } - if (menuKind && resource) { - dispatch( - 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 & { @@ -179,7 +160,6 @@ type DetailsCardProps = WithStyles & { frozenByFullName?: string; isAdmin: boolean; isSelected: boolean; - handleContextMenu: (event: React.MouseEvent, resource: ContextMenuResource, isAdmin: boolean) => void; handleCardClick: (resource: any) => void; }; @@ -187,7 +167,6 @@ type UserCardProps = WithStyles & { currentResource: UserResource; isAdmin: boolean; isSelected: boolean; - handleContextMenu: (event: React.MouseEvent, resource: ContextMenuResource, isAdmin: boolean) => void; handleCardClick: (resource: any) => void; }; @@ -196,7 +175,6 @@ type ProjectCardProps = WithStyles & { frozenByFullName: string | undefined; isAdmin: boolean; isSelected: boolean; - handleContextMenu: (event: React.MouseEvent, 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} /> ); @@ -229,7 +206,6 @@ export const ProjectDetailsCard = connect( frozenByFullName={frozenByFullName} isAdmin={isAdmin} isSelected={isSelected} - handleContextMenu={(ev) => handleContextMenu(ev, currentResource as any, isAdmin)} handleCardClick={handleCardClick} /> ); @@ -239,54 +215,47 @@ export const ProjectDetailsCard = connect( }) ); -const UserCard: React.FC = ({ classes, currentResource, handleContextMenu, handleCardClick, isAdmin, isSelected }) => { +const UserCard: React.FC = ({ classes, currentResource, handleCardClick, isSelected }) => { const { fullName, uuid } = currentResource as UserResource & { fullName: string }; return ( handleCardClick(uuid)} data-cy='user-details-card' > - - - {fullName} - - - } - action={ -
- {!currentResource.isActive && ( - - - - )} - - handleContextMenu(ev, currentResource as any, isAdmin)} + + + - - - -
- } - /> + {fullName} + +
+ {!currentResource.isActive && ( + + + + )} +
+ + } + /> + {isSelected && } +
); }; -const ProjectCard: React.FC = ({ classes, currentResource, frozenByFullName, handleContextMenu, handleCardClick, isAdmin, isSelected }) => { +const ProjectCard: React.FC = ({ classes, currentResource, frozenByFullName, handleCardClick, isSelected }) => { const { name, description, uuid } = currentResource as ProjectResource; const [showDescription, setShowDescription] = React.useState(false); const [showProperties, setShowProperties] = React.useState(false); @@ -301,59 +270,49 @@ const ProjectCard: React.FC = ({ classes, currentResource, fro return ( handleCardClick(uuid)} data-cy='project-details-card' > - -
- - {name} - - - - {!!frozenByFullName && ( - Project was frozen by {frozenByFullName}} + + +
+ - - - )} + {name} + + + + {!!frozenByFullName && ( + Project was frozen by {frozenByFullName}} + > + + + )} +
- - } - action={ - - //
- // - // handleContextMenu(ev, currentResource as any, isAdmin)} - // > - // - // - // - //
- } - /> + } + /> + {isSelected && } +
ev.stopPropagation()}> {description ? (
= ({ classes, currentResource, fro - {description} - + //dangerouslySetInnerHTML is ok here only if description is sanitized, + //which it is before it is loaded into the redux store + dangerouslySetInnerHTML={{ __html: description }} + />
@@ -396,12 +356,12 @@ const ProjectCard: React.FC = ({ classes, currentResource, fro timeout='auto' collapsedHeight='35px' > - - + {Object.keys(currentResource.properties).map((k) => Array.isArray(currentResource.properties[k]) ? currentResource.properties[k].map((v: string) => getPropertyChip(k, v, undefined, classes.tag)) @@ -409,7 +369,7 @@ const ProjectCard: React.FC = ({ classes, currentResource, fro )} - +