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

feat(ui-studies): add on click fetch and display list of non studies folder #2224

Merged
merged 44 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
077feeb
feat(ui): add on click fetch and display list of non studies folder
Nov 14, 2024
3860608
refactor(ui): fix build to pass npm lint add docs
Nov 14, 2024
fe91d5a
refactor(ui): make npm lint pass
Nov 14, 2024
37bb38e
refactor(ui): make npm lint pass
Nov 14, 2024
4d8db33
refactor(ui): move files, better naming
Nov 18, 2024
65b8d8e
refactor(ui): wip, add snack bar error alert for failed path load, re…
Nov 19, 2024
ea5950f
feat(ui): add workspace merge + optimize folder merge
Nov 20, 2024
c70db00
fix(ui): fix build
Nov 20, 2024
360cd2d
fix(ui): fix build for real
Nov 20, 2024
10a7223
refactor(ui): refactor some test + ui
Nov 20, 2024
8bc6882
refactor(ui): refactor some test + ui
Nov 20, 2024
3c3e76b
fix(ui): fix build
Nov 20, 2024
ed08ddc
refactor(ui): remove useless code, add doc, better naming
Nov 20, 2024
968060d
fix(ui): fix tests
Nov 20, 2024
ee8bc0e
feat(ui): handle click on root
Nov 20, 2024
f946e45
refactor(ui): add docs, renaming
Nov 21, 2024
fb0da14
fix(ui): fis bug first level of folder wasn't initialized
Nov 21, 2024
b68b992
refactor(ui): make more modular
Nov 22, 2024
9c995c6
refactor(ui): use i18n, make code more functionnal style
Nov 22, 2024
10926f6
feat(explorer): add parent path field, rename Dto object
Nov 22, 2024
5469e62
refactor(explorer): better doc string
Nov 22, 2024
38d606c
refactor(ui): adapt to new backend format
Nov 22, 2024
f8521dc
fix(ui): over escaped special charachters
Nov 22, 2024
a7b1b97
fix(explorer): fix build
Nov 22, 2024
74a47c4
fix(ui): fix build
Nov 22, 2024
16283c9
fix(ui): fix build
Nov 22, 2024
54177b8
feat(ui): make the scan non recursive by defaul, add an option for re…
Nov 28, 2024
72e4e8f
fix(ui): fix build npm lint
Nov 28, 2024
4442a5f
fix(ui): fix build
Nov 28, 2024
6612892
fix(ui): fix nonense tooltip messsage
Nov 28, 2024
fc19796
fix(ui): fix build
Nov 28, 2024
e54429f
fix(ui): fix build
Nov 28, 2024
eb1a170
refactor(ui): better naming and messages
Dec 3, 2024
e24f1da
refactor(ui): refactor duplicate code and fix style
Dec 5, 2024
b59eb6f
fix(ui): fix build
Dec 5, 2024
474169b
refactor(ui): move code into clean sections
Dec 6, 2024
d1fb134
refactor(ui): move test for study tree in their own folder
Dec 11, 2024
dfe103c
refactor(ui): remove useless await
Dec 17, 2024
763ea55
Merge branch 'dev' into feature/615-optimize-listing-studies
Dec 17, 2024
8361ec5
fix(build): add forgotten file
Dec 17, 2024
ab26401
Merge branch 'dev' into feature/615-optimize-listing-studies
Dec 18, 2024
b8ab1f7
feat(ui): fetch current folder and not only children
Dec 18, 2024
03c9ef0
refactor(ui): add docs
Dec 18, 2024
442cd41
refactor(ui): small refactor
Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 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, field_validator
from pydantic import BeforeValidator, PlainSerializer, computed_field, field_validator
from sqlalchemy import ( # type: ignore
Boolean,
Column,
Expand Down Expand Up @@ -323,7 +323,7 @@ class StudyFolder:
groups: t.List[Group]


class NonStudyFolder(AntaresBaseModel):
class NonStudyFolderDTO(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,6 +333,19 @@ class NonStudyFolder(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, NonStudyFolder, WorkspaceMetadata
from antarest.study.model import DEFAULT_WORKSPACE_NAME, NonStudyFolderDTO, 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[NonStudyFolder]:
) -> List[NonStudyFolderDTO]:
"""
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(NonStudyFolder(path=child_rel_path, workspace=workspace_name, name=child.name))
directories.append(NonStudyFolderDTO(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 NonStudyFolder, WorkspaceMetadata
from antarest.study.model import NonStudyFolderDTO, 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[NonStudyFolder],
response_model=List[NonStudyFolderDTO],
)
def list_dir(
workspace: str,
path: str,
current_user: JWTUser = Depends(auth.get_current_user),
) -> List[NonStudyFolder]:
) -> List[NonStudyFolderDTO]:
"""
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 NonStudyFolder, WorkspaceMetadata
from antarest.study.model import NonStudyFolderDTO, 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 = [NonStudyFolder(**d) for d in directories_res]
directories_res = [NonStudyFolderDTO(**d) for d in directories_res]
directorires_expected = [
NonStudyFolder(
NonStudyFolderDTO(
path=Path("folder/trash"),
workspace="ext",
name="trash",
Expand Down
12 changes: 5 additions & 7 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, NonStudyFolder, WorkspaceMetadata
from antarest.study.model import DEFAULT_WORKSPACE_NAME, NonStudyFolderDTO, WorkspaceMetadata
from antarest.study.storage.explorer_service import Explorer


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

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


@pytest.mark.unit_test
Expand All @@ -95,11 +94,10 @@ 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 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
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


@pytest.mark.unit_test
Expand Down
5 changes: 5 additions & 0 deletions webapp/public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,9 @@
"studies.copySuffix": "Copy",
"studies.folder": "Folder",
"studies.filters.strictfolder": "Show only direct folder children",
"studies.filters.showAllDescendants": "Show all children",
hdinia marked this conversation as resolved.
Show resolved Hide resolved
"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 @@ -669,6 +671,9 @@
"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: 5 additions & 1 deletion webapp/public/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,9 @@
"studies.copySuffix": "Copie",
"studies.folder": "Dossier",
"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 @@ -668,7 +670,9 @@
"studies.exportOutput": "Exporter une sortie",
"studies.exportOutputFilter": "Exporter une sortie filtrée",
"studies.selectOutput": "Selectionnez une sortie",
"studies.variant": "Variante",
Copy link
Member

Choose a reason for hiding this comment

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

Remove also the key in the english file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it was a duplicate in tis file or something

"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",
"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 "./StudyTree";
import StudyTree from "@/components/App/Studies/StudyTree";
import useAppSelector from "../../../redux/hooks/useAppSelector";
import { getFavoriteStudies } from "../../../redux/selectors";

Expand Down
44 changes: 34 additions & 10 deletions webapp/src/components/App/Studies/StudiesList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ 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 FolderOffIcon from "@mui/icons-material/FolderOff";
import FolderIcon from "@mui/icons-material/Folder";
import AccountTreeIcon from "@mui/icons-material/AccountTree";
import RadarIcon from "@mui/icons-material/Radar";
import { FixedSizeGrid, GridOnScrollProps } from "react-window";
import { v4 as uuidv4 } from "uuid";
Expand Down Expand Up @@ -64,6 +65,7 @@ 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 @@ -91,6 +93,7 @@ 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,13 +162,18 @@ function StudiesList(props: StudiesListProps) {
try {
// Remove "/root" from the path
const folder = folderList.slice(1).join("/");
await scanFolder(folder);
await scanFolder(folder, isRecursiveScan);
setConfirmFolderScan(false);
setIsRecursiveScan(false);
} catch (e) {
enqueueErrorSnackbar(t("studies.error.scanFolder"), e as AxiosError);
}
};

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

////////////////////////////////////////////////////////////////
// Utils
////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -252,13 +260,21 @@ function StudiesList(props: StudiesListProps) {
<Typography mx={2} sx={{ color: "white" }}>
({`${studyIds.length} ${t("global.studies").toLowerCase()}`})
</Typography>
<Tooltip title={t("studies.filters.strictfolder") as string}>
<IconButton onClick={toggleStrictFolder}>
<FolderOffIcon
color={strictFolderFilter ? "secondary" : "disabled"}
/>
</IconButton>
</Tooltip>

{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>
)}

{folder !== "root" && (
<Tooltip title={t("studies.scanFolder") as string}>
<IconButton onClick={() => setConfirmFolderScan(true)}>
Expand All @@ -269,12 +285,20 @@ function StudiesList(props: StudiesListProps) {
{folder !== "root" && confirmFolderScan && (
<ConfirmationDialog
titleIcon={RadarIcon}
onCancel={() => setConfirmFolderScan(false)}
onCancel={() => {
setConfirmFolderScan(false);
setIsRecursiveScan(false);
}}
onConfirm={handleFolderScan}
alert="warning"
open
>
{`${t("studies.scanFolder")} ${folder}?`}
<CheckBoxFE
label={t("studies.requestDeepScan")}
value={isRecursiveScan}
onChange={handleRecursiveScan}
/>
</ConfirmationDialog>
)}
</Box>
Expand Down
70 changes: 0 additions & 70 deletions webapp/src/components/App/Studies/StudyTree.tsx

This file was deleted.

Loading
Loading