1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as React from 'react';
6 import { connect, DispatchProp } from 'react-redux';
7 import Typography from '@material-ui/core/Typography';
8 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
9 import { Tooltip } from '@material-ui/core';
10 import { CopyIcon } from '~/components/icon/icon';
11 import * as CopyToClipboard from 'react-copy-to-clipboard';
12 import { ArvadosTheme } from '~/common/custom-theme';
13 import * as classnames from "classnames";
14 import { Link } from 'react-router-dom';
15 import { RootState } from "~/store/store";
16 import { FederationConfig, getNavUrl } from "~/routes/routes";
17 import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
19 type CssRules = 'attribute' | 'label' | 'value' | 'lowercaseValue' | 'link' | 'copyIcon';
21 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
24 alignItems: 'flex-start',
25 marginBottom: theme.spacing.unit
28 boxSizing: 'border-box',
29 color: theme.palette.grey["500"],
33 boxSizing: 'border-box',
35 alignItems: 'flex-start'
38 textTransform: 'lowercase'
42 color: theme.palette.primary.main,
43 textDecoration: 'none',
44 overflowWrap: 'break-word',
48 marginLeft: theme.spacing.unit,
50 color: theme.palette.grey["500"],
55 interface DetailsAttributeDataProps {
58 value?: React.ReactNode;
60 lowercaseValue?: boolean;
62 children?: React.ReactNode;
63 onValueClick?: () => void;
67 type DetailsAttributeProps = DetailsAttributeDataProps & WithStyles<CssRules> & FederationConfig & DispatchProp;
69 const mapStateToProps = ({ auth }: RootState): FederationConfig => ({
70 localCluster: auth.localCluster,
71 remoteHostsConfig: auth.remoteHostsConfig,
72 sessions: auth.sessions
75 export const DetailsAttribute = connect(mapStateToProps)(withStyles(styles)(
76 class extends React.Component<DetailsAttributeProps> {
78 onCopy = (message: string) => {
79 this.props.dispatch(snackbarActions.OPEN_SNACKBAR({
82 kind: SnackbarKind.SUCCESS
87 const { label, link, value, children, classes, classLabel,
88 classValue, lowercaseValue, onValueClick, linkToUuid,
89 localCluster, remoteHostsConfig, sessions } = this.props;
90 let valueNode: React.ReactNode;
93 const linkUrl = getNavUrl(linkToUuid || "", { localCluster, remoteHostsConfig, sessions });
94 if (linkUrl[0] === '/') {
95 valueNode = <Link to={linkUrl} className={classes.link}>{linkToUuid}</Link>;
97 valueNode = <a href={linkUrl} className={classes.link} target='_blank'>{linkToUuid}</a>;
100 valueNode = <a href={link} className={classes.link} target='_blank'>{value}</a>;
104 return <Typography component="div" className={classes.attribute}>
105 <Typography component="span" className={classnames([classes.label, classLabel])}>{label}</Typography>
107 onClick={onValueClick}
109 className={classnames([classes.value, classValue, { [classes.lowercaseValue]: lowercaseValue }])}>
112 {linkToUuid && <Tooltip title="Copy">
113 <CopyToClipboard text={linkToUuid || ""} onCopy={() => this.onCopy("Copied")}>
114 <CopyIcon className={classes.copyIcon} />