15067: Shows tags labels on project details. Adds copy-on-click feature.
[arvados-workbench2.git] / src / views-components / project-properties-dialog / project-properties-dialog.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from "react";
6 import { Dispatch } from "redux";
7 import { connect } from "react-redux";
8 import { RootState } from '~/store/store';
9 import { withDialog, WithDialogProps } from "~/store/dialog/with-dialog";
10 import { ProjectResource } from '~/models/project';
11 import { PROJECT_PROPERTIES_DIALOG_NAME, deleteProjectProperty } from '~/store/details-panel/details-panel-action';
12 import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Chip, withStyles, StyleRulesCallback, WithStyles } from '@material-ui/core';
13 import { ArvadosTheme } from '~/common/custom-theme';
14 import { ProjectPropertiesForm } from '~/views-components/project-properties-dialog/project-properties-form';
15 import { getResource } from '~/store/resources/resources';
16 import * as CopyToClipboard from 'react-copy-to-clipboard';
17 import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
18 import { getTagValueLabel, getTagKeyLabel, Vocabulary } from '~/models/vocabulary';
19 import { getVocabulary } from "~/store/vocabulary/vocabulary-selectors";
20
21 type CssRules = 'tag';
22
23 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
24     tag: {
25         marginRight: theme.spacing.unit,
26         marginBottom: theme.spacing.unit
27     }
28 });
29
30 interface ProjectPropertiesDialogDataProps {
31     project: ProjectResource;
32     vocabulary: Vocabulary;
33 }
34
35 interface ProjectPropertiesDialogActionProps {
36     handleDelete: (key: string) => void;
37     onCopy: (message: string) => void;
38 }
39
40 const mapStateToProps = ({ detailsPanel, resources, properties }: RootState): ProjectPropertiesDialogDataProps => ({
41     project: getResource(detailsPanel.resourceUuid)(resources) as ProjectResource,
42     vocabulary: getVocabulary(properties),
43 });
44
45 const mapDispatchToProps = (dispatch: Dispatch): ProjectPropertiesDialogActionProps => ({
46     handleDelete: (key: string) => dispatch<any>(deleteProjectProperty(key)),
47     onCopy: (message: string) => dispatch(snackbarActions.OPEN_SNACKBAR({
48                 message,
49                 hideDuration: 2000,
50                 kind: SnackbarKind.SUCCESS
51             }))
52 });
53
54 type ProjectPropertiesDialogProps =  ProjectPropertiesDialogDataProps & ProjectPropertiesDialogActionProps & WithDialogProps<{}> & WithStyles<CssRules>;
55
56 export const ProjectPropertiesDialog = connect(mapStateToProps, mapDispatchToProps)(
57     withStyles(styles)(
58     withDialog(PROJECT_PROPERTIES_DIALOG_NAME)(
59         ({ classes, open, closeDialog, handleDelete, onCopy, project, vocabulary }: ProjectPropertiesDialogProps) =>
60             <Dialog open={open}
61                 onClose={closeDialog}
62                 fullWidth
63                 maxWidth='sm'>
64                 <DialogTitle>Properties</DialogTitle>
65                 <DialogContent>
66                     <ProjectPropertiesForm />
67                     {project && project.properties &&
68                         Object.keys(project.properties).map(k => {
69                             const label = `${getTagKeyLabel(k, vocabulary)}: ${getTagValueLabel(k, project.properties[k], vocabulary)}`;
70                             return (
71                                 <CopyToClipboard key={k} text={label} onCopy={() => onCopy("Copied")}>
72                                     <Chip key={k} className={classes.tag}
73                                         onDelete={() => handleDelete(k)}
74                                         label={label} />
75                                 </CopyToClipboard>
76                             );
77                         })
78                     }
79                 </DialogContent>
80                 <DialogActions>
81                     <Button
82                         variant='text'
83                         color='primary'
84                         onClick={closeDialog}>
85                         Close
86                     </Button>
87                 </DialogActions>
88             </Dialog>
89 )));