From b9f84e7194fd47472703c8e01c29bfea2b70492f Mon Sep 17 00:00:00 2001 From: JacobiClark Date: Thu, 5 Dec 2024 14:59:56 -0800 Subject: [PATCH] wip: Enhance file explorer for presentation --- .../shared/DatasetTreeViewRenderer/index.jsx | 7 +- .../shared/manifest/DatasetEntitySelector.jsx | 340 ++++++++---------- .../utils/SodaComponentWrapper/index.jsx | 11 + .../guided-mode/guided-curate-dataset.js | 4 + .../slices/datasetEntitySelectorSlice.js | 65 ++-- .../src/stores/slices/datasetTreeViewSlice.js | 65 ++-- 6 files changed, 250 insertions(+), 242 deletions(-) diff --git a/src/renderer/src/components/shared/DatasetTreeViewRenderer/index.jsx b/src/renderer/src/components/shared/DatasetTreeViewRenderer/index.jsx index 5fd34f8e5..4e91e1d31 100644 --- a/src/renderer/src/components/shared/DatasetTreeViewRenderer/index.jsx +++ b/src/renderer/src/components/shared/DatasetTreeViewRenderer/index.jsx @@ -136,7 +136,6 @@ const FolderItem = ({ Object.keys(content.files || {}).length === 0; const folderHasFiles = Object.keys(content.files || {}).length > 0; - const folderHasFolders = Object.keys(content.folders || {}).length > 0; const isViewOnly = !onFileClick || !onFolderClick || !getEntityForRelativePath; @@ -157,7 +156,7 @@ const FolderItem = ({ /> )} {!isViewOnly && ( - + onFolderClick(name, content, "folder-select")} @@ -173,14 +172,14 @@ const FolderItem = ({ {!isViewOnly && ( <> {folderHasFiles && ( - + onFolderClick(name, content, "folder-files-select")} /> )} - + onFolderClick(name, content, "folder-recursive-select")} diff --git a/src/renderer/src/components/shared/manifest/DatasetEntitySelector.jsx b/src/renderer/src/components/shared/manifest/DatasetEntitySelector.jsx index 1d7868b1e..852f1a443 100644 --- a/src/renderer/src/components/shared/manifest/DatasetEntitySelector.jsx +++ b/src/renderer/src/components/shared/manifest/DatasetEntitySelector.jsx @@ -1,4 +1,5 @@ -import { Grid, Button, Stack, Title, Paper, Divider, Text, Box, Group, rem } from "@mantine/core"; +import { Grid, Paper, Divider, Text, Box, Group, Tooltip } from "@mantine/core"; +import { IconSearch } from "@tabler/icons-react"; import FullWidthContainer from "../../containers/FullWidthContainer"; import useGlobalStore from "../../../stores/globalStore"; import DatasetTreeViewRenderer from "../DatasetTreeViewRenderer"; @@ -7,152 +8,153 @@ import { modifyDatasetEntityForRelativeFilePath, getEntityForRelativePath, } from "../../../stores/slices/datasetEntitySelectorSlice"; +import { setDatasetstructureSearchFilter } from "../../../stores/slices/datasetTreeViewSlice"; -const DatasetEntitySelector = () => { - const { entityList, entityListName, activeEntity, entityType, datasetEntityObj } = useGlobalStore( - (state) => ({ - entityList: state.entityList, - entityListName: state.entityListName, - activeEntity: state.activeEntity, - entityType: state.entityType, - datasetEntityObj: state.datasetEntityObj, - }) +const useDatasetEntityStore = () => + useGlobalStore((state) => ({ + entityList: state.entityList, + entityListName: state.entityListName, + activeEntity: state.activeEntity, + entityType: state.entityType, + datasetEntityObj: state.datasetEntityObj, + })); + +const handleEntityClick = (entity) => setActiveEntity(entity); + +const handleFileClick = (entityType, activeEntity, datasetEntityObj, fileName, fileContents) => { + modifyDatasetEntityForRelativeFilePath( + entityType, + activeEntity, + fileContents.relativePath, + "toggle" ); +}; - const handleEntityClick = (entity) => { - setActiveEntity(entity); - }; +const recursiveFolderAction = ( + folderContents, + entityType, + activeEntity, + datasetEntityObj, + action +) => { + modifyDatasetEntityForRelativeFilePath( + entityType, + activeEntity, + folderContents.relativePath, + action + ); - const handleFileClick = (fileName, fileContents) => { - modifyDatasetEntityForRelativeFilePath( - entityType, - activeEntity, - fileContents.relativePath, - "toggle" - ); - }; + Object.values(folderContents.files).forEach((file) => { + modifyDatasetEntityForRelativeFilePath(entityType, activeEntity, file.relativePath, action); + }); - const handleFolderClick = (folderName, folderContents, folderClickAction) => { - console.log("handleFolderClick", folderClickAction); - /*if (folderClickAction === "folder-select") { - modifyDatasetEntityForRelativeFilePath( - entityType, - activeEntity, - folderContents.relativePath, - "toggle" - ); - return; - }*/ - - if (folderClickAction === "folder-files-select") { - // Get all of the files that do not belong to a seperate entity and are not claimed - const fileEntities = Object.keys(folderContents.files) - .map((file) => folderContents.files[file].relativePath) - .filter((fileEntity) => { - const entity = getEntityForRelativePath(datasetEntityObj, entityType, fileEntity); - console.log("Entity", entity); - - return !entity || entity === activeEntity; - }); - // Check to see if all of the files are already claimed by the active entity - const allFilesClaimed = fileEntities.every((fileEntity) => { + Object.values(folderContents.folders).forEach((subFolder) => { + recursiveFolderAction(subFolder, entityType, activeEntity, datasetEntityObj, action); + }); +}; + +const handleFolderClick = ( + entityType, + activeEntity, + datasetEntityObj, + folderContents, + folderClickAction +) => { + if (folderClickAction === "folder-files-select") { + const fileEntities = Object.keys(folderContents.files) + .map((file) => folderContents.files[file].relativePath) + .filter((fileEntity) => { const entity = getEntityForRelativePath(datasetEntityObj, entityType, fileEntity); - return entity === activeEntity; + return !entity || entity === activeEntity; }); - console.log("All files claimed", allFilesClaimed); - // If all files are claimed, unclaim them - if (allFilesClaimed) { - fileEntities.forEach((fileEntity) => { - console; - modifyDatasetEntityForRelativeFilePath(entityType, activeEntity, fileEntity, "remove"); - }); - } else { - // Otherwise, claim them - fileEntities.forEach((fileEntity) => { - modifyDatasetEntityForRelativeFilePath(entityType, activeEntity, fileEntity, "add"); - }); - } - } - - if (folderClickAction === "folder-recursive-select") { - const clickedFoldersEntity = getEntityForRelativePath( - datasetEntityObj, - entityType, - folderContents.relativePath - ); - console.log("Clicked folders entity", clickedFoldersEntity); - // If the folder is already claimed by an entity, recursively unclaim the entity and all of its contents - if (clickedFoldersEntity === activeEntity) { - const unclaimEntity = (folderContents) => { - modifyDatasetEntityForRelativeFilePath( - entityType, - activeEntity, - folderContents.relativePath, - "remove" - ); - for (const file of Object.keys(folderContents.files)) { - const filesRelativePath = folderContents.files[file].relativePath; - modifyDatasetEntityForRelativeFilePath( - entityType, - activeEntity, - filesRelativePath, - "remove" - ); - } - for (const subFolder of Object.keys(folderContents.folders)) { - unclaimEntity(folderContents.folders[subFolder]); - } - }; - unclaimEntity(folderContents); - } else { - // Otherwise, claim the folder and all of its contents - const claimEntity = (folderContents) => { - modifyDatasetEntityForRelativeFilePath( - entityType, - activeEntity, - folderContents.relativePath, - "add" - ); - for (const file of Object.keys(folderContents.files)) { - const filesRelativePath = folderContents.files[file].relativePath; - modifyDatasetEntityForRelativeFilePath( - entityType, - activeEntity, - filesRelativePath, - "add" - ); - } - for (const subFolder of Object.keys(folderContents.folders)) { - claimEntity(folderContents.folders[subFolder]); - } - }; - claimEntity(folderContents); - } - - /* - // Mark the folder itself as part of the active entity if needed + + const allFilesClaimed = fileEntities.every((fileEntity) => { + const entity = getEntityForRelativePath(datasetEntityObj, entityType, fileEntity); + return entity === activeEntity; + }); + + fileEntities.forEach((fileEntity) => { modifyDatasetEntityForRelativeFilePath( entityType, activeEntity, - folderContents.relativePath, - "add" + fileEntity, + allFilesClaimed ? "remove" : "add" ); - // Recursively toggle all subfolders and their contents - for (const file of Object.keys(folderContents.files)) { - const filesRelativePath = folderContents.files[file].relativePath; - console.log("Files relative path", filesRelativePath); - console.log( - "Files entity", - getEntityForRelativePath(datasetEntityObj, entityType, filesRelativePath) - ); - - modifyDatasetEntityForRelativeFilePath(entityType, activeEntity, filesRelativePath); - } - for (const subFolder of Object.keys(folderContents.folders)) { - handleFolderClick(subFolder, folderContents.folders[subFolder], "folder-recursive-select"); - }*/ - } - }; + }); + } + + if (folderClickAction === "folder-recursive-select") { + const clickedFoldersEntity = getEntityForRelativePath( + datasetEntityObj, + entityType, + folderContents.relativePath + ); + recursiveFolderAction( + folderContents, + entityType, + activeEntity, + datasetEntityObj, + clickedFoldersEntity === activeEntity ? "remove" : "add" + ); + } +}; + +const renderEntityList = (entityList, entityListName, activeEntity, datasetEntityObj) => + entityList.map((entity) => { + const entityItemsCount = Object.keys( + datasetEntityObj?.[datasetEntityObj.entityType]?.[entity] || {} + ).length; + const isActive = activeEntity === entity; + + return ( + handleEntityClick(entity)} + p="sm" + style={{ + width: "100%", + backgroundColor: isActive ? "#e3f2fd" : "transparent", + color: isActive ? "#0d47a1" : "#333", + border: "none", + borderLeft: `3px solid ${isActive ? "#2196f3" : "transparent"}`, + cursor: "pointer", + transition: "background-color 0.2s ease, border-color 0.2s ease", + }} + > + + {entity} + + {entityItemsCount} + + + { + const knownEntityPrefixes = ["sub-", "sam-", "perf-"]; + // Iterate through each prefix and check if the entity starts with it + let entityName = entity; + for (let prefix of knownEntityPrefixes) { + if (entity.startsWith(prefix)) { + // Remove the prefix if it matches + entityName = entity.substring(prefix.length); + break; // Stop once the first match is found + } + } + + setDatasetstructureSearchFilter(entityName); + }} + /> + + + + + ); + }); + +const DatasetEntitySelector = () => { + const { entityList, entityListName, activeEntity, entityType, datasetEntityObj } = + useDatasetEntityStore(); return ( @@ -165,50 +167,8 @@ const DatasetEntitySelector = () => { - - {entityList.map((entity, index) => { - const entityItemsCount = Object.keys( - datasetEntityObj?.[entityType]?.[entity] || {} - ).length; - const isActive = activeEntity === entity; - - return ( - handleEntityClick(entity)} - style={{ - display: "block", - width: "100%", - textAlign: "left", - backgroundColor: isActive ? "#e3f2fd" : "transparent", - color: isActive ? "#0d47a1" : "#333", - padding: rem(8), - paddingLeft: rem(16), // Add space for hierarchy-like appearance - fontSize: rem(14), - lineHeight: 1.5, - fontWeight: isActive ? 500 : 400, - textDecoration: "none", - border: "none", - borderLeft: `3px solid ${isActive ? "#2196f3" : "transparent"}`, // Highlight active with a border - cursor: "pointer", - transition: "background-color 0.2s ease, border-color 0.2s ease", - }} - > - - {entity} - - {entityItemsCount} - - - - ); - })} + + {renderEntityList(entityList, entityListName, activeEntity, datasetEntityObj)} @@ -217,8 +177,24 @@ const DatasetEntitySelector = () => { {activeEntity ? ( + handleFolderClick( + entityType, + activeEntity, + datasetEntityObj, + folderContents, + folderClickAction + ) + } + onFileClick={(fileName, fileContents) => + handleFileClick( + entityType, + activeEntity, + datasetEntityObj, + fileName, + fileContents + ) + } getEntityForRelativePath={getEntityForRelativePath} /> diff --git a/src/renderer/src/components/utils/SodaComponentWrapper/index.jsx b/src/renderer/src/components/utils/SodaComponentWrapper/index.jsx index e1b617a3b..8b1915498 100644 --- a/src/renderer/src/components/utils/SodaComponentWrapper/index.jsx +++ b/src/renderer/src/components/utils/SodaComponentWrapper/index.jsx @@ -1,6 +1,8 @@ import React from "react"; import { MantineProvider, createTheme, Stack } from "@mantine/core"; import FullWidthContainer from "../../containers/FullWidthContainer"; +import { Tooltip } from "bootstrap"; +import { root } from "postcss"; const theme = createTheme({ colors: { @@ -25,6 +27,15 @@ const theme = createTheme({ lg: "1.2rem", xl: "1.4rem", }, + components: { + Tooltip: { + styles: { + root: { + zIndex: 2999, + }, + }, + }, + }, }); const SodaComponentWrapper = ({ children }) => { diff --git a/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js b/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js index cc6a3eab7..2b5528880 100644 --- a/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js +++ b/src/renderer/src/scripts/guided-mode/guided-curate-dataset.js @@ -1358,6 +1358,9 @@ const savePageChanges = async (pageBeingLeftID) => { } } + if (pageBeingLeftID === "guided-denote-derivative-data-tab") { + } + if (pageBeingLeftID === "guided-manifest-subject-entity-selector-tab") { window.sodaJSONObj["subject-related-folders-and-files"] = getEntityListForEntityType( "subject-related-folders-and-files" @@ -5655,6 +5658,7 @@ window.openPage = async (targetPageID) => { renderManifestCards(); } if (targetPageID === "guided-manifest-subject-entity-selector-tab") { + const subjects = window.getExistingSubjectNames(); setEntityList(window.getExistingSubjectNames(), "Subjects List"); setTreeViewDatasetStructure(window.datasetStructureJSONObj, ["primary"]); setEntityType("subject-related-folders-and-files"); diff --git a/src/renderer/src/stores/slices/datasetEntitySelectorSlice.js b/src/renderer/src/stores/slices/datasetEntitySelectorSlice.js index 6d7634980..7d9911ea0 100644 --- a/src/renderer/src/stores/slices/datasetEntitySelectorSlice.js +++ b/src/renderer/src/stores/slices/datasetEntitySelectorSlice.js @@ -1,18 +1,21 @@ import useGlobalStore from "../globalStore"; import { produce } from "immer"; + +// Initial state for managing entities in the dataset const initialState = { - entityList: [], - entityListName: "", - activeEntity: null, - entityType: null, - datasetEntityObj: {}, + entityList: [], // List of entities for the current context + entityListName: "", // Name of the entity list being managed + activeEntity: null, // The currently active entity + entityType: null, // Type of the currently selected entity + datasetEntityObj: {}, // Object storing all entities organized by type }; -// Slice now only has initial state +// Define the slice for entity selector state export const datasetEntitySelectorSlice = (set) => ({ ...initialState, }); +// Resets the entity selector state to its initial configuration export const resetDatasetEntitySelectorState = () => { useGlobalStore.setState( produce((state) => { @@ -21,6 +24,7 @@ export const resetDatasetEntitySelectorState = () => { ); }; +// Sets the entity list and its associated name in the global store export const setEntityList = (entityList, entityListName) => { useGlobalStore.setState((state) => ({ ...state, @@ -29,15 +33,18 @@ export const setEntityList = (entityList, entityListName) => { })); }; +// Retrieves the list of entities for a given entity type export const getEntityListForEntityType = (entityListName) => { return useGlobalStore.getState()?.datasetEntityObj?.[entityListName] || {}; }; +// Retrieves entities for a specific type from the datasetEntityObj export const getEntitiesForType = (entityType) => { const datasetEntityObj = useGlobalStore((state) => state.datasetEntityObj); return datasetEntityObj?.[entityType] || {}; }; +// Updates the currently active entity in the global store export const setActiveEntity = (activeEntity) => { useGlobalStore.setState((state) => ({ ...state, @@ -45,6 +52,7 @@ export const setActiveEntity = (activeEntity) => { })); }; +// Updates the current entity type in the global store export const setEntityType = (entityType) => { useGlobalStore.setState((state) => ({ ...state, @@ -52,10 +60,12 @@ export const setEntityType = (entityType) => { })); }; +// Updates the list of entities for a given entity type export const setEntityListForEntityType = (entityType, entityListObj) => { if (!entityType || !entityListObj) { console.log("Aborting function: entityType or entityListObj is missing"); console.log(entityType, entityListObj); + return; } useGlobalStore.setState( @@ -65,19 +75,20 @@ export const setEntityListForEntityType = (entityType, entityListObj) => { ); }; -export const setdatasetEntityObj = (datasetEntityObj) => { +// Sets the dataset entity object in the global store +export const setDatasetEntityObj = (datasetEntityObj) => { useGlobalStore.setState((state) => ({ ...state, datasetEntityObj, })); }; -const entityHeirarchies = [ - ["subject-related-folders-and-files", "sample-related-folders-and-files"], // Sample folders and files are a subset of subject folders and files +// Hierarchies defining relationships between entity types +const entityHierarchies = [ + ["subject-related-folders-and-files", "sample-related-folders-and-files"], // Sample is a subset of subject ]; -// Function to add or update a specific value (relative path) in datasetEntityObj -// Function to add or update a specific value (relative path) in datasetEntityObj +// Modifies the dataset entity for a specific relative file path export const modifyDatasetEntityForRelativeFilePath = ( entityType, entityName, @@ -100,15 +111,12 @@ export const modifyDatasetEntityForRelativeFilePath = ( const entityEntries = datasetEntity[entityType]; const targetEntity = entityEntries[entityName] || []; - // Action handling + // Handle actions: toggle, add, or remove switch (action) { case "toggle": - console.log("Toggling entity for relative path", entityRelativePath); if (targetEntity.includes(entityRelativePath)) { - // Remove if it exists entityEntries[entityName] = targetEntity.filter((path) => path !== entityRelativePath); } else { - // Add and ensure exclusivity across other entities entityEntries[entityName] = [...targetEntity, entityRelativePath]; removeFromOtherEntities(entityEntries, entityName, entityRelativePath); } @@ -132,42 +140,43 @@ export const modifyDatasetEntityForRelativeFilePath = ( ); }; -// Helper function to remove a path from all other entities in the same entityType +// Removes a file path from all entities except the target entity const removeFromOtherEntities = (entityEntries, targetEntityName, entityRelativePath) => { Object.keys(entityEntries).forEach((entity) => { - console.log("entity", entity); if (entity !== targetEntityName) { entityEntries[entity] = entityEntries[entity].filter((path) => path !== entityRelativePath); } }); - // If the entity is a subset of another entity, remove the path from the parent entity - const entityExistsInHeirarchy = entityHeirarchies.find((heirarchy) => - heirarchy.includes(targetEntityName) + + // Handle hierarchies: if the entity is a subset of another, remove the path from the parent entity + const entityExistsInHierarchy = entityHierarchies.find((hierarchy) => + hierarchy.includes(targetEntityName) ); - console.log("removeFromOtherEntities"); - console.log(entityEntries); - console.log(targetEntityName); - console.log(entityRelativePath); + console.log("removeFromOtherEntities", { + entityEntries, + targetEntityName, + entityRelativePath, + entityExistsInHierarchy, + }); }; +// Retrieves the entity associated with a specific file path export const getEntityForRelativePath = (datasetEntityObj, entityType, relativePath) => { - // Ensure the datasetEntityObj and entityType are valid if (!datasetEntityObj || !entityType || !datasetEntityObj[entityType]) { return null; } - // Iterate through all entities within the specified entityType for (const entityName in datasetEntityObj[entityType]) { - // If the relativePath exists in the entity's list, return the entityName if (datasetEntityObj[entityType][entityName]?.includes(relativePath)) { return entityName; } } - return null; // Return null if the relativePath is not found + return null; }; +// Gets the number of files associated with a specific entity export const getNumberFilesForEntity = (entityName) => { const datasetEntityObj = useGlobalStore((state) => state.datasetEntityObj); const entityType = useGlobalStore((state) => state.entityType); diff --git a/src/renderer/src/stores/slices/datasetTreeViewSlice.js b/src/renderer/src/stores/slices/datasetTreeViewSlice.js index 1f0fe5f84..77f05e794 100644 --- a/src/renderer/src/stores/slices/datasetTreeViewSlice.js +++ b/src/renderer/src/stores/slices/datasetTreeViewSlice.js @@ -1,18 +1,22 @@ import useGlobalStore from "../globalStore"; +// Initial state for managing dataset structure and filters const initialState = { - datasetStructureJSONObj: null, - renderDatasetStructureJSONObj: null, - datasetStructureSearchFilter: "", - pathToRender: [], // Store pathToRender here + datasetStructureJSONObj: null, // Full dataset structure + renderDatasetStructureJSONObj: null, // Rendered subset of dataset structure + datasetStructureSearchFilter: "", // Current search filter text + pathToRender: [], // Path to the folder currently rendered in the tree view }; +// Create the dataset tree view slice for global state export const datasetTreeViewSlice = (set) => ({ ...initialState, }); -// Helper function to traverse dataset structure by pathToRender +// Traverses the dataset structure using the specified path +// Returns a reference to the nested folder at the specified path const traverseStructureByPath = (structure, pathToRender) => { + console.log("traverseStructureByPath", structure, pathToRender); let structureRef = structure; pathToRender.forEach((subFolder) => { structureRef = structureRef.folders[subFolder]; @@ -20,16 +24,19 @@ const traverseStructureByPath = (structure, pathToRender) => { return structureRef; }; -// Checks if a folder or its subfolders/files match the search filter +// Determines if a folder or its subfolders/files match the search filter const folderObjMatchesSearch = (folderObj, searchFilter) => { const relativePath = folderObj.relativePath.toLowerCase(); + // Check if the current folder's relative path matches the search filter if (relativePath.includes(searchFilter)) return true; + // Check if any subfolders match the search filter const foldersMatch = Object.values(folderObj.folders || {}).some((subFolder) => folderObjMatchesSearch(subFolder, searchFilter) ); + // Check if any files match the search filter const filesMatch = Object.values(folderObj.files || {}).some((file) => file.relativePath.toLowerCase().includes(searchFilter) ); @@ -37,17 +44,18 @@ const folderObjMatchesSearch = (folderObj, searchFilter) => { return foldersMatch || filesMatch; }; -// Filters the structure based on the search filter +// Filters the dataset structure based on the current search filter const filterStructure = (structure, searchFilter) => { if (!searchFilter) { - // Return the original structure when the filter is empty + // Return the original structure if no search filter is applied return structure; } const lowerCaseSearchFilter = searchFilter.toLowerCase(); + // Recursively prunes the dataset structure to retain only matching folders/files const pruneStructure = (folderObj) => { - // Recursively prune subfolders that do not match the filter + // Remove subfolders that do not match the search filter for (const subFolder of Object.keys(folderObj.folders || {})) { if (!folderObjMatchesSearch(folderObj.folders[subFolder], lowerCaseSearchFilter)) { delete folderObj.folders[subFolder]; @@ -56,43 +64,39 @@ const filterStructure = (structure, searchFilter) => { } } - // Remove files that do not match the filter + // Remove files that do not match the search filter for (const fileName of Object.keys(folderObj.files || {})) { - if (fileName.endsWith(".tiff")) { - console.log("File name:", fileName); - console.log("search filter:", lowerCaseSearchFilter); - console.log( - folderObj.files[fileName].relativePath.toLowerCase().includes(lowerCaseSearchFilter) - ); - } if (!folderObj.files[fileName].relativePath.toLowerCase().includes(lowerCaseSearchFilter)) { delete folderObj.files[fileName]; } } - return folderObj; // Ensure the function returns the modified folderObj + return folderObj; // Return the modified folder object }; - // Deep copy the structure to avoid in-place mutation + // Deep copy the structure to prevent in-place modification const structureCopy = JSON.parse(JSON.stringify(structure)); return pruneStructure(structureCopy); }; -// Sets the dataset structure search filter and updates the render dataset structure +// Updates the dataset search filter and modifies the rendered structure accordingly export const setDatasetstructureSearchFilter = (searchFilter) => { const globalStore = useGlobalStore.getState(); + console.log("Before filter set:", globalStore); - let originalStructure = JSON.parse(JSON.stringify(globalStore.datasetStructureJSONObj)); + // Deep copy the full dataset structure to prevent mutation + const originalStructure = JSON.parse(JSON.stringify(globalStore.datasetStructureJSONObj)); - // Use the helper function to traverse to the correct nested structure + // Get the portion of the structure to filter based on the current path const structureToFilter = traverseStructureByPath(originalStructure, globalStore.pathToRender); + // Apply the search filter to the relevant structure const filteredStructure = filterStructure(structureToFilter, searchFilter); - console.log("Filtered structure result:", filteredStructure); // Check result + console.log("Filtered structure result:", filteredStructure); - // Update the filtered structure in global state + // Update global state with the filtered structure and search filter useGlobalStore.setState({ ...globalStore, datasetStructureSearchFilter: searchFilter, @@ -100,11 +104,12 @@ export const setDatasetstructureSearchFilter = (searchFilter) => { }); }; -// Sets the tree view dataset structure and updates relative paths +// Sets the dataset structure and renders the specified path export const setTreeViewDatasetStructure = (datasetStructure, pathToRender) => { + // Deep copy the dataset structure to prevent mutation const clonedStructure = JSON.parse(JSON.stringify(datasetStructure)); - // Adds relative paths recursively + // Recursively adds relative paths to folders and files in the dataset structure const addRelativePaths = (obj, currentPath = []) => { for (const folderName in obj?.folders || {}) { const folderPath = [...currentPath, folderName].join("/") + "/"; @@ -118,18 +123,22 @@ export const setTreeViewDatasetStructure = (datasetStructure, pathToRender) => { } }; + // Add relative paths to the full dataset structure addRelativePaths(clonedStructure); + // Update the full dataset structure and path in the global store useGlobalStore.setState({ datasetStructureJSONObj: clonedStructure, pathToRender: pathToRender, }); - // Use the helper function to traverse to the correct structure - let renderStructureRef = traverseStructureByPath(clonedStructure, pathToRender); + // Traverse to the folder structure to be rendered + const renderStructureRef = traverseStructureByPath(clonedStructure, pathToRender); + // Add relative paths for the rendered subset addRelativePaths(renderStructureRef, pathToRender); + // Update the rendered structure in the global store useGlobalStore.setState({ renderDatasetStructureJSONObj: renderStructureRef, });