Skip to content

Commit

Permalink
Revert "feat(ui-studies): add on click fetch and display list of non …
Browse files Browse the repository at this point in the history
…studies folder (#2224)"

This reverts commit 763f370.
  • Loading branch information
skamril committed Dec 20, 2024
1 parent d8df7e9 commit 4b68b03
Show file tree
Hide file tree
Showing 17 changed files with 110 additions and 750 deletions.
17 changes: 2 additions & 15 deletions antarest/study/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from pathlib import Path

from antares.study.version import StudyVersion
from pydantic import BeforeValidator, PlainSerializer, computed_field, field_validator
from pydantic import BeforeValidator, PlainSerializer, field_validator
from sqlalchemy import ( # type: ignore
Boolean,
Column,
Expand Down Expand Up @@ -323,7 +323,7 @@ class StudyFolder:
groups: t.List[Group]


class NonStudyFolderDTO(AntaresBaseModel):
class NonStudyFolder(AntaresBaseModel):
"""
DTO used by the explorer to list directories that aren't studies directory, this will be usefull for the front
so the user can navigate in the hierarchy
Expand All @@ -333,19 +333,6 @@ class NonStudyFolderDTO(AntaresBaseModel):
workspace: str
name: str

@computed_field(alias="parentPath")
def parent_path(self) -> Path:
"""
This computed field is convenient for the front.
This field is also aliased as parentPath to match the front-end naming convention.
Returns: the parent path of the current directory. Starting with the workspace as a root directory (we want /workspafe/folder1/sub... and not workspace/folder1/fsub... ).
"""
workspace_path = Path(f"/{self.workspace}")
full_path = workspace_path.joinpath(self.path)
return full_path.parent


class WorkspaceMetadata(AntaresBaseModel):
"""
Expand Down
6 changes: 3 additions & 3 deletions antarest/study/storage/explorer_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from typing import List

from antarest.core.config import Config
from antarest.study.model import DEFAULT_WORKSPACE_NAME, NonStudyFolderDTO, WorkspaceMetadata
from antarest.study.model import DEFAULT_WORKSPACE_NAME, NonStudyFolder, WorkspaceMetadata
from antarest.study.storage.utils import (
get_folder_from_workspace,
get_workspace_from_config,
Expand All @@ -33,7 +33,7 @@ def list_dir(
self,
workspace_name: str,
workspace_directory_path: str,
) -> List[NonStudyFolderDTO]:
) -> List[NonStudyFolder]:
"""
return a list of all directories under workspace_directory_path, that aren't studies.
"""
Expand All @@ -44,7 +44,7 @@ def list_dir(
if child.is_dir() and not is_study_folder(child) and not should_ignore_folder_for_scan(child):
# we don't want to expose the full absolute path on the server
child_rel_path = child.relative_to(workspace.path)
directories.append(NonStudyFolderDTO(path=child_rel_path, workspace=workspace_name, name=child.name))
directories.append(NonStudyFolder(path=child_rel_path, workspace=workspace_name, name=child.name))
return directories

def list_workspaces(
Expand Down
6 changes: 3 additions & 3 deletions antarest/study/web/explorer_blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from antarest.core.config import Config
from antarest.core.jwt import JWTUser
from antarest.login.auth import Auth
from antarest.study.model import NonStudyFolderDTO, WorkspaceMetadata
from antarest.study.model import NonStudyFolder, WorkspaceMetadata
from antarest.study.storage.explorer_service import Explorer

logger = logging.getLogger(__name__)
Expand All @@ -40,13 +40,13 @@ def create_explorer_routes(config: Config, explorer: Explorer) -> APIRouter:
@bp.get(
"/explorer/{workspace}/_list_dir",
summary="For a given directory, list sub directories that aren't studies",
response_model=List[NonStudyFolderDTO],
response_model=List[NonStudyFolder],
)
def list_dir(
workspace: str,
path: str,
current_user: JWTUser = Depends(auth.get_current_user),
) -> List[NonStudyFolderDTO]:
) -> List[NonStudyFolder]:
"""
Endpoint to list sub directories of a given directory
Args:
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/explorer_blueprint/test_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import pytest
from starlette.testclient import TestClient

from antarest.study.model import NonStudyFolderDTO, WorkspaceMetadata
from antarest.study.model import NonStudyFolder, WorkspaceMetadata

BAD_REQUEST_STATUS_CODE = 400
# Status code for directory listing with invalid parameters
Expand Down Expand Up @@ -65,9 +65,9 @@ def test_explorer(client: TestClient, admin_access_token: str, study_tree: Path)
)
res.raise_for_status()
directories_res = res.json()
directories_res = [NonStudyFolderDTO(**d) for d in directories_res]
directories_res = [NonStudyFolder(**d) for d in directories_res]
directorires_expected = [
NonStudyFolderDTO(
NonStudyFolder(
path=Path("folder/trash"),
workspace="ext",
name="trash",
Expand Down
12 changes: 7 additions & 5 deletions tests/storage/business/test_explorer_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import pytest

from antarest.core.config import Config, StorageConfig, WorkspaceConfig
from antarest.study.model import DEFAULT_WORKSPACE_NAME, NonStudyFolderDTO, WorkspaceMetadata
from antarest.study.model import DEFAULT_WORKSPACE_NAME, NonStudyFolder, WorkspaceMetadata
from antarest.study.storage.explorer_service import Explorer


Expand Down Expand Up @@ -85,7 +85,8 @@ def test_list_dir_empty_string(config_scenario_a: Config):
result = explorer.list_dir("diese", "")

assert len(result) == 1
assert result[0] == NonStudyFolderDTO(path=Path("folder"), workspace="diese", name="folder")
workspace_path = config_scenario_a.get_workspace_path(workspace="diese")
assert result[0] == NonStudyFolder(path=Path("folder"), workspace="diese", name="folder")


@pytest.mark.unit_test
Expand All @@ -94,10 +95,11 @@ def test_list_dir_several_subfolders(config_scenario_a: Config):
result = explorer.list_dir("diese", "folder")

assert len(result) == 3
workspace_path = config_scenario_a.get_workspace_path(workspace="diese")
folder_path = Path("folder")
assert NonStudyFolderDTO(path=(folder_path / "subfolder1"), workspace="diese", name="subfolder1") in result
assert NonStudyFolderDTO(path=(folder_path / "subfolder2"), workspace="diese", name="subfolder2") in result
assert NonStudyFolderDTO(path=(folder_path / "subfolder3"), workspace="diese", name="subfolder3") in result
assert NonStudyFolder(path=(folder_path / "subfolder1"), workspace="diese", name="subfolder1") in result
assert NonStudyFolder(path=(folder_path / "subfolder2"), workspace="diese", name="subfolder2") in result
assert NonStudyFolder(path=(folder_path / "subfolder3"), workspace="diese", name="subfolder3") in result


@pytest.mark.unit_test
Expand Down
5 changes: 0 additions & 5 deletions webapp/public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -642,9 +642,7 @@
"studies.studylaunched": "{{studyname}} launched!",
"studies.copySuffix": "Copy",
"studies.filters.strictfolder": "Show only direct folder children",
"studies.filters.showAllDescendants": "Show all children",
"studies.scanFolder": "Scan folder",
"studies.requestDeepScan": "Recursive scan",
"studies.moveStudy": "Move",
"studies.movefolderplaceholder": "Path separated by '/'",
"studies.importcopy": "Copy to database",
Expand Down Expand Up @@ -676,9 +674,6 @@
"studies.exportOutputFilter": "Export filtered output",
"studies.selectOutput": "Select an output",
"studies.variant": "Variant",
"studies.tree.error.failToFetchWorkspace": "Failed to load workspaces",
"studies.tree.error.failToFetchFolder": "Failed to load subfolders for {{path}}",
"studies.tree.error.detailsInConsole": "Details logged in the console",
"variants.createNewVariant": "Create new variant",
"variants.newVariant": "New variant",
"variants.newCommand": "Add new command",
Expand Down
6 changes: 1 addition & 5 deletions webapp/public/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -642,9 +642,7 @@
"studies.studylaunched": "{{studyname}} lancé(s) !",
"studies.copySuffix": "Copie",
"studies.filters.strictfolder": "Afficher uniquement les descendants directs",
"studies.filters.showAllDescendants": "Voir les sous-dossiers",
"studies.scanFolder": "Scanner le dossier",
"studies.requestDeepScan": "Scan récursif",
"studies.moveStudy": "Déplacer",
"studies.movefolderplaceholder": "Chemin séparé par des '/'",
"studies.importcopy": "Copier en base",
Expand Down Expand Up @@ -675,9 +673,7 @@
"studies.exportOutput": "Exporter une sortie",
"studies.exportOutputFilter": "Exporter une sortie filtrée",
"studies.selectOutput": "Selectionnez une sortie",
"studies.tree.error.failToFetchWorkspace": "Échec lors de la récupération de l'espace de travail",
"studies.tree.error.failToFetchFolder": "Échec lors de la récupération des sous dossiers de {{path}}",
"studies.tree.error.detailsInConsole": "Détails de l'érreur dans la console",
"studies.variant": "Variante",
"variants.createNewVariant": "Créer une nouvelle variante",
"variants.newVariant": "Nouvelle variante",
"variants.newCommand": "Ajouter une nouvelle commande",
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/App/Studies/SideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useNavigate } from "react-router";
import { Box, Typography, List, ListItem, ListItemText } from "@mui/material";
import { useTranslation } from "react-i18next";
import { STUDIES_SIDE_NAV_WIDTH } from "../../../theme";
import StudyTree from "@/components/App/Studies/StudyTree";
import StudyTree from "./StudyTree";
import useAppSelector from "../../../redux/hooks/useAppSelector";
import { getFavoriteStudies } from "../../../redux/selectors";

Expand Down
44 changes: 10 additions & 34 deletions webapp/src/components/App/Studies/StudiesList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ import AutoSizer from "react-virtualized-auto-sizer";
import HomeIcon from "@mui/icons-material/Home";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import FolderIcon from "@mui/icons-material/Folder";
import AccountTreeIcon from "@mui/icons-material/AccountTree";
import FolderOffIcon from "@mui/icons-material/FolderOff";
import RadarIcon from "@mui/icons-material/Radar";
import { FixedSizeGrid, GridOnScrollProps } from "react-window";
import { v4 as uuidv4 } from "uuid";
Expand Down Expand Up @@ -62,7 +61,6 @@ import RefreshButton from "../RefreshButton";
import { scanFolder } from "../../../../services/api/study";
import useEnqueueErrorSnackbar from "../../../../hooks/useEnqueueErrorSnackbar";
import ConfirmationDialog from "../../../common/dialogs/ConfirmationDialog";
import CheckBoxFE from "@/components/common/fieldEditors/CheckBoxFE";

const CARD_TARGET_WIDTH = 500;
const CARD_HEIGHT = 250;
Expand Down Expand Up @@ -90,7 +88,6 @@ function StudiesList(props: StudiesListProps) {
const [selectedStudies, setSelectedStudies] = useState<string[]>([]);
const [selectionMode, setSelectionMode] = useState(false);
const [confirmFolderScan, setConfirmFolderScan] = useState<boolean>(false);
const [isRecursiveScan, setIsRecursiveScan] = useState<boolean>(false);

useEffect(() => {
setFolderList(folder.split("/"));
Expand Down Expand Up @@ -159,18 +156,13 @@ function StudiesList(props: StudiesListProps) {
try {
// Remove "/root" from the path
const folder = folderList.slice(1).join("/");
await scanFolder(folder, isRecursiveScan);
await scanFolder(folder);
setConfirmFolderScan(false);
setIsRecursiveScan(false);
} catch (e) {
enqueueErrorSnackbar(t("studies.error.scanFolder"), e as AxiosError);
}
};

const handleRecursiveScan = () => {
setIsRecursiveScan(!isRecursiveScan);
};

////////////////////////////////////////////////////////////////
// Utils
////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -257,21 +249,13 @@ function StudiesList(props: StudiesListProps) {
<Typography mx={2} sx={{ color: "white" }}>
({`${studyIds.length} ${t("global.studies").toLowerCase()}`})
</Typography>

{strictFolderFilter ? (
<Tooltip title={t("studies.filters.strictfolder")}>
<IconButton onClick={toggleStrictFolder}>
<FolderIcon color="secondary" />
</IconButton>
</Tooltip>
) : (
<Tooltip title={t("studies.filters.showAllDescendants")}>
<IconButton onClick={toggleStrictFolder}>
<AccountTreeIcon color="secondary" />
</IconButton>
</Tooltip>
)}

<Tooltip title={t("studies.filters.strictfolder") as string}>
<IconButton onClick={toggleStrictFolder}>
<FolderOffIcon
color={strictFolderFilter ? "secondary" : "disabled"}
/>
</IconButton>
</Tooltip>
{folder !== "root" && (
<Tooltip title={t("studies.scanFolder") as string}>
<IconButton onClick={() => setConfirmFolderScan(true)}>
Expand All @@ -282,20 +266,12 @@ function StudiesList(props: StudiesListProps) {
{folder !== "root" && confirmFolderScan && (
<ConfirmationDialog
titleIcon={RadarIcon}
onCancel={() => {
setConfirmFolderScan(false);
setIsRecursiveScan(false);
}}
onCancel={() => setConfirmFolderScan(false)}
onConfirm={handleFolderScan}
alert="warning"
open
>
{`${t("studies.scanFolder")} ${folder}?`}
<CheckBoxFE
label={t("studies.requestDeepScan")}
value={isRecursiveScan}
onChange={handleRecursiveScan}
/>
</ConfirmationDialog>
)}
</Box>
Expand Down
77 changes: 77 additions & 0 deletions webapp/src/components/App/Studies/StudyTree.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2024, RTE (https://www.rte-france.com)
*
* See AUTHORS.txt
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*
* This file is part of the Antares project.
*/

import { StudyTreeNode } from "./utils";
import useAppSelector from "../../../redux/hooks/useAppSelector";
import { getStudiesTree, getStudyFilters } from "../../../redux/selectors";
import useAppDispatch from "../../../redux/hooks/useAppDispatch";
import { updateStudyFilters } from "../../../redux/ducks/studies";
import TreeItemEnhanced from "../../common/TreeItemEnhanced";
import { SimpleTreeView } from "@mui/x-tree-view/SimpleTreeView";
import { getParentPaths } from "../../../utils/pathUtils";
import * as R from "ramda";

function StudyTree() {
const folder = useAppSelector((state) => getStudyFilters(state).folder, R.T);
const studiesTree = useAppSelector(getStudiesTree);
const dispatch = useAppDispatch();

////////////////////////////////////////////////////////////////
// Event Handlers
////////////////////////////////////////////////////////////////

const handleTreeItemClick = (itemId: string) => {
dispatch(updateStudyFilters({ folder: itemId }));
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////

const buildTree = (children: StudyTreeNode[], parentId?: string) => {
return children.map((child) => {
const id = parentId ? `${parentId}/${child.name}` : child.name;

return (
<TreeItemEnhanced
key={id}
itemId={id}
label={child.name}
onClick={() => handleTreeItemClick(id)}
>
{buildTree(child.children, id)}
</TreeItemEnhanced>
);
});
};

return (
<SimpleTreeView
defaultExpandedItems={[...getParentPaths(folder), folder]}
defaultSelectedItems={folder}
sx={{
flexGrow: 1,
height: 0,
overflowY: "auto",
overflowX: "hidden",
width: 1,
py: 1,
}}
>
{buildTree([studiesTree])}
</SimpleTreeView>
);
}

export default StudyTree;
Loading

0 comments on commit 4b68b03

Please sign in to comment.