Skip to content

Commit b9f3413

Browse files
authored
Merge branch 'main' into admin/remove-x86-build
2 parents 261b1f2 + 1c0883f commit b9f3413

File tree

8 files changed

+224
-22
lines changed

8 files changed

+224
-22
lines changed

packages/core/components/DirectoryTree/DirectoryTreeNode.module.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
}
2323

2424
.focused {
25-
border: 1px solid var(--highlight-text-color);
25+
border: 1px solid var(--highlight-hover-background-color);
2626
margin: 0;
2727
}
2828

packages/core/components/FileList/FileList.module.css

+1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@
3333
height: var(--row-count-intrisic-height-height);
3434
font-size: var(--row-count-intrisic-height);
3535
margin-top: var(--row-count-margin-top);
36+
margin-block-end: 0;
3637
}

packages/core/components/StatusMessage/StatusMessage.module.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
display: none;
1818
}
1919

20-
.centeringParent {
20+
.centering-parent {
2121
display: flex;
2222
font-size: var(--l-paragraph-size);
2323
font-weight: 500;

packages/core/hooks/useFileAccessContextMenu.ts

+43-19
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import { interaction, selection } from "../state";
1414
* previously saved applications. Can be supplied an array of filters to use
1515
* to find files to access instead of the currently selected files.
1616
*/
17-
export default (filters?: FileFilter[], onDismiss?: () => void) => {
17+
export default (folderFilters?: FileFilter[], onDismiss?: () => void) => {
1818
const dispatch = useDispatch();
1919
const isOnWeb = useSelector(interaction.selectors.isOnWeb);
2020
const fileSelection = useSelector(selection.selectors.getFileSelection);
2121
const isQueryingAicsFms = useSelector(selection.selectors.isQueryingAicsFms);
2222

2323
const [fileDetails, setFileDetails] = React.useState<FileDetail>();
2424

25-
const openWithSubMenuItems = useOpenWithMenuItems(fileDetails, filters);
25+
const openWithSubMenuItems = useOpenWithMenuItems(fileDetails, folderFilters);
2626

2727
fileSelection.fetchFocusedItemDetails().then((fileDetails) => {
2828
setFileDetails(fileDetails);
@@ -33,6 +33,30 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
3333
evt.preventDefault();
3434

3535
const contextMenuItems: IContextualMenuItem[] = [
36+
...(!folderFilters
37+
? []
38+
: [
39+
{
40+
key: "expand",
41+
text: "Expand all",
42+
iconProps: {
43+
iconName: "ExploreContent",
44+
},
45+
onClick() {
46+
dispatch(selection.actions.expandAllFileFolders());
47+
},
48+
},
49+
{
50+
key: "collapse",
51+
text: "Collapse all",
52+
iconProps: {
53+
iconName: "CollapseContent",
54+
},
55+
onClick() {
56+
dispatch(selection.actions.collapseAllFileFolders());
57+
},
58+
},
59+
]),
3660
// Avoid showing default open option when on web
3761
...(isOnWeb
3862
? []
@@ -43,10 +67,10 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
4367
iconProps: {
4468
iconName: "OpenInNewWindow",
4569
},
46-
disabled: !filters && fileSelection.count() === 0,
70+
disabled: !folderFilters && fileSelection.count() === 0,
4771
onClick() {
48-
if (filters) {
49-
dispatch(interaction.actions.openWithDefault(filters));
72+
if (folderFilters) {
73+
dispatch(interaction.actions.openWithDefault(folderFilters));
5074
} else if (fileDetails) {
5175
dispatch(
5276
interaction.actions.openWithDefault(undefined, [
@@ -60,7 +84,7 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
6084
{
6185
key: "open-with",
6286
text: "Open with",
63-
disabled: !filters && fileSelection.count() === 0,
87+
disabled: !folderFilters && fileSelection.count() === 0,
6488
iconProps: {
6589
iconName: "OpenInNewWindow",
6690
},
@@ -71,7 +95,7 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
7195
{
7296
key: "save-as",
7397
text: "Save metadata as",
74-
disabled: !filters && fileSelection.count() === 0,
98+
disabled: !folderFilters && fileSelection.count() === 0,
7599
iconProps: {
76100
iconName: "Saveas",
77101
},
@@ -86,13 +110,13 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
86110
{
87111
key: "csv",
88112
text: "CSV",
89-
disabled: !filters && fileSelection.count() === 0,
113+
disabled: !folderFilters && fileSelection.count() === 0,
90114
title: "Download a CSV of the metadata of the selected files",
91115
onClick() {
92116
dispatch(
93117
interaction.actions.showManifestDownloadDialog(
94118
"csv",
95-
filters
119+
folderFilters
96120
)
97121
);
98122
},
@@ -104,29 +128,29 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
104128
{
105129
key: "json",
106130
text: "JSON",
107-
disabled: !filters && fileSelection.count() === 0,
131+
disabled: !folderFilters && fileSelection.count() === 0,
108132
title:
109133
"Download a JSON file of the metadata of the selected files",
110134
onClick() {
111135
dispatch(
112136
interaction.actions.showManifestDownloadDialog(
113137
"json",
114-
filters
138+
folderFilters
115139
)
116140
);
117141
},
118142
},
119143
{
120144
key: "parquet",
121145
text: "Parquet",
122-
disabled: !filters && fileSelection.count() === 0,
146+
disabled: !folderFilters && fileSelection.count() === 0,
123147
title:
124148
"Download a Parquet file of the metadata of the selected files",
125149
onClick() {
126150
dispatch(
127151
interaction.actions.showManifestDownloadDialog(
128152
"parquet",
129-
filters
153+
folderFilters
130154
)
131155
);
132156
},
@@ -141,7 +165,7 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
141165
key: "copy-to-cache",
142166
text: "Copy to vast",
143167
title: "Copy selected files to NAS Cache (VAST)",
144-
disabled: !filters && fileSelection.count() === 0,
168+
disabled: !folderFilters && fileSelection.count() === 0,
145169
iconProps: { iconName: "MoveToFolder" },
146170
onClick() {
147171
dispatch(interaction.actions.showCopyFileManifest());
@@ -153,7 +177,7 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
153177
key: "download",
154178
text: "Download",
155179
title: "Download selected files to a specific directory",
156-
disabled: !filters && fileSelection.count() === 0,
180+
disabled: !folderFilters && fileSelection.count() === 0,
157181
iconProps: {
158182
iconName: "Download",
159183
},
@@ -168,13 +192,13 @@ export default (filters?: FileFilter[], onDismiss?: () => void) => {
168192
);
169193
},
170194
[
171-
filters,
172195
dispatch,
173-
onDismiss,
174-
isOnWeb,
196+
fileDetails,
175197
fileSelection,
198+
folderFilters,
199+
isOnWeb,
176200
isQueryingAicsFms,
177-
fileDetails,
201+
onDismiss,
178202
openWithSubMenuItems,
179203
]
180204
);

packages/core/state/selection/actions.ts

+35
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,41 @@ export function toggleFileFolderCollapse(fileFolder: FileFolder): ToggleFileFold
515515
};
516516
}
517517

518+
/**
519+
* COLLAPSE_ALL_FILE_FOLDERS
520+
* Intention to collapse all file folders
521+
*/
522+
export const COLLAPSE_ALL_FILE_FOLDERS = makeConstant(
523+
STATE_BRANCH_NAME,
524+
"collapse-all-file-folders"
525+
);
526+
527+
export interface CollapseAllFileFoldersAction {
528+
type: string;
529+
}
530+
531+
export function collapseAllFileFolders(): CollapseAllFileFoldersAction {
532+
return {
533+
type: COLLAPSE_ALL_FILE_FOLDERS,
534+
};
535+
}
536+
537+
/**
538+
* EXPAND_ALL_FILE_FOLDERS
539+
* Intention to toggle the given file folder's collapsed state
540+
*/
541+
export const EXPAND_ALL_FILE_FOLDERS = makeConstant(STATE_BRANCH_NAME, "expand-all-file-folders");
542+
543+
export interface ExpandAllFileFoldersAction {
544+
type: string;
545+
}
546+
547+
export function expandAllFileFolders(): ExpandAllFileFoldersAction {
548+
return {
549+
type: EXPAND_ALL_FILE_FOLDERS,
550+
};
551+
}
552+
518553
/**
519554
* SET_OPEN_FILE_FOLDERS
520555
* Intention to set which file folders are open as opposed to collapsed

packages/core/state/selection/logics.ts

+51
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
AddDataSourceReloadError,
4949
setFileView,
5050
setColumns,
51+
EXPAND_ALL_FILE_FOLDERS,
5152
} from "./actions";
5253
import { interaction, metadata, ReduxLogicDeps, selection } from "../";
5354
import * as selectionSelectors from "./selectors";
@@ -57,6 +58,7 @@ import FileFilter, { FilterType } from "../../entity/FileFilter";
5758
import FileFolder from "../../entity/FileFolder";
5859
import FileSelection from "../../entity/FileSelection";
5960
import FileSet from "../../entity/FileSet";
61+
import { AnnotationValue } from "../../services/AnnotationService";
6062
import HttpAnnotationService from "../../services/AnnotationService/HttpAnnotationService";
6163
import { DataSource } from "../../services/DataSourceService";
6264
import DataSourcePreparationError from "../../errors/DataSourcePreparationError";
@@ -340,6 +342,54 @@ const toggleFileFolderCollapse = createLogic({
340342
type: [TOGGLE_FILE_FOLDER_COLLAPSE],
341343
});
342344

345+
/**
346+
* Interceptor responsible for transforming COLLAPSE_ALL_FILE_FOLDERS and EXPAND_ALL_FILE_FOLDERS
347+
* actions into SET_OPEN_FILE_FOLDERS actions by either setting to none or recursively
348+
* unpacking the directory structure
349+
*/
350+
const expandAllFileFolders = createLogic({
351+
async process(deps: ReduxLogicDeps, dispatch, done) {
352+
const { getState } = deps;
353+
const hierarchy = selection.selectors.getAnnotationHierarchy(getState());
354+
const annotationService = interaction.selectors.getAnnotationService(getState());
355+
const selectedFileFilters = selection.selectors.getFileFilters(getState());
356+
// Track internally rather than relying on selector (may be out of sync)
357+
const openedSoFar: FileFolder[] = [];
358+
// Recursive helper
359+
async function unpackAllFileFolders(values: string[], pathSoFar: string[]) {
360+
const fileFoldersToOpen: FileFolder[] = values.map(
361+
(value) => new FileFolder([...pathSoFar, value] as AnnotationValue[])
362+
);
363+
// Needs to be set wholesale so must include already opened folderes
364+
openedSoFar.push(...fileFoldersToOpen);
365+
dispatch(setOpenFileFolders(openedSoFar));
366+
for (const value of values) {
367+
// At end of folder hierarchy
368+
if (!!hierarchy.length && pathSoFar.length === hierarchy.length - 1) continue;
369+
370+
const childNodes = await annotationService.fetchHierarchyValuesUnderPath(
371+
hierarchy,
372+
[...pathSoFar, value],
373+
selectedFileFilters
374+
);
375+
if (childNodes.length) {
376+
// Not a leaf
377+
unpackAllFileFolders(childNodes, [...pathSoFar, value]);
378+
}
379+
}
380+
}
381+
382+
const rootHierarchyValues = await annotationService.fetchRootHierarchyValues(
383+
hierarchy,
384+
selectedFileFilters
385+
);
386+
await unpackAllFileFolders(rootHierarchyValues, []);
387+
dispatch(interaction.actions.refresh() as AnyAction); // synchronize UI with state
388+
done();
389+
},
390+
type: [EXPAND_ALL_FILE_FOLDERS],
391+
});
392+
343393
/**
344394
* Interceptor responsible for processing DECODE_FILE_EXPLORER_URL actions into various
345395
* other actions responsible for rehydrating the FileExplorerURL into application state.
@@ -754,6 +804,7 @@ export default [
754804
modifyAnnotationHierarchy,
755805
modifyFileFilters,
756806
toggleFileFolderCollapse,
807+
expandAllFileFolders,
757808
decodeFileExplorerURLLogics,
758809
selectNearbyFile,
759810
setAvailableAnnotationsLogic,

packages/core/state/selection/reducer.ts

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
Column,
3434
SetColumns,
3535
SET_COLUMNS,
36+
COLLAPSE_ALL_FILE_FOLDERS,
3637
} from "./actions";
3738
import interaction from "../interaction";
3839
import { FileView, Source } from "../../entity/FileExplorerURL";
@@ -194,6 +195,10 @@ export default makeReducer<SelectionStateBranch>(
194195
availableAnnotationsForHierarchy: action.payload,
195196
availableAnnotationsForHierarchyLoading: false,
196197
}),
198+
[COLLAPSE_ALL_FILE_FOLDERS]: (state) => ({
199+
...state,
200+
openFileFolders: [],
201+
}),
197202
[SET_OPEN_FILE_FOLDERS]: (state, action) => ({
198203
...state,
199204
openFileFolders: action.payload,

0 commit comments

Comments
 (0)