From f2a05596f3b20477304c849f4575086baa3a1581 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Fri, 25 Oct 2024 13:08:37 -0700 Subject: [PATCH 01/13] feature/toggle-modal --- .../MoveFileManifest.module.css | 23 +++++ .../Modal/MoveFileManifest/index.tsx | 97 +++++++++++++++++++ packages/core/components/Modal/index.tsx | 4 + .../core/hooks/useFileAccessContextMenu.ts | 12 ++- packages/core/state/interaction/actions.ts | 24 +++++ packages/core/state/interaction/reducer.ts | 13 +++ packages/core/state/interaction/selectors.ts | 1 + 7 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css create mode 100644 packages/core/components/Modal/MoveFileManifest/index.tsx diff --git a/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css new file mode 100644 index 00000000..01b3af96 --- /dev/null +++ b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css @@ -0,0 +1,23 @@ +.fileListContainer { + max-height: 200px; + overflow-y: auto; + padding: 8px; + border: 1px solid #ddd; + border-radius: 4px; +} + +.fileList { + list-style-type: none; + margin: 0; + padding: 0; +} + +.fileItem { + margin-bottom: 4px; + white-space: nowrap; +} + + +.confirmButton { + margin-top: 10px; +} diff --git a/packages/core/components/Modal/MoveFileManifest/index.tsx b/packages/core/components/Modal/MoveFileManifest/index.tsx new file mode 100644 index 00000000..63e5d4cc --- /dev/null +++ b/packages/core/components/Modal/MoveFileManifest/index.tsx @@ -0,0 +1,97 @@ +import * as React from "react"; +import { useSelector } from "react-redux"; + +import { ModalProps } from ".."; +import BaseModal from "../BaseModal"; +import { PrimaryButton } from "../../Buttons"; +import { interaction, selection } from "../../../state"; +import FileDetail from "../../../entity/FileDetail"; +import styles from "./MoveFileManifest.module.css"; +import FileSelection from "../../../entity/FileSelection"; + +/** + * Modal overlay for displaying details of selected files for NAS cache operations. + */ +export default function MoveFileManifest({ onDismiss }: ModalProps) { + // const dispatch = useDispatch(); //TODO: add onMove functionality + const fileSelection = useSelector( + selection.selectors.getFileSelection, + FileSelection.selectionsAreEqual + ); + const moveFileTarget = useSelector(interaction.selectors.getMoveFileTarget); + + const [fileDetails, setFileDetails] = React.useState([]); + const [totalSize, setTotalSize] = React.useState(0); + + React.useEffect(() => { + async function fetchDetails() { + const details = await fileSelection.fetchAllDetails(); + setFileDetails(details); + const totalFileSize = details.reduce((acc, file) => acc + (file.size || 0), 0); + setTotalSize(totalFileSize); + } + + fetchDetails(); + }, [fileSelection]); + + const onMove = () => { + console.log( + `Moving ${fileDetails.length} files ${ + moveFileTarget === "ON_TO_NAS" ? "onto" : "off of" + } NAS.` + ); + onDismiss(); + }; + + const body = ( +
+

Selected Files:

+
+
    + {fileDetails.map((file) => ( +
  • + {file.name} - {formatFileSize(file.size || 0)} +
  • + ))} +
+
+

Total Files: {fileDetails.length}

+

Total Size: {formatFileSize(totalSize)}

+
+ ); + + return ( + + } + onDismiss={onDismiss} + title={`Move Files ${moveFileTarget === "ON_TO_NAS" ? "onto" : "off of"} NAS Cache`} + /> + ); +} + +/** + * Formats a file size to a human-readable string. + */ +const formatFileSize = (size: number) => { + if (size < 1024) return `${size} B`; + const units = ["KB", "MB", "GB", "TB"]; + let unitIndex = -1; + let formattedSize = size; + + do { + formattedSize /= 1024; + unitIndex++; + } while (formattedSize >= 1024 && unitIndex < units.length - 1); + + return `${formattedSize.toFixed(2)} ${units[unitIndex]}`; +}; diff --git a/packages/core/components/Modal/index.tsx b/packages/core/components/Modal/index.tsx index e05a4bc6..66f998f5 100644 --- a/packages/core/components/Modal/index.tsx +++ b/packages/core/components/Modal/index.tsx @@ -6,6 +6,7 @@ import CodeSnippet from "./CodeSnippet"; import DataSource from "./DataSource"; import MetadataManifest from "./MetadataManifest"; import SmallScreenWarning from "./SmallScreenWarning"; +import MoveFileManifest from "./MoveFileManifest"; export interface ModalProps { onDismiss: () => void; @@ -16,6 +17,7 @@ export enum ModalType { DataSource = 2, MetadataManifest = 3, SmallScreenWarning = 4, + MoveFileManifest = 5, } /** @@ -38,6 +40,8 @@ export default function Modal() { return ; case ModalType.SmallScreenWarning: return ; + case ModalType.MoveFileManifest: + return ; default: return null; } diff --git a/packages/core/hooks/useFileAccessContextMenu.ts b/packages/core/hooks/useFileAccessContextMenu.ts index 0c79a321..2d32bea0 100644 --- a/packages/core/hooks/useFileAccessContextMenu.ts +++ b/packages/core/hooks/useFileAccessContextMenu.ts @@ -157,13 +157,18 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => { }, subMenuProps: { items: [ + { + key: "move-files-title", + text: "CACHE LOCATION", + title: "Move files to or from the NAS cache", + itemType: ContextualMenuItemType.Header, + }, { key: "off-nas", text: "Off NAS Cache", title: "Move files off the NAS cache", onClick() { - // Placeholder for moving files off NAS Cache - console.log("Move files off NAS Cache"); + dispatch(interaction.actions.showMoveFileManifest("OFF_NAS")); }, }, { @@ -171,8 +176,7 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => { text: "Onto NAS Cache", title: "Move files onto the NAS cache", onClick() { - // Placeholder for moving files onto NAS Cache - console.log("Move files onto NAS Cache"); + dispatch(interaction.actions.showMoveFileManifest("ON_TO_NAS")); }, }, ], diff --git a/packages/core/state/interaction/actions.ts b/packages/core/state/interaction/actions.ts index 441dca1e..46efbe5e 100644 --- a/packages/core/state/interaction/actions.ts +++ b/packages/core/state/interaction/actions.ts @@ -679,3 +679,27 @@ export function setSelectedPublicDataset(dataset: PublicDataset): SetSelectedPub type: SET_SELECTED_PUBLIC_DATASET, }; } + +/** + * SHOW_MOVE_FILE_MANIFEST + * + * Action to show the Move File dialog (manifest) for NAS cache operations. + * This modal will allow users to move files on or off the NAS cache. + */ +export const SHOW_MOVE_FILE_MANIFEST = makeConstant(STATE_BRANCH_NAME, "show-move-file-manifest"); + +export interface ShowMoveFileManifestAction { + type: string; + payload: { + target: "ON_TO_NAS" | "OFF_NAS"; + }; +} + +export function showMoveFileManifest(target: "ON_TO_NAS" | "OFF_NAS"): ShowMoveFileManifestAction { + return { + type: SHOW_MOVE_FILE_MANIFEST, + payload: { + target, + }, + }; +} diff --git a/packages/core/state/interaction/reducer.ts b/packages/core/state/interaction/reducer.ts index 4a8905f7..4a069a9c 100644 --- a/packages/core/state/interaction/reducer.ts +++ b/packages/core/state/interaction/reducer.ts @@ -15,10 +15,12 @@ import { SHOW_CONTEXT_MENU, SHOW_DATASET_DETAILS_PANEL, SHOW_MANIFEST_DOWNLOAD_DIALOG, + SHOW_MOVE_FILE_MANIFEST, StatusUpdate, MARK_AS_USED_APPLICATION_BEFORE, MARK_AS_DISMISSED_SMALL_SCREEN_WARNING, ShowManifestDownloadDialogAction, + ShowMoveFileManifestAction, SET_IS_AICS_EMPLOYEE, PROMPT_FOR_DATA_SOURCE, DownloadManifestAction, @@ -57,6 +59,7 @@ export interface InteractionStateBranch { hasUsedApplicationBefore: boolean; isAicsEmployee?: boolean; isOnWeb: boolean; + moveFileTarget?: "ON_TO_NAS" | "OFF_NAS"; platformDependentServices: PlatformDependentServices; refreshKey?: string; selectedPublicDataset?: PublicDataset; @@ -195,6 +198,16 @@ export default makeReducer( ...state, selectedPublicDataset: action.payload, }), + [SHOW_MOVE_FILE_MANIFEST]: (state, action: ShowMoveFileManifestAction) => ({ + ...state, + visibleModal: ModalType.MoveFileManifest, + moveFileTarget: action.payload.target, + }), + [HIDE_VISIBLE_MODAL]: (state) => ({ + ...state, + visibleModal: undefined, + moveFileTarget: undefined, + }), }, initialState ); diff --git a/packages/core/state/interaction/selectors.ts b/packages/core/state/interaction/selectors.ts index ec880228..bf7096df 100644 --- a/packages/core/state/interaction/selectors.ts +++ b/packages/core/state/interaction/selectors.ts @@ -47,6 +47,7 @@ export const getUserSelectedApplications = (state: State) => state.interaction.userSelectedApplications; export const getVisibleModal = (state: State) => state.interaction.visibleModal; export const isAicsEmployee = (state: State) => state.interaction.isAicsEmployee; +export const getMoveFileTarget = (state: State) => state.interaction.moveFileTarget; // COMPOSED SELECTORS export const getApplicationVersion = createSelector( From f52d31c7091c7f8f43dfd4fd1af3aabe80ec94fe Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 11:11:31 -0700 Subject: [PATCH 02/13] add conditional show move menu item --- .../core/hooks/useFileAccessContextMenu.ts | 82 +++++++++++-------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/packages/core/hooks/useFileAccessContextMenu.ts b/packages/core/hooks/useFileAccessContextMenu.ts index 2d32bea0..b58261d5 100644 --- a/packages/core/hooks/useFileAccessContextMenu.ts +++ b/packages/core/hooks/useFileAccessContextMenu.ts @@ -147,41 +147,53 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => { dispatch(interaction.actions.downloadFiles()); }, }, - { - key: "move-files", - text: "Move Files", - title: "Move files between NAS Cache", - disabled: !filters && fileSelection.count() === 0, - iconProps: { - iconName: "MoveToFolder", - }, - subMenuProps: { - items: [ - { - key: "move-files-title", - text: "CACHE LOCATION", - title: "Move files to or from the NAS cache", - itemType: ContextualMenuItemType.Header, - }, - { - key: "off-nas", - text: "Off NAS Cache", - title: "Move files off the NAS cache", - onClick() { - dispatch(interaction.actions.showMoveFileManifest("OFF_NAS")); - }, - }, - { - key: "onto-nas", - text: "Onto NAS Cache", - title: "Move files onto the NAS cache", - onClick() { - dispatch(interaction.actions.showMoveFileManifest("ON_TO_NAS")); - }, - }, - ], - }, - }, + ...(isQueryingAicsFms + ? [ + { + key: "move-files", + text: "Move Files", + title: "Move files between NAS Cache", + disabled: !filters && fileSelection.count() === 0, + iconProps: { + iconName: "MoveToFolder", + }, + subMenuProps: { + items: [ + { + key: "move-files-title", + text: "CACHE LOCATION", + title: "Move files to or from the NAS cache", + itemType: ContextualMenuItemType.Header, + }, + { + key: "off-nas", + text: "Off NAS Cache", + title: "Move files off the NAS cache", + onClick() { + dispatch( + interaction.actions.showMoveFileManifest( + "OFF_NAS" + ) + ); + }, + }, + { + key: "onto-nas", + text: "Onto NAS Cache", + title: "Move files onto the NAS cache", + onClick() { + dispatch( + interaction.actions.showMoveFileManifest( + "ON_TO_NAS" + ) + ); + }, + }, + ], + }, + }, + ] + : []), ]; dispatch( From 77a52bd92652b8a0f7f0eeb5ed43216f73ff3045 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 11:23:58 -0700 Subject: [PATCH 03/13] modal list to table --- .../MoveFileManifest.module.css | 44 ++++++++++++++----- .../Modal/MoveFileManifest/index.tsx | 25 +++++++---- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css index 01b3af96..4252eb86 100644 --- a/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css +++ b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css @@ -1,23 +1,43 @@ -.fileListContainer { - max-height: 200px; +.fileTableContainer { + max-height: 300px; overflow-y: auto; - padding: 8px; border: 1px solid #ddd; - border-radius: 4px; + margin-bottom: 1em; } -.fileList { - list-style-type: none; - margin: 0; - padding: 0; +.fileTable { + width: 100%; + border-collapse: collapse; } -.fileItem { - margin-bottom: 4px; +.fileTable th, +.fileTable td { + padding: 8px; + text-align: left; + border-bottom: 1px solid #ddd; white-space: nowrap; } +.fileTable th { + background-color: #f2f2f2; + position: sticky; + top: 0; + z-index: 1; +} + +.fileTable td:first-child { + border-right: 1px solid #ddd; +} + +.fileTableContainer::-webkit-scrollbar { + width: 8px; +} + +.fileTableContainer::-webkit-scrollbar-thumb { + background-color: #888; + border-radius: 4px; +} -.confirmButton { - margin-top: 10px; +.fileTableContainer::-webkit-scrollbar-thumb:hover { + background-color: #555; } diff --git a/packages/core/components/Modal/MoveFileManifest/index.tsx b/packages/core/components/Modal/MoveFileManifest/index.tsx index 63e5d4cc..166c1352 100644 --- a/packages/core/components/Modal/MoveFileManifest/index.tsx +++ b/packages/core/components/Modal/MoveFileManifest/index.tsx @@ -46,14 +46,23 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { const body = (

