Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/toggle-modal #311

Merged
merged 13 commits into from
Nov 4, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.file-table-container {
max-height: 300px;
overflow-y: auto;
border: 1px solid var(--border-color);
margin-bottom: var(--margin);
}

.file-table {
width: 100%;
border-collapse: collapse;
}

.file-table th,
.file-table td {
padding: 8px;
text-align: left;
border-bottom: 1px solid var(--border-color);
white-space: nowrap;
color: var(--primary-text-color);
}

.file-table th {
background-color: var(--secondary-background-color);
position: sticky;
top: 0;
z-index: 1;
}

.file-table td:first-child {
border-right: 1px solid var(--border-color);
}
99 changes: 99 additions & 0 deletions packages/core/components/Modal/MoveFileManifest/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import filesize from "filesize";
import * as React from "react";
import { useDispatch, useSelector } from "react-redux";

import { ModalProps } from "..";
import BaseModal from "../BaseModal";
import { PrimaryButton } from "../../Buttons";
import FileDetail from "../../../entity/FileDetail";
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.
*/
export default function MoveFileManifest({ onDismiss }: ModalProps) {
const dispatch = useDispatch();
const fileService = useSelector(interaction.selectors.getFileService);
const fileSelection = useSelector(
selection.selectors.getFileSelection,
FileSelection.selectionsAreEqual
);
const moveFileTarget = useSelector(interaction.selectors.getMoveFileTarget);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we don't have a notion of moving on/off the cache it seems we can remove the idea of having a target. IMO this is likely a YAGNI since other than FMS we won't have control over moving files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved in 034549d


const [fileDetails, setFileDetails] = React.useState<FileDetail[]>([]);
const [totalSize, setTotalSize] = React.useState<string | undefined>();
const [isLoading, setLoading] = React.useState(false);

React.useEffect(() => {
async function fetchDetails() {
setLoading(true);
const details = await fileSelection.fetchAllDetails();
setFileDetails(details);

const aggregateInfo = await fileService.getAggregateInformation(fileSelection);
const formattedSize = aggregateInfo.size ? filesize(aggregateInfo.size) : undefined;
setTotalSize(formattedSize);
setLoading(false);
}

fetchDetails();
}, [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."
BrianWhitneyAI marked this conversation as resolved.
Show resolved Hide resolved
);
}
};

const body = (
<div>
<p>Selected Files:</p>
<div className={styles.fileTableContainer}>
<table className={styles.fileTable}>
<thead>
<tr>
<th>File Name</th>
<th>File Size</th>
</tr>
</thead>
<tbody>
{fileDetails.map((file) => (
<tr key={file.id}>
<td>{file.name}</td>
<td>{filesize(file.size || 0)}</td>
</tr>
))}
</tbody>
</table>
</div>
<p>Total Files: {fileDetails.length}</p>
<p>Total Size: {isLoading ? "Loading..." : totalSize}</p>
</div>
);

return (
<BaseModal
body={body}
footer={
<PrimaryButton
className={styles.confirmButton}
disabled={!fileDetails.length}
iconName="Accept"
onClick={onMove}
text="CONFIRM"
title="Confirm"
/>
}
onDismiss={onDismiss}
title={`Move Files ${moveFileTarget === "ON_TO_NAS" ? "onto" : "off of"} NAS Cache`}
saeliddp marked this conversation as resolved.
Show resolved Hide resolved
/>
);
}
4 changes: 4 additions & 0 deletions packages/core/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -16,6 +17,7 @@ export enum ModalType {
DataSource = 2,
MetadataManifest = 3,
SmallScreenWarning = 4,
MoveFileManifest = 5,
}

/**
Expand All @@ -38,6 +40,8 @@ export default function Modal() {
return <MetadataManifest onDismiss={onDismiss} />;
case ModalType.SmallScreenWarning:
return <SmallScreenWarning onDismiss={onDismiss} />;
case ModalType.MoveFileManifest:
return <MoveFileManifest onDismiss={onDismiss} />;
default:
return null;
}
Expand Down
64 changes: 33 additions & 31 deletions packages/core/hooks/useFileAccessContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,37 +147,39 @@ 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: "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");
},
},
{
key: "onto-nas",
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");
},
},
],
},
},
...(isQueryingAicsFms
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets move this option above "Download"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved in 034549d

? [
{
key: "move-files",
text: "Move Files",
saeliddp marked this conversation as resolved.
Show resolved Hide resolved
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",
saeliddp marked this conversation as resolved.
Show resolved Hide resolved
itemType: ContextualMenuItemType.Header,
},
{
key: "onto-nas",
text: "Onto NAS Cache",
title: "Move files onto the NAS cache",
onClick() {
dispatch(
interaction.actions.showMoveFileManifest("NAS")
);
},
},
],
},
},
]
: []),
];

dispatch(
Expand Down
44 changes: 44 additions & 0 deletions packages/core/state/interaction/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -679,3 +679,47 @@ 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.
BrianWhitneyAI marked this conversation as resolved.
Show resolved Hide resolved
*/
export const SHOW_MOVE_FILE_MANIFEST = makeConstant(STATE_BRANCH_NAME, "show-move-file-manifest");

export interface ShowMoveFileManifestAction {
type: string;
payload: {
target: string;
};
}

export function showMoveFileManifest(target: string): ShowMoveFileManifestAction {
return {
type: SHOW_MOVE_FILE_MANIFEST,
payload: {
target,
},
};
}

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 {
return {
type: MOVE_FILES,
payload: {
fileDetails,
target,
},
};
}
16 changes: 16 additions & 0 deletions packages/core/state/interaction/logics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
SetIsSmallScreenAction,
setVisibleModal,
hideVisibleModal,
MoveFilesAction,
MOVE_FILES,
} from "./actions";
import * as interactionSelectors from "./selectors";
import { DownloadResolution, FileInfo } from "../../services/FileDownloadService";
Expand Down Expand Up @@ -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,
Expand All @@ -586,4 +601,5 @@ export default [
showContextMenu,
refresh,
setIsSmallScreen,
moveFilesLogic,
];
8 changes: 8 additions & 0 deletions packages/core/state/interaction/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -57,6 +59,7 @@ export interface InteractionStateBranch {
hasUsedApplicationBefore: boolean;
isAicsEmployee?: boolean;
isOnWeb: boolean;
moveFileTarget?: string;
platformDependentServices: PlatformDependentServices;
refreshKey?: string;
selectedPublicDataset?: PublicDataset;
Expand Down Expand Up @@ -195,6 +198,11 @@ export default makeReducer<InteractionStateBranch>(
...state,
selectedPublicDataset: action.payload,
}),
[SHOW_MOVE_FILE_MANIFEST]: (state, action: ShowMoveFileManifestAction) => ({
...state,
visibleModal: ModalType.MoveFileManifest,
moveFileTarget: action.payload.target,
}),
},
initialState
);
1 change: 1 addition & 0 deletions packages/core/state/interaction/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading