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

fix(study-tree-ui): fix several bugs and major refactoring #2348

Open
wants to merge 22 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion webapp/public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,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.fetchFolderLoading": "Loading...",
"variants.createNewVariant": "Create new variant",
Expand Down
1 change: 0 additions & 1 deletion webapp/public/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,6 @@
"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.fetchFolderLoading": "Chargement...",
"variants.createNewVariant": "Créer une nouvelle variante",
Expand Down
10 changes: 7 additions & 3 deletions webapp/src/components/App/Studies/StudiesList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { scanFolder } from "../../../../services/api/study";
import useEnqueueErrorSnackbar from "../../../../hooks/useEnqueueErrorSnackbar";
import ConfirmationDialog from "../../../common/dialogs/ConfirmationDialog";
import CheckBoxFE from "@/components/common/fieldEditors/CheckBoxFE";
import { DEFAULT_WORKSPACE_PREFIX, ROOT_FOLDER_NAME } from "@/components/common/utils/constants";

const CARD_TARGET_WIDTH = 500;
const CARD_HEIGHT = 250;
Expand All @@ -87,6 +88,9 @@ function StudiesList(props: StudiesListProps) {
const [selectionMode, setSelectionMode] = useState(false);
const [confirmFolderScan, setConfirmFolderScan] = useState(false);
const [isRecursiveScan, setIsRecursiveScan] = useState(false);
const isInDefaultWorkspace = !!folder && folder.startsWith(DEFAULT_WORKSPACE_PREFIX);
const isRootFolder = folder === ROOT_FOLDER_NAME;
const scanDisabled: boolean = isInDefaultWorkspace || isRootFolder;

useEffect(() => {
setFolderList(folder.split("/"));
Expand Down Expand Up @@ -265,14 +269,14 @@ function StudiesList(props: StudiesListProps) {
</Tooltip>
)}

{folder !== "root" && (
{!scanDisabled && (
<Tooltip title={t("studies.scanFolder") as string}>
<IconButton onClick={() => setConfirmFolderScan(true)}>
<IconButton onClick={() => setConfirmFolderScan(true)} disabled={scanDisabled}>
<RadarIcon />
</IconButton>
</Tooltip>
)}
{folder !== "root" && confirmFolderScan && (
{!isRootFolder && confirmFolderScan && (
<ConfirmationDialog
titleIcon={RadarIcon}
onCancel={() => {
Expand Down
31 changes: 14 additions & 17 deletions webapp/src/components/App/Studies/StudyTree/StudyTreeNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,48 @@
* This file is part of the Antares project.
*/

import { memo, useMemo } from "react";
import { useMemo } from "react";
import * as R from "ramda";
import type { StudyTreeNodeProps } from "./types";
import TreeItemEnhanced from "@/components/common/TreeItemEnhanced";
import { t } from "i18next";

export default memo(function StudyTreeNode({
export default function StudyTreeNode({
studyTreeNode,
parentId,
itemsLoading,
onNodeClick,
}: StudyTreeNodeProps) {
const isLoadingFolder = studyTreeNode.hasChildren && studyTreeNode.children.length === 0;
const id = parentId ? `${parentId}/${studyTreeNode.name}` : studyTreeNode.name;

const isLoadingFolder = itemsLoading.includes(id);
const hasUnloadedChildern = studyTreeNode.hasChildren && studyTreeNode.children.length === 0;
const sortedChildren = useMemo(
() => R.sortBy(R.prop("name"), studyTreeNode.children),
() => R.sortBy(R.compose(R.toLower, R.prop("name")), studyTreeNode.children),
[studyTreeNode.children],
);

if (isLoadingFolder) {
// Either the user clicked on the folder and we need to show the folder is loading
// Or the explorer api says that this folder has children so we need to load at least one element
// so the arrow to explanse the element is displayed which indicate to the user that this is a folder
if (isLoadingFolder || hasUnloadedChildern) {
return (
<TreeItemEnhanced
itemId={id}
label={studyTreeNode.name}
onClick={() => onNodeClick(id, studyTreeNode)}
>
<TreeItemEnhanced itemId={id} label={studyTreeNode.name}>
<TreeItemEnhanced itemId={id + "loading"} label={t("studies.tree.fetchFolderLoading")} />
</TreeItemEnhanced>
);
}

return (
<TreeItemEnhanced
itemId={id}
label={studyTreeNode.name}
onClick={() => onNodeClick(id, studyTreeNode)}
>
<TreeItemEnhanced itemId={id} label={studyTreeNode.name} onClick={() => onNodeClick(id)}>
{sortedChildren.map((child) => (
<StudyTreeNode
key={`${id}/${child.name}`}
studyTreeNode={child}
parentId={id}
itemsLoading={itemsLoading}
onNodeClick={onNodeClick}
/>
))}
</TreeItemEnhanced>
);
});
}
119 changes: 0 additions & 119 deletions webapp/src/components/App/Studies/StudyTree/__test__/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,6 @@
* This file is part of the Antares project.
*/

import { StudyType, type StudyMetadata } from "@/common/types";

function createStudyMetadata(folder: string, workspace: string): StudyMetadata {
return {
id: "test-study-id",
name: "Test Study",
creationDate: "2024-01-01",
modificationDate: "2024-01-02",
owner: { id: 1, name: "Owner 1" },
type: StudyType.RAW,
version: "v1",
workspace,
managed: false,
archived: false,
groups: [],
folder,
publicMode: "NONE",
};
}

export const FIXTURES = {
basicTree: {
name: "Basic tree with single level",
Expand Down Expand Up @@ -229,102 +209,3 @@ export const FIXTURES = {
},
},
};

export const FIXTURES_BUILD_STUDY_TREE = {
simpleCase: {
name: "Basic case",
studies: [createStudyMetadata("studies/team1/myFolder", "workspace")],
expected: {
name: "root",
path: "",
children: [
{
name: "default",
path: "/default",
children: [],
},
{
name: "workspace",
path: "/workspace",
children: [
{
name: "studies",
path: "/workspace/studies",
children: [
{
name: "team1",
path: "/workspace/studies/team1",
children: [],
},
],
},
],
},
],
},
},
multiplieStudies: {
name: "Multiple studies case",
studies: [
createStudyMetadata("studies/team1/study", "workspace"),
createStudyMetadata("studies/team2/study", "workspace"),
createStudyMetadata("studies/team3/study", "workspace"),
createStudyMetadata("archives/team4/study", "workspace2"),
],
expected: {
name: "root",
path: "",
children: [
{
name: "default",
path: "/default",
children: [],
},
{
name: "workspace",
path: "/workspace",
children: [
{
name: "studies",
path: "/workspace/studies",
children: [
{
name: "team1",
path: "/workspace/studies/team1",
children: [],
},
{
name: "team2",
path: "/workspace/studies/team2",
children: [],
},
{
name: "team3",
path: "/workspace/studies/team3",
children: [],
},
],
},
],
},
{
name: "workspace2",
path: "/workspace2",
children: [
{
name: "archives",
path: "/workspace2/archives",
children: [
{
name: "team4",
path: "/workspace2/archives/team4",
children: [],
},
],
},
],
},
],
},
},
};
57 changes: 2 additions & 55 deletions webapp/src/components/App/Studies/StudyTree/__test__/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
* This file is part of the Antares project.
*/

import { FIXTURES, FIXTURES_BUILD_STUDY_TREE } from "./fixtures";
import { buildStudyTree, insertFoldersIfNotExist, insertWorkspacesIfNotExist } from "../utils";
import { FIXTURES } from "./fixtures";
import { insertFoldersIfNotExist } from "../utils";
import type { NonStudyFolderDTO, StudyTreeNode } from "../types";

describe("StudyTree Utils", () => {
Expand Down Expand Up @@ -58,58 +58,5 @@ describe("StudyTree Utils", () => {
const result = insertFoldersIfNotExist(tree, [invalidFolder]);
expect(result).toEqual(tree);
});

test("should handle empty workspaces", () => {
const tree: StudyTreeNode = {
name: "Root",
path: "/",
children: [
{
name: "a",
path: "/a",
children: [{ name: "suba", path: "/a/suba", children: [] }],
},
],
};
const workspaces: string[] = [];
const result = insertWorkspacesIfNotExist(tree, workspaces);
expect(result).toEqual(tree);
});

test("should merge workspaces", () => {
const tree: StudyTreeNode = {
name: "Root",
path: "/",
children: [
{
name: "a",
path: "/a",
children: [{ name: "suba", path: "/a/suba", children: [] }],
},
],
};
const expected: StudyTreeNode = {
name: "Root",
path: "/",
children: [
{
name: "a",
path: "/a",
children: [{ name: "suba", path: "/a/suba", children: [] }],
},
{ name: "workspace1", path: "/workspace1", children: [] },
{ name: "workspace2", path: "/workspace2", children: [] },
],
};

const workspaces = ["a", "workspace1", "workspace2"];
const result = insertWorkspacesIfNotExist(tree, workspaces);
expect(result).toEqual(expected);
});

test.each(Object.values(FIXTURES_BUILD_STUDY_TREE))("$name", ({ studies, expected }) => {
const result = buildStudyTree(studies);
expect(result).toEqual(expected);
});
});
});
Loading
Loading