Merge branch '21121-cluster-activity' refs #21121
[arvados.git] / services / workbench2 / src / views-components / sharing-dialog / sharing-urls-component.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 { CustomStyleRulesCallback } from 'common/custom-theme';
7 import { Grid, IconButton, Link, Tooltip, Typography } from '@mui/material';
8 import { WithStyles } from '@mui/styles';
9 import withStyles from '@mui/styles/withStyles';
10 import { ApiClientAuthorization } from 'models/api-client-authorization';
11 import { CopyIcon, CloseIcon } from 'components/icon/icon';
12 import CopyToClipboard from 'react-copy-to-clipboard';
13 import { ArvadosTheme } from 'common/custom-theme';
14 import moment from 'moment';
15
16 type CssRules = 'sharingUrlText'
17     | 'sharingUrlButton'
18     | 'sharingUrlList'
19     | 'sharingUrlRow';
20
21 const styles: CustomStyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
22     sharingUrlText: {
23         fontSize: '1rem',
24     },
25     sharingUrlButton: {
26         color: theme.palette.grey["500"],
27         cursor: 'pointer',
28         '& svg': {
29             fontSize: '1rem'
30         },
31         verticalAlign: 'middle',
32     },
33     sharingUrlList: {
34         marginTop: '-0.5rem',
35     },
36     sharingUrlRow: {
37         marginLeft: theme.spacing(1),
38         borderBottom: `1px solid ${theme.palette.grey["300"]}`,
39     },
40 });
41
42 export interface SharingURLsComponentDataProps {
43     collectionUuid: string;
44     sharingTokens: ApiClientAuthorization[];
45     sharingURLsPrefix: string;
46 }
47
48 export interface SharingURLsComponentActionProps {
49     onDeleteSharingToken: (uuid: string) => void;
50     onCopy: (message: string) => void;
51 }
52
53 export type SharingURLsComponentProps = SharingURLsComponentDataProps & SharingURLsComponentActionProps;
54
55 export const SharingURLsComponent = withStyles(styles)((props: SharingURLsComponentProps & WithStyles<CssRules>) => <Grid container direction='column' spacing={3} className={props.classes.sharingUrlList}>
56     {props.sharingTokens.length > 0
57         ? props.sharingTokens
58             .sort((a, b) => (new Date(a.expiresAt).getTime() - new Date(b.expiresAt).getTime()))
59             .map(token => {
60                 const url = props.sharingURLsPrefix.includes('*')
61                     ? `${props.sharingURLsPrefix.replace('*', props.collectionUuid)}/t=${token.apiToken}/_/`
62                     : `${props.sharingURLsPrefix}/c=${props.collectionUuid}/t=${token.apiToken}/_/`;
63                 const expDate = new Date(token.expiresAt);
64                 const urlLabel = !!token.expiresAt
65                     ? `Token ${token.apiToken.slice(0, 8)}... expiring at: ${expDate.toLocaleString()} (${moment(expDate).fromNow()})`
66                     : `Token ${token.apiToken.slice(0, 8)}... with no expiration date`;
67
68                 return (
69                     <Grid container alignItems='center' key={token.uuid} className={props.classes.sharingUrlRow}>
70                         <Grid item>
71                             <Link className={props.classes.sharingUrlText} href={url} target='_blank' rel="noopener">
72                                 {urlLabel}
73                             </Link>
74                         </Grid>
75                         <Grid item xs />
76                         <Grid item>
77                             <Tooltip title='Copy link to clipboard'>
78                                 <span className={props.classes.sharingUrlButton}>
79                                     <CopyToClipboard text={url} onCopy={() => props.onCopy('Sharing URL copied')}>
80                                         <CopyIcon />
81                                     </CopyToClipboard>
82                                 </span>
83                             </Tooltip>
84                             <span data-cy='remove-url-btn' className={props.classes.sharingUrlButton}>
85                                 <Tooltip title='Remove'>
86                                     <IconButton onClick={() => props.onDeleteSharingToken(token.uuid)} size="large">
87                                         <CloseIcon />
88                                     </IconButton>
89                                 </Tooltip>
90                             </span>
91                         </Grid>
92                     </Grid>
93                 );
94             })
95         : <Grid item><Typography>No sharing URLs</Typography></Grid>}
96 </Grid>);