From 27d2ca4c2691cad55993f25a4427d48e86ec6166 Mon Sep 17 00:00:00 2001 From: Peter Amstutz Date: Mon, 4 Jan 2021 15:56:03 -0500 Subject: [PATCH] 16622: Dialog with connection details for WebDAV and S3 Uses tabs to reduce visual clutter Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- .../details-attribute/details-attribute.tsx | 7 +- .../collections/collection-info-actions.ts | 39 +++++ .../action-sets/collection-action-set.ts | 10 +- .../webdav-s3-dialog/webdav-s3-dialog.tsx | 162 ++++++++++++++++++ src/views/workbench/workbench.tsx | 10 +- 5 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 src/store/collections/collection-info-actions.ts create mode 100644 src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx diff --git a/src/components/details-attribute/details-attribute.tsx b/src/components/details-attribute/details-attribute.tsx index 4b8ee837..01276c57 100644 --- a/src/components/details-attribute/details-attribute.tsx +++ b/src/components/details-attribute/details-attribute.tsx @@ -61,6 +61,7 @@ interface DetailsAttributeDataProps { children?: React.ReactNode; onValueClick?: () => void; linkToUuid?: string; + copyValue?: string; } type DetailsAttributeProps = DetailsAttributeDataProps & WithStyles & FederationConfig & DispatchProp; @@ -85,7 +86,7 @@ export const DetailsAttribute = connect(mapStateToProps)(withStyles(styles)( render() { const { label, link, value, children, classes, classLabel, classValue, lowercaseValue, onValueClick, linkToUuid, - localCluster, remoteHostsConfig, sessions } = this.props; + localCluster, remoteHostsConfig, sessions, copyValue } = this.props; let valueNode: React.ReactNode; if (linkToUuid) { @@ -108,9 +109,9 @@ export const DetailsAttribute = connect(mapStateToProps)(withStyles(styles)( className={classnames([classes.value, classValue, { [classes.lowercaseValue]: lowercaseValue }])}> {valueNode} {children} - {linkToUuid && + {(linkToUuid || copyValue) && - this.onCopy("Copied")}> + this.onCopy("Copied")}> diff --git a/src/store/collections/collection-info-actions.ts b/src/store/collections/collection-info-actions.ts new file mode 100644 index 00000000..1509206d --- /dev/null +++ b/src/store/collections/collection-info-actions.ts @@ -0,0 +1,39 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { Dispatch } from "redux"; +import { RootState } from "~/store/store"; +import { ServiceRepository } from "~/services/services"; +import { dialogActions } from '~/store/dialog/dialog-actions'; + +export const COLLECTION_WEBDAV_S3_DIALOG_NAME = 'collectionWebdavS3Dialog'; + +export interface WebDavS3InfoDialogData { + uuid: string; + token: string; + downloadUrl: string; + homeCluster: string; + localCluster: string; + username: string; + activeTab: number; + setActiveTab: (event: any, tabNr: number) => void; +} + +export const openWebDavS3InfoDialog = (uuid: string, activeTab?: number) => + (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { + dispatch(dialogActions.OPEN_DIALOG({ + id: COLLECTION_WEBDAV_S3_DIALOG_NAME, + data: { + title: 'Access Collection using WebDAV or S3', + token: getState().auth.apiToken, + downloadUrl: getState().auth.config.keepWebInlineServiceUrl, + homeCluster: getState().auth.homeCluster, + localCluster: getState().auth.localCluster, + username: getState().auth.user!.username, + activeTab: activeTab || 0, + setActiveTab: (event: any, tabNr: number) => dispatch(openWebDavS3InfoDialog(uuid, tabNr)), + uuid + } + })); + }; diff --git a/src/views-components/context-menu/action-sets/collection-action-set.ts b/src/views-components/context-menu/action-sets/collection-action-set.ts index 4a6c910b..170e7e9a 100644 --- a/src/views-components/context-menu/action-sets/collection-action-set.ts +++ b/src/views-components/context-menu/action-sets/collection-action-set.ts @@ -23,6 +23,7 @@ import { openCollectionUpdateDialog } from "~/store/collections/collection-updat import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action"; import { openMoveCollectionDialog } from '~/store/collections/collection-move-actions'; import { openCollectionCopyDialog } from "~/store/collections/collection-copy-actions"; +import { openWebDavS3InfoDialog } from "~/store/collections/collection-info-actions"; import { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action"; import { toggleCollectionTrashed } from "~/store/trash/trash-actions"; import { openSharingDialog } from '~/store/sharing-dialog/sharing-dialog-actions'; @@ -86,6 +87,13 @@ const commonActionSet: ContextMenuActionSet = [[ export const readOnlyCollectionActionSet: ContextMenuActionSet = [[ ...commonActionSet.reduce((prev, next) => prev.concat(next), []), toggleFavoriteAction, + { + icon: AdvancedIcon, + name: "Connecting with WebDav or S3", + execute: (dispatch, resource) => { + dispatch(openWebDavS3InfoDialog(resource.uuid)); + } + }, ]]; export const collectionActionSet: ContextMenuActionSet = [ @@ -146,4 +154,4 @@ export const oldCollectionVersionActionSet: ContextMenuActionSet = [ } }, ] -]; \ No newline at end of file +]; diff --git a/src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx b/src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx new file mode 100644 index 00000000..2c92e28d --- /dev/null +++ b/src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx @@ -0,0 +1,162 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import * as React from "react"; +import { Dialog, DialogActions, Button, StyleRulesCallback, WithStyles, withStyles, CardHeader, Tab, Tabs } from '@material-ui/core'; +import { withDialog } from "~/store/dialog/with-dialog"; +import { COLLECTION_WEBDAV_S3_DIALOG_NAME, WebDavS3InfoDialogData } from '~/store/collections/collection-info-actions'; +import { WithDialogProps } from '~/store/dialog/with-dialog'; +import { compose } from 'redux'; +import { DetailsAttribute } from "~/components/details-attribute/details-attribute"; + +type CssRules = 'details'; + +const styles: StyleRulesCallback = theme => ({ + details: { + marginLeft: theme.spacing.unit * 3, + marginRight: theme.spacing.unit * 3, + } +}); + +interface TabPanelData { + children: React.ReactElement[]; + value: number; + index: number; +} + +function TabPanel(props: TabPanelData) { + const { children, value, index } = props; + + return ( + + ); +} + +export const WebDavS3InfoDialog = compose( + withDialog(COLLECTION_WEBDAV_S3_DIALOG_NAME), + withStyles(styles), +)( + (props: WithDialogProps & WithStyles) => { + if (!props.data.downloadUrl) { return null; } + + const keepwebUrl = props.data.downloadUrl.replace(/\/\*(--[^.]+)?\./, "/"); + + const winDav = new URL(props.data.downloadUrl.replace("*", props.data.uuid)); + + const gnomeDav = new URL(keepwebUrl); + gnomeDav.username = props.data.username; + gnomeDav.pathname = `/c=${props.data.uuid}/`; + gnomeDav.protocol = "davs:"; + + const s3endpoint = new URL(keepwebUrl); + + const sp = props.data.token.split("/"); + let tokenUuid; + let tokenSecret; + if (sp.length === 3 && sp[0] === "v2" && props.data.homeCluster === props.data.localCluster) { + tokenUuid = sp[1]; + tokenSecret = sp[2]; + } else { + tokenUuid = props.data.token.replace(/\//g, "_"); + tokenSecret = tokenUuid; + } + + return + +
+ + + + + + + +
    +
  1. Open File Explorer
  2. +
  3. Click on "This PC", then go to Computer → Add a Network Location
  4. +
  5. Click Next, then choose "Add a custom network location", then click Next
  6. +
+ + + + + + +
+ + +
    +
  1. Open Files
  2. +
  3. Select +Other Locations
  4. +
  5. Connect to Server → Enter server address
  6. +
+ + + + +
+ + + + + + + + + + + + +
+ + + + +
; + } +); diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx index 9f4a5cb5..f5cfda89 100644 --- a/src/views/workbench/workbench.tsx +++ b/src/views/workbench/workbench.tsx @@ -100,6 +100,7 @@ import { AllProcessesPanel } from '../all-processes-panel/all-processes-panel'; import { NotFoundPanel } from '../not-found-panel/not-found-panel'; import { AutoLogout } from '~/views-components/auto-logout/auto-logout'; import { RestoreCollectionVersionDialog } from '~/views-components/collections-dialog/restore-version-dialog'; +import { WebDavS3InfoDialog } from '~/views-components/webdav-s3-dialog/webdav-s3-dialog'; type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content'; @@ -151,18 +152,18 @@ const saveSplitterSize = (size: number) => localStorage.setItem('splitterSize', export const WorkbenchPanel = withStyles(styles)((props: WorkbenchPanelProps) => - { props.sessionIdleTimeout > 0 && } + {props.sessionIdleTimeout > 0 && } - { props.isUserActive && props.isNotLinking && + {props.isUserActive && props.isNotLinking && - } + } - { props.isNotLinking && } + {props.isNotLinking && } @@ -262,5 +263,6 @@ export const WorkbenchPanel = + ); -- 2.30.2