From da4bec7681a503f4a0dbb258cdef5be9e6762299 Mon Sep 17 00:00:00 2001 From: Peter Amstutz Date: Mon, 20 May 2019 14:04:48 -0400 Subject: [PATCH] 15230: Refactor copy to clipboard, applies to all DetailsAttribute All fields using linkToUuid now have a "copy to clipboard" button. Process owner uuid is linked. Tweaked styling of details panel to use of space better. Cleaned up some debug logging. Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- .../details-attribute/details-attribute.tsx | 81 ++++++++++++------- src/models/resource.ts | 1 - src/routes/routes.ts | 1 - src/store/navigation/navigation-action.ts | 2 - .../details-panel/details-panel.tsx | 2 +- .../details-panel/process-details.tsx | 2 +- .../collection-panel/collection-panel.tsx | 38 ++------- 7 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/components/details-attribute/details-attribute.tsx b/src/components/details-attribute/details-attribute.tsx index aa177882..8f470858 100644 --- a/src/components/details-attribute/details-attribute.tsx +++ b/src/components/details-attribute/details-attribute.tsx @@ -3,16 +3,20 @@ // SPDX-License-Identifier: AGPL-3.0 import * as React from 'react'; -import { connect } from 'react-redux'; +import { connect, DispatchProp } from 'react-redux'; import Typography from '@material-ui/core/Typography'; import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles'; +import { Tooltip } from '@material-ui/core'; +import { CopyIcon } from '~/components/icon/icon'; +import * as CopyToClipboard from 'react-copy-to-clipboard'; import { ArvadosTheme } from '~/common/custom-theme'; import * as classnames from "classnames"; import { Link } from 'react-router-dom'; import { RootState } from "~/store/store"; import { FederationConfig, getNavUrl } from "~/routes/routes"; +import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions'; -type CssRules = 'attribute' | 'label' | 'value' | 'lowercaseValue' | 'link'; +type CssRules = 'attribute' | 'label' | 'value' | 'lowercaseValue' | 'link' | 'copyIcon'; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ attribute: { @@ -28,7 +32,6 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ value: { boxSizing: 'border-box', width: '60%', - display: 'flex', alignItems: 'flex-start' }, lowercaseValue: { @@ -40,6 +43,12 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ textDecoration: 'none', overflowWrap: 'break-word', cursor: 'pointer' + }, + copyIcon: { + marginLeft: theme.spacing.unit, + fontSize: '1.125rem', + color: theme.palette.grey["500"], + cursor: 'pointer' } }); @@ -55,7 +64,7 @@ interface DetailsAttributeDataProps { linkToUuid?: string; } -type DetailsAttributeProps = DetailsAttributeDataProps & WithStyles & FederationConfig; +type DetailsAttributeProps = DetailsAttributeDataProps & WithStyles & FederationConfig & DispatchProp; const mapStateToProps = ({ auth }: RootState): FederationConfig => ({ localCluster: auth.localCluster, @@ -64,31 +73,49 @@ const mapStateToProps = ({ auth }: RootState): FederationConfig => ({ }); export const DetailsAttribute = connect(mapStateToProps)(withStyles(styles)( - ({ label, link, value, children, classes, classLabel, - classValue, lowercaseValue, onValueClick, linkToUuid, - localCluster, remoteHostsConfig, sessions }: DetailsAttributeProps) => { - let insertLink: React.ReactNode; - if (linkToUuid) { - const linkUrl = getNavUrl(linkToUuid || "", { localCluster, remoteHostsConfig, sessions }); - if (linkUrl[0] === '/') { - insertLink = {value}; + class extends React.Component { + + onCopy = (message: string) => { + this.props.dispatch(snackbarActions.OPEN_SNACKBAR({ + message, + hideDuration: 2000, + kind: SnackbarKind.SUCCESS + })); + } + + render() { + const { label, link, value, children, classes, classLabel, + classValue, lowercaseValue, onValueClick, linkToUuid, + localCluster, remoteHostsConfig, sessions } = this.props; + let valueNode: React.ReactNode; + + if (linkToUuid) { + const linkUrl = getNavUrl(linkToUuid || "", { localCluster, remoteHostsConfig, sessions }); + if (linkUrl[0] === '/') { + valueNode = {linkToUuid}; + } else { + valueNode = {linkToUuid}; + } + } else if (link) { + valueNode = {value}; } else { - insertLink = {value}; + valueNode = value; } - } else if (link) { - insertLink = {value}; + return + {label} + + {valueNode} + {children} + {linkToUuid && + this.onCopy("Copied")}> + + + } + + ; } - return - {label} - {insertLink} - {!insertLink && - {value} - {children} - - } - ; } )); diff --git a/src/models/resource.ts b/src/models/resource.ts index 2af51ecb..239a67cc 100644 --- a/src/models/resource.ts +++ b/src/models/resource.ts @@ -104,7 +104,6 @@ export const extractUuidKind = (uuid: string = '') => { return ResourceKind.LINK; default: const match = COLLECTION_PDH_REGEX.exec(uuid); - console.log("matching " + match); return match ? ResourceKind.COLLECTION : undefined; } }; diff --git a/src/routes/routes.ts b/src/routes/routes.ts index ae418b80..37c7a816 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -49,7 +49,6 @@ export const Routes = { export const getResourceUrl = (uuid: string) => { const kind = extractUuidKind(uuid); - console.log(`for ${uuid} the kind is ${kind}`); switch (kind) { case ResourceKind.PROJECT: return getProjectUrl(uuid); diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts index b5d769e7..f7eeae57 100644 --- a/src/store/navigation/navigation-action.ts +++ b/src/store/navigation/navigation-action.ts @@ -48,7 +48,6 @@ export const navigateToWorkflows = push(Routes.WORKFLOWS); export const pushOrGoto = (url: string): AnyAction => { if (url === "") { - console.log("url should not be empty"); return { type: "noop" }; } else if (url[0] === '/') { return push(url); @@ -63,7 +62,6 @@ export const navigateToProcessLogs = compose(push, getProcessLogUrl); export const navigateToRootProject = (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const rootProjectUuid = services.authService.getUuid(); - console.log("rootProjectUuid " + rootProjectUuid); if (rootProjectUuid) { dispatch(navigateTo(rootProjectUuid)); } diff --git a/src/views-components/details-panel/details-panel.tsx b/src/views-components/details-panel/details-panel.tsx index 9ce84867..f4aaa843 100644 --- a/src/views-components/details-panel/details-panel.tsx +++ b/src/views-components/details-panel/details-panel.tsx @@ -56,7 +56,7 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ }, tabContainer: { overflow: 'auto', - padding: theme.spacing.unit * 3, + padding: theme.spacing.unit * 1, }, }); diff --git a/src/views-components/details-panel/process-details.tsx b/src/views-components/details-panel/process-details.tsx index b6fdaa6f..2fbdd313 100644 --- a/src/views-components/details-panel/process-details.tsx +++ b/src/views-components/details-panel/process-details.tsx @@ -21,7 +21,7 @@ export class ProcessDetails extends DetailsData { return
- + {/* Missing attr */} diff --git a/src/views/collection-panel/collection-panel.tsx b/src/views/collection-panel/collection-panel.tsx index f1e93783..5d799f0b 100644 --- a/src/views/collection-panel/collection-panel.tsx +++ b/src/views/collection-panel/collection-panel.tsx @@ -15,7 +15,6 @@ import { MoreOptionsIcon, CollectionIcon, CopyIcon } from '~/components/icon/ico import { DetailsAttribute } from '~/components/details-attribute/details-attribute'; import { CollectionResource } from '~/models/collection'; import { CollectionPanelFiles } from '~/views-components/collection-panel-files/collection-panel-files'; -import * as CopyToClipboard from 'react-copy-to-clipboard'; import { CollectionTagForm } from './collection-tag-form'; import { deleteCollectionTag, navigateToProcess } from '~/store/collection-panel/collection-panel-action'; import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions'; @@ -27,7 +26,7 @@ import { getResourceData } from "~/store/resources-data/resources-data"; import { ResourceData } from "~/store/resources-data/resources-data-reducer"; import { openDetailsPanel } from '~/store/details-panel/details-panel-action'; -type CssRules = 'card' | 'iconHeader' | 'tag' | 'copyIcon' | 'label' | 'value' | 'link'; +type CssRules = 'card' | 'iconHeader' | 'tag' | 'label' | 'value' | 'link'; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ card: { @@ -41,12 +40,6 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ marginRight: theme.spacing.unit, marginBottom: theme.spacing.unit }, - copyIcon: { - marginLeft: theme.spacing.unit, - fontSize: '1.125rem', - color: theme.palette.grey["500"], - cursor: 'pointer' - }, label: { fontSize: '0.875rem' }, @@ -105,32 +98,19 @@ export const CollectionPanel = withStyles(styles)( subheaderTypographyProps={this.titleProps} /> - + - - this.onCopy("UUID has been copied")}> - - - - + linkToUuid={item && item.uuid} /> - - this.onCopy("PDH has been copied")}> - - - - + linkToUuid={item && item.portableDataHash} /> + label='Owner' linkToUuid={item && item.ownerUuid} /> {(item.properties.container_request || item.properties.containerRequest) && dispatch(navigateToProcess(item.properties.container_request || item.properties.containerRequest))}> @@ -186,14 +166,6 @@ export const CollectionPanel = withStyles(styles)( this.props.dispatch(deleteCollectionTag(key)); } - onCopy = (message: string) => { - this.props.dispatch(snackbarActions.OPEN_SNACKBAR({ - message, - hideDuration: 2000, - kind: SnackbarKind.SUCCESS - })); - } - openCollectionDetails = () => { const { item } = this.props; if (item) { -- 2.30.2