1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React from 'react';
6 import { Card, CardHeader, WithStyles, withStyles, Typography, CardContent } from '@material-ui/core';
7 import { StyleRulesCallback } from '@material-ui/core';
8 import { ArvadosTheme } from 'common/custom-theme';
9 import { RootState } from 'store/store';
10 import { connect } from 'react-redux';
11 import { getResource } from 'store/resources/resources';
12 import { MultiselectToolbar } from 'components/multiselect-toolbar/MultiselectToolbar';
13 import { DetailsAttribute } from 'components/details-attribute/details-attribute';
14 import { RichTextEditorLink } from 'components/rich-text-editor-link/rich-text-editor-link';
15 import { getPropertyChip } from '../resource-properties-form/property-chip';
16 import { ProjectResource } from 'models/project';
17 import { GroupClass } from 'models/group';
18 import { ResourceWithName } from 'views-components/data-explorer/renderers';
19 import { formatDate } from 'common/formatters';
20 import { resourceLabel } from 'common/labels';
21 import { ResourceKind } from 'models/resource';
22 import { UserResource } from 'models/user';
23 import { UserResourceAccountStatus } from 'views-components/data-explorer/renderers';
27 type CssRules = 'root' | 'cardheader' | 'fadeout' | 'nameContainer' | 'activeIndicator' | 'cardcontent' | 'attributesection' | 'attribute' | 'chipsection' | 'tag';
29 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
39 WebkitMaskImage: '-webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)))',
45 margin: '0.3rem auto auto 1rem',
52 flexDirection: 'column',
60 marginBottom: '0.5rem',
62 border: '1px solid lightgrey',
76 const mapStateToProps = (state: RootState) => {
77 const currentRoute = state.router.location?.pathname.split('/') || [];
78 const currentItemUuid = currentRoute[currentRoute.length - 1];
79 const currentResource = getResource(currentItemUuid)(state.resources);
85 type DetailsCardProps = {
86 currentResource: ProjectResource | UserResource;
89 export const ProjectDetailsCard = connect(mapStateToProps)(
90 withStyles(styles)((props: DetailsCardProps & WithStyles<CssRules>) => {
91 const { currentResource } = props;
92 return (currentResource.kind as string) === ResourceKind.USER ? <UserCard props={props} /> : <ProjectCard props={props} />;
96 const UserCard = ({ props }) => {
97 const { classes, currentResource } = props;
98 const { fullName, uuid, username, email, isAdmin } = currentResource as UserResource & { fullName: string };
101 <Card className={classes.root}>
103 className={classes.cardheader}
105 <section className={classes.nameContainer}>
113 className={classes.activeIndicator}
115 <UserResourceAccountStatus uuid={uuid} />
120 <MultiselectToolbar inputSelectedUuid={uuid} />
123 <CardContent className={classes.cardcontent}>
124 <section className={classes.attributesection}>
127 className={classes.attribute}
136 className={classes.attribute}
145 className={classes.attribute}
149 value={isAdmin ? 'Yes' : 'No'}
154 className={classes.attribute}
158 linkToUuid={currentResource.uuid}
159 value={currentResource.uuid}
168 const ProjectCard = ({ props }) => {
169 const { classes, currentResource } = props;
170 const { name, uuid, description } = currentResource as ProjectResource;
172 <Card className={classes.root}>
174 className={classes.cardheader}
186 <Typography className={classes.fadeout}>{description.replace(/<[^>]*>/g, '')}</Typography>
188 title={`Description of ${name}`}
189 content={description}
190 label='Show full description'
194 'no description available'
197 action={<MultiselectToolbar inputSelectedUuid={uuid} />}
200 <CardContent className={classes.cardcontent}>
201 <section className={classes.attributesection}>
204 className={classes.attribute}
208 value={currentResource.groupClass === GroupClass.FILTER ? 'Filter group' : resourceLabel(ResourceKind.PROJECT)}
213 className={classes.attribute}
217 linkToUuid={currentResource.ownerUuid}
218 uuidEnhancer={(uuid: string) => <ResourceWithName uuid={uuid} />}
223 className={classes.attribute}
226 label='Last modified'
227 value={formatDate(currentResource.modifiedAt)}
232 className={classes.attribute}
236 value={formatDate(currentResource.createdAt)}
241 className={classes.attribute}
245 linkToUuid={currentResource.uuid}
246 value={currentResource.uuid}
250 <section className={classes.chipsection}>
251 <Typography component='div'>
252 {typeof currentResource.properties === 'object' &&
253 Object.keys(currentResource.properties).map((k) =>
254 Array.isArray(currentResource.properties[k])
255 ? currentResource.properties[k].map((v: string) => getPropertyChip(k, v, undefined, classes.tag))
256 : getPropertyChip(k, currentResource.properties[k], undefined, classes.tag)