[arvados] updated: 2.7.0-6576-g11c207c691
git repository hosting
git at public.arvados.org
Thu May 16 17:19:58 UTC 2024
Summary of changes:
.../details-card/project-details-card.tsx | 298 +++++++++++++++++++
.../details-card/root-details-card.tsx | 323 +--------------------
2 files changed, 313 insertions(+), 308 deletions(-)
create mode 100644 services/workbench2/src/views-components/details-card/project-details-card.tsx
via 11c207c691729bdc94aa131f332f63969766b20a (commit)
from 8e1c9542efbfddb2cf8cb79bb30937b436e6d3ef (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 11c207c691729bdc94aa131f332f63969766b20a
Author: Lisa Knox <lisaknox83 at gmail.com>
Date: Thu May 16 13:19:51 2024 -0400
21224: moved project card to separate file
Arvados-DCO-1.1-Signed-off-by: Lisa Knox <lisa.knox at curii.com>
diff --git a/services/workbench2/src/views-components/details-card/project-details-card.tsx b/services/workbench2/src/views-components/details-card/project-details-card.tsx
new file mode 100644
index 0000000000..d0aa67a20b
--- /dev/null
+++ b/services/workbench2/src/views-components/details-card/project-details-card.tsx
@@ -0,0 +1,298 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+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';
+import { getResource } from 'store/resources/resources';
+import { getPropertyChip } from '../resource-properties-form/property-chip';
+import { ProjectResource } from 'models/project';
+import { FavoriteStar, PublicFavoriteStar } from 'views-components/favorite-star/favorite-star';
+import { FreezeIcon } from 'components/icon/icon';
+import { Resource } from 'models/resource';
+import { Dispatch } from 'redux';
+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'
+ | 'cardHeaderContainer'
+ | 'cardHeader'
+ | 'descriptionToggle'
+ | 'showMore'
+ | 'noDescription'
+ | 'userNameContainer'
+ | 'cardContent'
+ | 'nameSection'
+ | 'namePlate'
+ | 'faveIcon'
+ | 'frozenIcon'
+ | 'chipToggle'
+ | 'chipSection'
+ | 'tag'
+ | 'description';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ root: {
+ width: '100%',
+ marginBottom: '1rem',
+ flex: '0 0 auto',
+ padding: 0,
+ minHeight: '3rem',
+ },
+ showMore: {
+ cursor: 'pointer',
+ },
+ noDescription: {
+ color: theme.palette.grey['600'],
+ fontStyle: 'italic',
+ marginLeft: '2rem',
+ },
+ userNameContainer: {
+ display: 'flex',
+ alignItems: 'center',
+ minHeight: '2.7rem',
+ },
+ cardHeaderContainer: {
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
+ cardHeader: {
+ minWidth: '30rem',
+ padding: '0.2rem 0.4rem 0.2rem 1rem',
+ },
+ descriptionToggle: {
+ display: 'flex',
+ flexDirection: 'row',
+ cursor: 'pointer',
+ paddingBottom: '0.5rem',
+ },
+ cardContent: {
+ display: 'flex',
+ flexDirection: 'column',
+ paddingTop: 0,
+ paddingLeft: '0.1rem',
+ },
+ nameSection: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ namePlate: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ margin: 0,
+ minHeight: '2.7rem',
+ },
+ faveIcon: {
+ fontSize: '0.8rem',
+ margin: 'auto 0 1rem 0.3rem',
+ color: theme.palette.text.primary,
+ },
+ frozenIcon: {
+ fontSize: '0.5rem',
+ marginLeft: '0.3rem',
+ height: '1rem',
+ color: theme.palette.text.primary,
+ },
+ chipToggle: {
+ display: 'flex',
+ alignItems: 'center',
+ height: '2rem',
+ },
+ chipSection: {
+ marginBottom: '-2rem',
+ },
+ tag: {
+ marginRight: '0.75rem',
+ marginBottom: '0.5rem',
+ },
+ description: {
+ maxWidth: '95%',
+ marginTop: 0,
+ },
+});
+
+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 = selectedResourceUuid === properties.currentRouteUuid;
+
+ return {
+ isAdmin: auth.user?.isAdmin,
+ currentResource,
+ frozenByFullName,
+ isSelected,
+ };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ handleCardClick: (uuid: string) => {
+ dispatch<any>(loadDetailsPanel(uuid));
+ dispatch<any>(setSelectedResourceUuid(uuid));
+ dispatch<any>(deselectAllOthers(uuid));
+ },
+});
+
+type ProjectCardProps = WithStyles<CssRules> & {
+ currentResource: ProjectResource;
+ frozenByFullName: string | undefined;
+ isAdmin: boolean;
+ isSelected: boolean;
+ handleCardClick: (resource: any) => void;
+};
+
+export const ProjectCard = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(
+ withStyles(styles)((props: ProjectCardProps) => {
+ const { classes, currentResource, frozenByFullName, handleCardClick, isSelected } = props;
+ const { name, description, uuid } = currentResource as ProjectResource;
+ const [showDescription, setShowDescription] = React.useState(false);
+ const [showProperties, setShowProperties] = React.useState(false);
+
+ const toggleDescription = () => {
+ setShowDescription(!showDescription);
+ };
+
+ const toggleProperties = () => {
+ setShowProperties(!showProperties);
+ };
+
+ const parser = new DOMParser();
+
+ return (
+ <Card
+ className={classes.root}
+ onClick={() => handleCardClick(uuid)}
+ data-cy='project-details-card'
+ >
+ <Grid
+ container
+ wrap='nowrap'
+ className={classes.cardHeaderContainer}
+ >
+ <CardHeader
+ className={classes.cardHeader}
+ title={
+ <section className={classes.nameSection}>
+ <section className={classes.namePlate}>
+ <Typography
+ variant='h6'
+ style={{ marginRight: '1rem' }}
+ >
+ {name}
+ </Typography>
+ <FavoriteStar
+ className={classes.faveIcon}
+ resourceUuid={currentResource.uuid}
+ />
+ <PublicFavoriteStar
+ className={classes.faveIcon}
+ resourceUuid={currentResource.uuid}
+ />
+ {!!frozenByFullName && (
+ <Tooltip
+ className={classes.frozenIcon}
+ disableFocusListener
+ title={<span>Project was frozen by {frozenByFullName}</span>}
+ >
+ <FreezeIcon style={{ fontSize: 'inherit' }} />
+ </Tooltip>
+ )}
+ </section>
+ {!description && (
+ <Typography
+ data-cy='no-description'
+ className={classes.noDescription}
+ >
+ no description available
+ </Typography>
+ )}
+ </section>
+ }
+ />
+ {isSelected && <MultiselectToolbar />}
+ </Grid>
+ <section onClick={(ev) => ev.stopPropagation()}>
+ {description ? (
+ <section
+ onClick={toggleDescription}
+ className={classes.descriptionToggle}
+ data-cy='toggle-description'
+ >
+ <ExpandChevronRight expanded={showDescription} />
+ <section className={classes.showMore}>
+ <Collapse
+ in={showDescription}
+ timeout='auto'
+ collapsedHeight='1.25rem'
+ >
+ <Typography
+ className={classes.description}
+ data-cy='project-description'
+ //dangerouslySetInnerHTML is ok here only if description is sanitized,
+ //which it is before it is loaded into the redux store
+ dangerouslySetInnerHTML={{ __html: parser.parseFromString(description, 'text/html').body.textContent || '' }}
+ />
+ </Collapse>
+ </section>
+ </section>
+ ) : (
+ <></>
+ )}
+ {typeof currentResource.properties === 'object' && Object.keys(currentResource.properties).length > 0 ? (
+ <section
+ onClick={toggleProperties}
+ className={classes.descriptionToggle}
+ >
+ <div
+ className={classes.chipToggle}
+ data-cy='toggle-chips'
+ >
+ <ExpandChevronRight expanded={showProperties} />
+ </div>
+ <section className={classes.showMore}>
+ <Collapse
+ in={showProperties}
+ timeout='auto'
+ collapsedHeight='35px'
+ >
+ <div
+ className={classes.description}
+ data-cy='project-description'
+ >
+ <CardContent className={classes.cardContent}>
+ <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))
+ : getPropertyChip(k, currentResource.properties[k], undefined, classes.tag)
+ )}
+ </Typography>
+ </CardContent>
+ </div>
+ </Collapse>
+ </section>
+ </section>
+ ) : null}
+ </section>
+ </Card>
+ );
+ })
+);
diff --git a/services/workbench2/src/views-components/details-card/root-details-card.tsx b/services/workbench2/src/views-components/details-card/root-details-card.tsx
index 8ee0240baa..8b4ca558b2 100644
--- a/services/workbench2/src/views-components/details-card/root-details-card.tsx
+++ b/services/workbench2/src/views-components/details-card/root-details-card.tsx
@@ -3,330 +3,37 @@
// SPDX-License-Identifier: AGPL-3.0
import React from 'react';
-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';
import { getResource } from 'store/resources/resources';
-import { getPropertyChip } from '../resource-properties-form/property-chip';
import { ProjectResource } from 'models/project';
import { ResourceKind } from 'models/resource';
import { UserResource } from 'models/user';
-import { FavoriteStar, PublicFavoriteStar } from 'views-components/favorite-star/favorite-star';
-import { FreezeIcon } from 'components/icon/icon';
-import { Resource } from 'models/resource';
-import { Dispatch } from 'redux';
-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';
import { UserCard } from './user-details-card';
+import { ProjectCard } from './project-details-card';
-type CssRules =
- | 'root'
- | 'cardHeaderContainer'
- | 'cardHeader'
- | 'projectToolbar'
- | 'descriptionToggle'
- | 'showMore'
- | 'noDescription'
- | 'userNameContainer'
- | 'cardContent'
- | 'nameSection'
- | 'namePlate'
- | 'faveIcon'
- | 'frozenIcon'
- | 'accountStatusSection'
- | 'chipToggle'
- | 'chipSection'
- | 'tag'
- | 'description';
-
-const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
- root: {
- width: '100%',
- marginBottom: '1rem',
- flex: '0 0 auto',
- padding: 0,
- minHeight: '3rem',
- },
- showMore: {
- cursor: 'pointer',
- },
- noDescription: {
- color: theme.palette.grey['600'],
- fontStyle: 'italic',
- marginLeft: '2rem',
- },
- userNameContainer: {
- display: 'flex',
- alignItems: 'center',
- minHeight: '2.7rem',
- },
- cardHeaderContainer: {
- width: '100%',
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between',
- },
- cardHeader: {
- 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',
- cursor: 'pointer',
- paddingBottom: '0.5rem',
- },
- cardContent: {
- display: 'flex',
- flexDirection: 'column',
- paddingTop: 0,
- paddingLeft: '0.1rem',
- },
- nameSection: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- },
- namePlate: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- margin: 0,
- minHeight: '2.7rem',
- },
- faveIcon: {
- fontSize: '0.8rem',
- margin: 'auto 0 1rem 0.3rem',
- color: theme.palette.text.primary,
- },
- frozenIcon: {
- fontSize: '0.5rem',
- marginLeft: '0.3rem',
- height: '1rem',
- color: theme.palette.text.primary,
- },
- accountStatusSection: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- paddingLeft: '1rem',
- },
- chipToggle: {
- display: 'flex',
- alignItems: 'center',
- height: '2rem',
- },
- chipSection: {
- marginBottom: '-2rem',
- },
- tag: {
- marginRight: '0.75rem',
- marginBottom: '0.5rem',
- },
- description: {
- maxWidth: '95%',
- marginTop: 0,
- },
-});
-
-const mapStateToProps = ({ auth, selectedResourceUuid, resources, properties }: RootState) => {
+const mapStateToProps = ({ 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 = selectedResourceUuid === properties.currentRouteUuid;
return {
- isAdmin: auth.user?.isAdmin,
currentResource,
- frozenByFullName,
- isSelected,
};
};
-const mapDispatchToProps = (dispatch: Dispatch) => ({
- handleCardClick: (uuid: string) => {
- dispatch<any>(loadDetailsPanel(uuid));
- dispatch<any>(setSelectedResourceUuid(uuid));
- dispatch<any>(deselectAllOthers(uuid));
- },
-
-});
-
-type DetailsCardProps = WithStyles<CssRules> & {
+type DetailsCardProps = {
currentResource: ProjectResource | UserResource;
- frozenByFullName?: string;
- isAdmin: boolean;
- isSelected: boolean;
- handleCardClick: (resource: any) => void;
-};
-
-type ProjectCardProps = WithStyles<CssRules> & {
- currentResource: ProjectResource;
- frozenByFullName: string | undefined;
- isAdmin: boolean;
- isSelected: boolean;
- handleCardClick: (resource: any) => void;
};
-export const RootDetailsCard = connect(
- mapStateToProps,
- mapDispatchToProps
-)(
- withStyles(styles)((props: DetailsCardProps) => {
- const { classes, currentResource, frozenByFullName, handleCardClick, isAdmin, isSelected } = props;
- if (!currentResource) {
+export const RootDetailsCard = connect(mapStateToProps)(({ currentResource }: DetailsCardProps) => {
+ if (!currentResource) {
+ return null;
+ }
+ switch (currentResource.kind as string) {
+ case ResourceKind.USER:
+ return <UserCard />;
+ case ResourceKind.PROJECT:
+ return <ProjectCard />;
+ default:
return null;
- }
- switch (currentResource.kind as string) {
- case ResourceKind.USER:
- return <UserCard />;
- case ResourceKind.PROJECT:
- return (
- <ProjectCard
- classes={classes}
- currentResource={currentResource as ProjectResource}
- frozenByFullName={frozenByFullName}
- isAdmin={isAdmin}
- isSelected={isSelected}
- handleCardClick={handleCardClick}
- />
- );
- default:
- return null;
- }
- })
-);
-
-const ProjectCard: React.FC<ProjectCardProps> = ({ classes, currentResource, frozenByFullName, handleCardClick, isSelected }) => {
- const { name, description, uuid } = currentResource as ProjectResource;
- const [showDescription, setShowDescription] = React.useState(false);
- const [showProperties, setShowProperties] = React.useState(false);
-
- const toggleDescription = () => {
- setShowDescription(!showDescription);
- };
-
- const toggleProperties = () => {
- setShowProperties(!showProperties);
- };
-
- const parser = new DOMParser();
-
- return (
- <Card
- className={classes.root}
- onClick={() => handleCardClick(uuid)}
- data-cy='project-details-card'
- >
- <Grid
- container
- wrap='nowrap'
- className={classes.cardHeaderContainer}
- >
- <CardHeader
- className={classes.cardHeader}
- title={
- <section className={classes.nameSection}>
- <section className={classes.namePlate}>
- <Typography
- variant='h6'
- style={{ marginRight: '1rem' }}
- >
- {name}
- </Typography>
- <FavoriteStar
- className={classes.faveIcon}
- resourceUuid={currentResource.uuid}
- />
- <PublicFavoriteStar
- className={classes.faveIcon}
- resourceUuid={currentResource.uuid}
- />
- {!!frozenByFullName && (
- <Tooltip
- className={classes.frozenIcon}
- disableFocusListener
- title={<span>Project was frozen by {frozenByFullName}</span>}
- >
- <FreezeIcon style={{ fontSize: 'inherit' }} />
- </Tooltip>
- )}
- </section>
- {!description && <Typography data-cy="no-description" className={classes.noDescription}>no description available</Typography>}
- </section>
- }
- />
- {isSelected && <MultiselectToolbar injectedStyles={classes.projectToolbar} />}
- </Grid>
- <section onClick={(ev) => ev.stopPropagation()}>
- {description ? (
- <section
- onClick={toggleDescription}
- className={classes.descriptionToggle}
- data-cy="toggle-description"
- >
- <ExpandChevronRight expanded={showDescription} />
- <section className={classes.showMore}>
- <Collapse
- in={showDescription}
- timeout='auto'
- collapsedHeight='1.25rem'
- >
- <Typography
- className={classes.description}
- data-cy='project-description'
- //dangerouslySetInnerHTML is ok here only if description is sanitized,
- //which it is before it is loaded into the redux store
- dangerouslySetInnerHTML={{ __html: parser.parseFromString(description, 'text/html').body.textContent || ''}}
- />
- </Collapse>
- </section>
- </section>
- ) : (
- <></>
- )}
- {typeof currentResource.properties === 'object' && Object.keys(currentResource.properties).length > 0 ? (
- <section
- onClick={toggleProperties}
- className={classes.descriptionToggle}
- >
- <div className={classes.chipToggle} data-cy="toggle-chips">
- <ExpandChevronRight expanded={showProperties} />
- </div>
- <section className={classes.showMore}>
- <Collapse
- in={showProperties}
- timeout='auto'
- collapsedHeight='35px'
- >
- <div
- className={classes.description}
- data-cy='project-description'
- >
- <CardContent className={classes.cardContent}>
- <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))
- : getPropertyChip(k, currentResource.properties[k], undefined, classes.tag)
- )}
- </Typography>
- </CardContent>
- </div>
- </Collapse>
- </section>
- </section>
- ) : null}
- </section>
- </Card>
- );
-};
+ }
+});
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list