19504: Add resource colors to breadcrumbs
[arvados-workbench2.git] / src / components / breadcrumbs / breadcrumbs.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from 'react';
6 import { Button, Grid, StyleRulesCallback, WithStyles, Typography, Tooltip } from '@material-ui/core';
7 import ChevronRightIcon from '@material-ui/icons/ChevronRight';
8 import { withStyles } from '@material-ui/core';
9 import { IllegalNamingWarning } from '../warning/warning';
10 import { IconType, FreezeIcon } from 'components/icon/icon';
11 import grey from '@material-ui/core/colors/grey';
12 import { ResourcesState } from 'store/resources/resources';
13 import classNames from 'classnames';
14 import { ArvadosTheme } from 'common/custom-theme';
15 import { extractUuidKind, ResourceKind } from 'models/resource';
16 import { ClassNameMap } from '@material-ui/core/styles/withStyles';
17
18 export interface Breadcrumb {
19     label: string;
20     icon?: IconType;
21     uuid: string;
22 }
23
24 type CssRules = "item" | "defaultItem" | "processItem" | "collectionItem" | "parentItem" | "currentItem" | "label" | "icon" | "frozenIcon";
25
26 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
27     item: {
28         borderRadius: '16px',
29     },
30     defaultItem: {
31         backgroundColor: theme.customs.colors.grey300,
32         '&:hover': {
33             backgroundColor: theme.customs.colors.grey400,
34         }
35     },
36     processItem: {
37         backgroundColor: theme.customs.colors.lightGreen300,
38         '&:hover': {
39             backgroundColor: theme.customs.colors.lightGreen400,
40         }
41     },
42     collectionItem: {
43         backgroundColor: theme.customs.colors.cyan100,
44         '&:hover': {
45             backgroundColor: theme.customs.colors.cyan200,
46         }
47     },
48     parentItem: {
49         opacity: 0.75
50     },
51     currentItem: {
52         opacity: 1
53     },
54     label: {
55         textTransform: "none"
56     },
57     icon: {
58         fontSize: 20,
59         color: grey["600"],
60         marginRight: '10px',
61     },
62     frozenIcon: {
63         fontSize: 20,
64         color: grey["600"],
65         marginLeft: '10px',
66     },
67 });
68
69 export interface BreadcrumbsProps {
70     items: Breadcrumb[];
71     resources: ResourcesState;
72     onClick: (breadcrumb: Breadcrumb) => void;
73     onContextMenu: (event: React.MouseEvent<HTMLElement>, breadcrumb: Breadcrumb) => void;
74 }
75
76 const getBreadcrumbClass = (item: Breadcrumb, classes: ClassNameMap<CssRules>): string => {
77     switch (extractUuidKind(item.uuid)) {
78         case ResourceKind.PROCESS:
79             return classes.processItem;
80         case ResourceKind.COLLECTION:
81             return classes.collectionItem;
82         default:
83             return classes.defaultItem;
84     }
85 };
86
87 export const Breadcrumbs = withStyles(styles)(
88     ({ classes, onClick, onContextMenu, items, resources }: BreadcrumbsProps & WithStyles<CssRules>) =>
89     <Grid container data-cy='breadcrumbs' alignItems="center" wrap="nowrap">
90     {
91         items.map((item, index) => {
92             const isLastItem = index === items.length - 1;
93             const isFirstItem = index === 0;
94             const Icon = item.icon || (() => (null));
95             return (
96                 <React.Fragment key={index}>
97                     {isFirstItem ? null : <IllegalNamingWarning name={item.label} />}
98                     <Tooltip title={item.label}>
99                         <Button
100                             data-cy={
101                                 isFirstItem
102                                 ? 'breadcrumb-first'
103                                 : isLastItem
104                                     ? 'breadcrumb-last'
105                                     : false}
106                             className={classNames(
107                                 isLastItem ? classes.currentItem : classes.parentItem,
108                                 classes.item,
109                                 getBreadcrumbClass(item, classes)
110                             )}
111                             onClick={() => onClick(item)}
112                             onContextMenu={event => onContextMenu(event, item)}>
113                             <Icon className={classes.icon} />
114                             <Typography
115                                 noWrap
116                                 color="inherit"
117                                 className={classes.label}>
118                                 {item.label}
119                             </Typography>
120                             {
121                                 (resources[item.uuid] as any)?.frozenByUuid ? <FreezeIcon className={classes.frozenIcon} /> : null
122                             }
123                         </Button>
124                     </Tooltip>
125                     {!isLastItem && <ChevronRightIcon color="inherit" className={classes.parentItem} />}
126                 </React.Fragment>
127             );
128         })
129     }
130     </Grid>
131 );