Selected Files:

-
-
    - {fileDetails.map((file) => ( -
  • - {file.name} - {formatFileSize(file.size || 0)} -
  • - ))} -
+
+ + + + + + + + + {fileDetails.map((file) => ( + + + + + ))} + +
File NameFile Size
{file.name}{formatFileSize(file.size || 0)}

Total Files: {fileDetails.length}

Total Size: {formatFileSize(totalSize)}

From 1201a846f67e846b16e1c4adc2b738813713e2f7 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 11:26:02 -0700 Subject: [PATCH 04/13] reorder imports --- packages/core/components/Modal/MoveFileManifest/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/index.tsx b/packages/core/components/Modal/MoveFileManifest/index.tsx index 166c1352..5d59b0a2 100644 --- a/packages/core/components/Modal/MoveFileManifest/index.tsx +++ b/packages/core/components/Modal/MoveFileManifest/index.tsx @@ -4,10 +4,11 @@ import { useSelector } from "react-redux"; import { ModalProps } from ".."; import BaseModal from "../BaseModal"; import { PrimaryButton } from "../../Buttons"; -import { interaction, selection } from "../../../state"; import FileDetail from "../../../entity/FileDetail"; -import styles from "./MoveFileManifest.module.css"; import FileSelection from "../../../entity/FileSelection"; +import { interaction, selection } from "../../../state"; + +import styles from "./MoveFileManifest.module.css"; /** * Modal overlay for displaying details of selected files for NAS cache operations. From ae06c75ecf44f37d7f577e30a61ce146c19f0d27 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 11:41:26 -0700 Subject: [PATCH 05/13] use existing filesize method --- .../Modal/MoveFileManifest/index.tsx | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/index.tsx b/packages/core/components/Modal/MoveFileManifest/index.tsx index 5d59b0a2..1c472957 100644 --- a/packages/core/components/Modal/MoveFileManifest/index.tsx +++ b/packages/core/components/Modal/MoveFileManifest/index.tsx @@ -1,3 +1,4 @@ +import filesize from "filesize"; import * as React from "react"; import { useSelector } from "react-redux"; @@ -15,6 +16,7 @@ import styles from "./MoveFileManifest.module.css"; */ export default function MoveFileManifest({ onDismiss }: ModalProps) { // const dispatch = useDispatch(); //TODO: add onMove functionality + const fileService = useSelector(interaction.selectors.getFileService); const fileSelection = useSelector( selection.selectors.getFileSelection, FileSelection.selectionsAreEqual @@ -22,18 +24,23 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { const moveFileTarget = useSelector(interaction.selectors.getMoveFileTarget); const [fileDetails, setFileDetails] = React.useState([]); - const [totalSize, setTotalSize] = React.useState(0); + const [totalSize, setTotalSize] = React.useState(); + const [isLoading, setLoading] = React.useState(false); React.useEffect(() => { async function fetchDetails() { + setLoading(true); const details = await fileSelection.fetchAllDetails(); setFileDetails(details); - const totalFileSize = details.reduce((acc, file) => acc + (file.size || 0), 0); - setTotalSize(totalFileSize); + + const aggregateInfo = await fileService.getAggregateInformation(fileSelection); + const formattedSize = aggregateInfo.size ? filesize(aggregateInfo.size) : undefined; + setTotalSize(formattedSize); + setLoading(false); } fetchDetails(); - }, [fileSelection]); + }, [fileSelection, fileService]); const onMove = () => { console.log( @@ -59,14 +66,14 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { {fileDetails.map((file) => ( {file.name} - {formatFileSize(file.size || 0)} + {filesize(file.size || 0)} ))}

Total Files: {fileDetails.length}

-

Total Size: {formatFileSize(totalSize)}

+

Total Size: {isLoading ? "Loading..." : totalSize}

); @@ -88,20 +95,3 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { /> ); } - -/** - * Formats a file size to a human-readable string. - */ -const formatFileSize = (size: number) => { - if (size < 1024) return `${size} B`; - const units = ["KB", "MB", "GB", "TB"]; - let unitIndex = -1; - let formattedSize = size; - - do { - formattedSize /= 1024; - unitIndex++; - } while (formattedSize >= 1024 && unitIndex < units.length - 1); - - return `${formattedSize.toFixed(2)} ${units[unitIndex]}`; -}; From e1594389fa5dbe6648cf9d9208c74ad9ea5fbbf3 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 12:10:38 -0700 Subject: [PATCH 06/13] add placeholder action --- .../Modal/MoveFileManifest/index.tsx | 18 ++++++++------- packages/core/state/interaction/actions.ts | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/index.tsx b/packages/core/components/Modal/MoveFileManifest/index.tsx index 1c472957..08b5196a 100644 --- a/packages/core/components/Modal/MoveFileManifest/index.tsx +++ b/packages/core/components/Modal/MoveFileManifest/index.tsx @@ -1,6 +1,6 @@ import filesize from "filesize"; import * as React from "react"; -import { useSelector } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { ModalProps } from ".."; import BaseModal from "../BaseModal"; @@ -15,7 +15,7 @@ import styles from "./MoveFileManifest.module.css"; * Modal overlay for displaying details of selected files for NAS cache operations. */ export default function MoveFileManifest({ onDismiss }: ModalProps) { - // const dispatch = useDispatch(); //TODO: add onMove functionality + const dispatch = useDispatch(); const fileService = useSelector(interaction.selectors.getFileService); const fileSelection = useSelector( selection.selectors.getFileSelection, @@ -43,12 +43,14 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { }, [fileSelection, fileService]); const onMove = () => { - console.log( - `Moving ${fileDetails.length} files ${ - moveFileTarget === "ON_TO_NAS" ? "onto" : "off of" - } NAS.` - ); - onDismiss(); + if (moveFileTarget) { + dispatch(interaction.actions.moveFiles(fileDetails, moveFileTarget)); + onDismiss(); + } else { + console.warn( + "Move file target location is undefined. Cannot proceed with moving files." + ); + } }; const body = ( diff --git a/packages/core/state/interaction/actions.ts b/packages/core/state/interaction/actions.ts index 46efbe5e..5daf3512 100644 --- a/packages/core/state/interaction/actions.ts +++ b/packages/core/state/interaction/actions.ts @@ -703,3 +703,26 @@ export function showMoveFileManifest(target: "ON_TO_NAS" | "OFF_NAS"): ShowMoveF }, }; } + +export const MOVE_FILES = makeConstant(STATE_BRANCH_NAME, "move-files"); + +export interface MoveFilesAction { + type: string; + payload: { + fileDetails: FileDetail[]; + target: string; + }; +} + +export function moveFiles(fileDetails: FileDetail[], target: string): MoveFilesAction { + console.log( + `Moving ${fileDetails.length} files ${target === "ON_TO_NAS" ? "onto" : "off of"} NAS.` + ); + return { + type: MOVE_FILES, + payload: { + fileDetails, + target, + }, + }; +} From 8c810a631d8892a318daba8284aa6585d91952d0 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 12:19:37 -0700 Subject: [PATCH 07/13] add placeholder logic --- packages/core/state/interaction/actions.ts | 3 --- packages/core/state/interaction/logics.ts | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/core/state/interaction/actions.ts b/packages/core/state/interaction/actions.ts index 5daf3512..a2994b1c 100644 --- a/packages/core/state/interaction/actions.ts +++ b/packages/core/state/interaction/actions.ts @@ -715,9 +715,6 @@ export interface MoveFilesAction { } export function moveFiles(fileDetails: FileDetail[], target: string): MoveFilesAction { - console.log( - `Moving ${fileDetails.length} files ${target === "ON_TO_NAS" ? "onto" : "off of"} NAS.` - ); return { type: MOVE_FILES, payload: { diff --git a/packages/core/state/interaction/logics.ts b/packages/core/state/interaction/logics.ts index 9c7eb4eb..4a882aa5 100644 --- a/packages/core/state/interaction/logics.ts +++ b/packages/core/state/interaction/logics.ts @@ -31,6 +31,8 @@ import { SetIsSmallScreenAction, setVisibleModal, hideVisibleModal, + MoveFilesAction, + MOVE_FILES, } from "./actions"; import * as interactionSelectors from "./selectors"; import { DownloadResolution, FileInfo } from "../../services/FileDownloadService"; @@ -575,6 +577,19 @@ const setIsSmallScreen = createLogic({ type: SET_IS_SMALL_SCREEN, }); +/** + * Interceptor responsible for handling the MOVE_FILES action. + * Logs the target location for file movement in the console. + */ +const moveFilesLogic = createLogic({ + type: MOVE_FILES, + process(deps, dispatch, done) { + const action = deps.action as MoveFilesAction; + console.log(`Moving files to location: ${action.payload.target}`); + done(); + }, +}); + export default [ initializeApp, downloadManifest, @@ -586,4 +601,5 @@ export default [ showContextMenu, refresh, setIsSmallScreen, + moveFilesLogic, ]; From 1e3c38bfdd76d177129d05b25cc8fb37bc9aec84 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 12:23:31 -0700 Subject: [PATCH 08/13] remove duplicate reducer --- packages/core/state/interaction/reducer.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/core/state/interaction/reducer.ts b/packages/core/state/interaction/reducer.ts index 4a069a9c..9bbdc83d 100644 --- a/packages/core/state/interaction/reducer.ts +++ b/packages/core/state/interaction/reducer.ts @@ -203,11 +203,6 @@ export default makeReducer( visibleModal: ModalType.MoveFileManifest, moveFileTarget: action.payload.target, }), - [HIDE_VISIBLE_MODAL]: (state) => ({ - ...state, - visibleModal: undefined, - moveFileTarget: undefined, - }), }, initialState ); From 588447da65efe53f1b4eebc5459cc97f4b185646 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 13:48:33 -0700 Subject: [PATCH 09/13] update styling for move modal --- .../MoveFileManifest.module.css | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css index 4252eb86..df5280ae 100644 --- a/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css +++ b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css @@ -1,43 +1,31 @@ -.fileTableContainer { +.file-table-container { max-height: 300px; overflow-y: auto; - border: 1px solid #ddd; - margin-bottom: 1em; + border: 1px solid var(--border-color); + margin-bottom: var(--margin); } -.fileTable { +.file-table { width: 100%; border-collapse: collapse; } -.fileTable th, -.fileTable td { +.file-table th, +.file-table td { padding: 8px; text-align: left; - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--border-color); white-space: nowrap; + color: var(--primary-text-color); } -.fileTable th { - background-color: #f2f2f2; +.file-table th { + background-color: var(--secondary-background-color); position: sticky; top: 0; z-index: 1; } -.fileTable td:first-child { - border-right: 1px solid #ddd; -} - -.fileTableContainer::-webkit-scrollbar { - width: 8px; -} - -.fileTableContainer::-webkit-scrollbar-thumb { - background-color: #888; - border-radius: 4px; -} - -.fileTableContainer::-webkit-scrollbar-thumb:hover { - background-color: #555; +.file-table td:first-child { + border-right: 1px solid var(--border-color); } From 741d4156b5d9b26680909984d437ad9a63bc3480 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Mon, 28 Oct 2024 14:18:54 -0700 Subject: [PATCH 10/13] remove off nas --- packages/core/hooks/useFileAccessContextMenu.ts | 16 +--------------- packages/core/state/interaction/actions.ts | 4 ++-- packages/core/state/interaction/reducer.ts | 2 +- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/core/hooks/useFileAccessContextMenu.ts b/packages/core/hooks/useFileAccessContextMenu.ts index b58261d5..d3917325 100644 --- a/packages/core/hooks/useFileAccessContextMenu.ts +++ b/packages/core/hooks/useFileAccessContextMenu.ts @@ -165,27 +165,13 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => { title: "Move files to or from the NAS cache", itemType: ContextualMenuItemType.Header, }, - { - key: "off-nas", - text: "Off NAS Cache", - title: "Move files off the NAS cache", - onClick() { - dispatch( - interaction.actions.showMoveFileManifest( - "OFF_NAS" - ) - ); - }, - }, { key: "onto-nas", text: "Onto NAS Cache", title: "Move files onto the NAS cache", onClick() { dispatch( - interaction.actions.showMoveFileManifest( - "ON_TO_NAS" - ) + interaction.actions.showMoveFileManifest("NAS") ); }, }, diff --git a/packages/core/state/interaction/actions.ts b/packages/core/state/interaction/actions.ts index a2994b1c..9d840068 100644 --- a/packages/core/state/interaction/actions.ts +++ b/packages/core/state/interaction/actions.ts @@ -691,11 +691,11 @@ export const SHOW_MOVE_FILE_MANIFEST = makeConstant(STATE_BRANCH_NAME, "show-mov export interface ShowMoveFileManifestAction { type: string; payload: { - target: "ON_TO_NAS" | "OFF_NAS"; + target: string; }; } -export function showMoveFileManifest(target: "ON_TO_NAS" | "OFF_NAS"): ShowMoveFileManifestAction { +export function showMoveFileManifest(target: string): ShowMoveFileManifestAction { return { type: SHOW_MOVE_FILE_MANIFEST, payload: { diff --git a/packages/core/state/interaction/reducer.ts b/packages/core/state/interaction/reducer.ts index 9bbdc83d..07655889 100644 --- a/packages/core/state/interaction/reducer.ts +++ b/packages/core/state/interaction/reducer.ts @@ -59,7 +59,7 @@ export interface InteractionStateBranch { hasUsedApplicationBefore: boolean; isAicsEmployee?: boolean; isOnWeb: boolean; - moveFileTarget?: "ON_TO_NAS" | "OFF_NAS"; + moveFileTarget?: string; platformDependentServices: PlatformDependentServices; refreshKey?: string; selectedPublicDataset?: PublicDataset; From 1bc859fc0ecc021de5b18b02a10e656a50a92322 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Tue, 29 Oct 2024 12:08:10 -0700 Subject: [PATCH 11/13] update move only structure --- .../Modal/MoveFileManifest/index.tsx | 2 +- .../core/hooks/useFileAccessContextMenu.ts | 31 ++++--------------- packages/core/state/interaction/actions.ts | 2 +- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/index.tsx b/packages/core/components/Modal/MoveFileManifest/index.tsx index 08b5196a..de9fac41 100644 --- a/packages/core/components/Modal/MoveFileManifest/index.tsx +++ b/packages/core/components/Modal/MoveFileManifest/index.tsx @@ -93,7 +93,7 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { /> } onDismiss={onDismiss} - title={`Move Files ${moveFileTarget === "ON_TO_NAS" ? "onto" : "off of"} NAS Cache`} + title={`Move Files to ${moveFileTarget}`} /> ); } diff --git a/packages/core/hooks/useFileAccessContextMenu.ts b/packages/core/hooks/useFileAccessContextMenu.ts index d3917325..7381316f 100644 --- a/packages/core/hooks/useFileAccessContextMenu.ts +++ b/packages/core/hooks/useFileAccessContextMenu.ts @@ -150,32 +150,13 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => { ...(isQueryingAicsFms ? [ { - key: "move-files", - text: "Move Files", - title: "Move files between NAS Cache", + key: "move-to-cache", + text: "Move to Cache", + title: "Move selected files to NAS Cache", disabled: !filters && fileSelection.count() === 0, - iconProps: { - iconName: "MoveToFolder", - }, - subMenuProps: { - items: [ - { - key: "move-files-title", - text: "CACHE LOCATION", - title: "Move files to or from the NAS cache", - itemType: ContextualMenuItemType.Header, - }, - { - key: "onto-nas", - text: "Onto NAS Cache", - title: "Move files onto the NAS cache", - onClick() { - dispatch( - interaction.actions.showMoveFileManifest("NAS") - ); - }, - }, - ], + iconProps: { iconName: "MoveToFolder" }, + onClick() { + dispatch(interaction.actions.showMoveFileManifest("NAS")); }, }, ] diff --git a/packages/core/state/interaction/actions.ts b/packages/core/state/interaction/actions.ts index 9d840068..7c9d79ca 100644 --- a/packages/core/state/interaction/actions.ts +++ b/packages/core/state/interaction/actions.ts @@ -684,7 +684,7 @@ export function setSelectedPublicDataset(dataset: PublicDataset): SetSelectedPub * SHOW_MOVE_FILE_MANIFEST * * Action to show the Move File dialog (manifest) for NAS cache operations. - * This modal will allow users to move files on or off the NAS cache. + * This modal will allow users to move files onto the NAS cache. */ export const SHOW_MOVE_FILE_MANIFEST = makeConstant(STATE_BRANCH_NAME, "show-move-file-manifest"); From 034549de1962d08622e9c4e1b8ea409741103aa5 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Thu, 31 Oct 2024 15:56:36 -0700 Subject: [PATCH 12/13] remove loc target --- .../Modal/MoveFileManifest/index.tsx | 13 +++------- .../core/hooks/useFileAccessContextMenu.ts | 26 +++++++++---------- packages/core/state/interaction/actions.ts | 12 ++------- packages/core/state/interaction/logics.ts | 4 +-- packages/core/state/interaction/reducer.ts | 5 +--- packages/core/state/interaction/selectors.ts | 1 - 6 files changed, 21 insertions(+), 40 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/index.tsx b/packages/core/components/Modal/MoveFileManifest/index.tsx index de9fac41..41611686 100644 --- a/packages/core/components/Modal/MoveFileManifest/index.tsx +++ b/packages/core/components/Modal/MoveFileManifest/index.tsx @@ -21,7 +21,6 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { selection.selectors.getFileSelection, FileSelection.selectionsAreEqual ); - const moveFileTarget = useSelector(interaction.selectors.getMoveFileTarget); const [fileDetails, setFileDetails] = React.useState([]); const [totalSize, setTotalSize] = React.useState(); @@ -43,14 +42,8 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { }, [fileSelection, fileService]); const onMove = () => { - if (moveFileTarget) { - dispatch(interaction.actions.moveFiles(fileDetails, moveFileTarget)); - onDismiss(); - } else { - console.warn( - "Move file target location is undefined. Cannot proceed with moving files." - ); - } + dispatch(interaction.actions.moveFiles(fileDetails)); + onDismiss(); }; const body = ( @@ -93,7 +86,7 @@ export default function MoveFileManifest({ onDismiss }: ModalProps) { /> } onDismiss={onDismiss} - title={`Move Files to ${moveFileTarget}`} + title="Move Files to NAS Cache" /> ); } diff --git a/packages/core/hooks/useFileAccessContextMenu.ts b/packages/core/hooks/useFileAccessContextMenu.ts index 7381316f..372c25e1 100644 --- a/packages/core/hooks/useFileAccessContextMenu.ts +++ b/packages/core/hooks/useFileAccessContextMenu.ts @@ -135,18 +135,6 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => { ], }, }, - { - key: "download", - text: "Download", - title: "Download selected files to a specific directory", - disabled: !filters && fileSelection.count() === 0, - iconProps: { - iconName: "Download", - }, - onClick() { - dispatch(interaction.actions.downloadFiles()); - }, - }, ...(isQueryingAicsFms ? [ { @@ -156,11 +144,23 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => { disabled: !filters && fileSelection.count() === 0, iconProps: { iconName: "MoveToFolder" }, onClick() { - dispatch(interaction.actions.showMoveFileManifest("NAS")); + dispatch(interaction.actions.showMoveFileManifest()); }, }, ] : []), + { + key: "download", + text: "Download", + title: "Download selected files to a specific directory", + disabled: !filters && fileSelection.count() === 0, + iconProps: { + iconName: "Download", + }, + onClick() { + dispatch(interaction.actions.downloadFiles()); + }, + }, ]; dispatch( diff --git a/packages/core/state/interaction/actions.ts b/packages/core/state/interaction/actions.ts index 7c9d79ca..7f85149c 100644 --- a/packages/core/state/interaction/actions.ts +++ b/packages/core/state/interaction/actions.ts @@ -690,17 +690,11 @@ export const SHOW_MOVE_FILE_MANIFEST = makeConstant(STATE_BRANCH_NAME, "show-mov export interface ShowMoveFileManifestAction { type: string; - payload: { - target: string; - }; } -export function showMoveFileManifest(target: string): ShowMoveFileManifestAction { +export function showMoveFileManifest(): ShowMoveFileManifestAction { return { type: SHOW_MOVE_FILE_MANIFEST, - payload: { - target, - }, }; } @@ -710,16 +704,14 @@ export interface MoveFilesAction { type: string; payload: { fileDetails: FileDetail[]; - target: string; }; } -export function moveFiles(fileDetails: FileDetail[], target: string): MoveFilesAction { +export function moveFiles(fileDetails: FileDetail[]): MoveFilesAction { return { type: MOVE_FILES, payload: { fileDetails, - target, }, }; } diff --git a/packages/core/state/interaction/logics.ts b/packages/core/state/interaction/logics.ts index 4a882aa5..3e70a360 100644 --- a/packages/core/state/interaction/logics.ts +++ b/packages/core/state/interaction/logics.ts @@ -579,13 +579,13 @@ const setIsSmallScreen = createLogic({ /** * Interceptor responsible for handling the MOVE_FILES action. - * Logs the target location for file movement in the console. + * Logs details of files that are being moved. */ const moveFilesLogic = createLogic({ type: MOVE_FILES, process(deps, dispatch, done) { const action = deps.action as MoveFilesAction; - console.log(`Moving files to location: ${action.payload.target}`); + console.log(`Moving files:`, action.payload.fileDetails); done(); }, }); diff --git a/packages/core/state/interaction/reducer.ts b/packages/core/state/interaction/reducer.ts index 07655889..2f39ea7e 100644 --- a/packages/core/state/interaction/reducer.ts +++ b/packages/core/state/interaction/reducer.ts @@ -20,7 +20,6 @@ import { MARK_AS_USED_APPLICATION_BEFORE, MARK_AS_DISMISSED_SMALL_SCREEN_WARNING, ShowManifestDownloadDialogAction, - ShowMoveFileManifestAction, SET_IS_AICS_EMPLOYEE, PROMPT_FOR_DATA_SOURCE, DownloadManifestAction, @@ -59,7 +58,6 @@ export interface InteractionStateBranch { hasUsedApplicationBefore: boolean; isAicsEmployee?: boolean; isOnWeb: boolean; - moveFileTarget?: string; platformDependentServices: PlatformDependentServices; refreshKey?: string; selectedPublicDataset?: PublicDataset; @@ -198,10 +196,9 @@ export default makeReducer( ...state, selectedPublicDataset: action.payload, }), - [SHOW_MOVE_FILE_MANIFEST]: (state, action: ShowMoveFileManifestAction) => ({ + [SHOW_MOVE_FILE_MANIFEST]: (state) => ({ ...state, visibleModal: ModalType.MoveFileManifest, - moveFileTarget: action.payload.target, }), }, initialState diff --git a/packages/core/state/interaction/selectors.ts b/packages/core/state/interaction/selectors.ts index bf7096df..ec880228 100644 --- a/packages/core/state/interaction/selectors.ts +++ b/packages/core/state/interaction/selectors.ts @@ -47,7 +47,6 @@ export const getUserSelectedApplications = (state: State) => state.interaction.userSelectedApplications; export const getVisibleModal = (state: State) => state.interaction.visibleModal; export const isAicsEmployee = (state: State) => state.interaction.isAicsEmployee; -export const getMoveFileTarget = (state: State) => state.interaction.moveFileTarget; // COMPOSED SELECTORS export const getApplicationVersion = createSelector( From a450c4102951f88a6061ac7ae88d3696a9f8a171 Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Thu, 31 Oct 2024 16:59:09 -0700 Subject: [PATCH 13/13] add gradient --- .../Modal/MoveFileManifest/MoveFileManifest.module.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css index df5280ae..641907b9 100644 --- a/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css +++ b/packages/core/components/Modal/MoveFileManifest/MoveFileManifest.module.css @@ -1,8 +1,10 @@ -.file-table-container { +.fileTableContainer { max-height: 300px; overflow-y: auto; border: 1px solid var(--border-color); - margin-bottom: var(--margin); + margin-bottom: 1em; + padding: 1em; + background: linear-gradient(to bottom, transparent, var(--secondary-background-color)); } .file-table {