From 645dc443a72397b94be70b733305f512ba3ebf4c Mon Sep 17 00:00:00 2001 From: hatim dinia Date: Mon, 2 Dec 2024 15:52:05 +0100 Subject: [PATCH] feat(ui-debug): add unsupported files handling --- webapp/public/locales/en/main.json | 1 + webapp/public/locales/fr/main.json | 1 + .../Singlestudy/explore/Debug/Data/Image.tsx | 34 --------- .../Singlestudy/explore/Debug/Data/Matrix.tsx | 2 +- .../explore/Debug/Data/Unsupported.tsx | 75 +++++++++++++++++++ .../Singlestudy/explore/Debug/Data/index.tsx | 20 ++--- .../App/Singlestudy/explore/Debug/utils.ts | 35 +++++++-- 7 files changed, 115 insertions(+), 53 deletions(-) delete mode 100644 webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx create mode 100644 webapp/src/components/App/Singlestudy/explore/Debug/Data/Unsupported.tsx diff --git a/webapp/public/locales/en/main.json b/webapp/public/locales/en/main.json index 952091b0d4..d6bbea522e 100644 --- a/webapp/public/locales/en/main.json +++ b/webapp/public/locales/en/main.json @@ -252,6 +252,7 @@ "study.bindingconstraints": "Binding Constraints", "study.debug": "Debug", "study.debug.file.image": "Image file", + "study.debug.file.unsupported": "Unsupported file type", "study.debug.file.deleteConfirm.title": "Delete File?", "study.debug.file.deleteConfirm.message": "Are you sure you want to delete the file?", "study.debug.folder.empty": "Folder is empty", diff --git a/webapp/public/locales/fr/main.json b/webapp/public/locales/fr/main.json index 81ffca6679..9ddb68910e 100644 --- a/webapp/public/locales/fr/main.json +++ b/webapp/public/locales/fr/main.json @@ -253,6 +253,7 @@ "study.debug": "Debug", "study.debug.file.image": "Fichier image", "study.debug.folder.empty": "Le dossier est vide", + "study.debug.file.unsupported": "Type de fichier non supporté", "study.debug.file.deleteConfirm.title": "Supprimer le fichier ?", "study.debug.file.deleteConfirm.message": "Êtes-vous sûr de vouloir supprimer le fichier ?", "study.debug.folder.upload.replaceFileConfirm.title": "Remplacer le fichier ?", diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx deleted file mode 100644 index 23aa34e993..0000000000 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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 { useTranslation } from "react-i18next"; -import EmptyView from "../../../../../common/page/SimpleContent"; -import ImageIcon from "@mui/icons-material/Image"; -import { Filename, Flex, Menubar } from "./styles"; -import type { DataCompProps } from "../utils"; - -function Image({ filename }: DataCompProps) { - const { t } = useTranslation(); - - return ( - - - {filename} - - - - ); -} - -export default Image; diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Matrix.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Matrix.tsx index a140fe71e8..26a211251d 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Matrix.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Matrix.tsx @@ -15,7 +15,7 @@ import Matrix from "../../../../../common/Matrix"; import type { DataCompProps } from "../utils"; -function DebugMatrix({ studyId, filename, filePath, canEdit }: DataCompProps) { +function DebugMatrix({ filename, filePath, canEdit }: DataCompProps) { return ; } diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Unsupported.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Unsupported.tsx new file mode 100644 index 0000000000..59c4f48950 --- /dev/null +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Unsupported.tsx @@ -0,0 +1,75 @@ +/** + * 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 { useTranslation } from "react-i18next"; +import EmptyView from "../../../../../common/page/SimpleContent"; +import BlockIcon from "@mui/icons-material/Block"; +import { Filename, Flex, Menubar } from "./styles"; +import type { DataCompProps } from "../utils"; +import DownloadButton from "@/components/common/buttons/DownloadButton"; +import UploadFileButton from "@/components/common/buttons/UploadFileButton"; +import usePromiseWithSnackbarError from "@/hooks/usePromiseWithSnackbarError"; +import { getStudyData } from "@/services/api/study"; +import { downloadFile } from "@/utils/fileUtils"; + +function Unsupported({ studyId, filePath, filename }: DataCompProps) { + const { t } = useTranslation(); + + const res = usePromiseWithSnackbarError( + () => getStudyData(studyId, filePath), + { + errorMessage: t("studies.error.retrieveData"), + deps: [studyId, filePath], + }, + ); + + //////////////////////////////////////////////////////////////// + // Event Handlers + //////////////////////////////////////////////////////////////// + + const handleDownload = () => { + if (res.data) { + downloadFile( + res.data, + filename.endsWith(".txt") ? filename : `${filename}.txt`, + ); + } + }; + + const handleUploadSuccessful = () => { + res.reload(); + }; + + //////////////////////////////////////////////////////////////// + // JSX + //////////////////////////////////////////////////////////////// + + return ( + + + {filename} + + + + + + ); +} + +export default Unsupported; diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/index.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/index.tsx index f387b7ef9c..de7e0ca24e 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/index.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/index.tsx @@ -12,15 +12,16 @@ * This file is part of the Antares project. */ +import { ComponentType } from "react"; import Text from "./Text"; -import Image from "./Image"; -import Json from "./Json"; +import Unsupported from "./Unsupported"; import Matrix from "./Matrix"; import Folder from "./Folder"; import { canEditFile, type FileInfo, type FileType } from "../utils"; import type { DataCompProps } from "../utils"; import ViewWrapper from "../../../../../common/page/ViewWrapper"; import type { StudyMetadata } from "../../../../../../common/types"; +import Json from "./Json"; interface Props extends FileInfo { study: StudyMetadata; @@ -28,28 +29,23 @@ interface Props extends FileInfo { reloadTreeData: () => void; } -type DataComponent = React.ComponentType; - -const componentByFileType: Record = { +const componentByFileType: Record> = { matrix: Matrix, json: Json, text: Text, - image: Image, + unsupported: Unsupported, folder: Folder, } as const; -function Data(props: Props) { - const { study, setSelectedFile, reloadTreeData, ...fileInfo } = props; - const { fileType, filePath } = fileInfo; - const canEdit = canEditFile(study, filePath); - const DataViewer = componentByFileType[fileType]; +function Data({ study, setSelectedFile, reloadTreeData, ...fileInfo }: Props) { + const DataViewer = componentByFileType[fileInfo.fileType]; return ( diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/utils.ts b/webapp/src/components/App/Singlestudy/explore/Debug/utils.ts index b1d8653f07..d192aad6d9 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/utils.ts +++ b/webapp/src/components/App/Singlestudy/explore/Debug/utils.ts @@ -14,7 +14,7 @@ import DataObjectIcon from "@mui/icons-material/DataObject"; import TextSnippetIcon from "@mui/icons-material/TextSnippet"; -import ImageIcon from "@mui/icons-material/Image"; +import BlockIcon from "@mui/icons-material/Block"; import FolderIcon from "@mui/icons-material/Folder"; import DatasetIcon from "@mui/icons-material/Dataset"; import { SvgIconComponent } from "@mui/icons-material"; @@ -33,7 +33,7 @@ export interface TreeFolder { export type TreeData = TreeFolder | TreeFile; -export type FileType = "json" | "matrix" | "text" | "image" | "folder"; +export type FileType = "json" | "matrix" | "text" | "folder" | "unsupported"; export interface FileInfo { fileType: FileType; @@ -58,8 +58,8 @@ const iconByFileType: Record = { matrix: DatasetIcon, json: DataObjectIcon, text: TextSnippetIcon, - image: ImageIcon, folder: FolderIcon, + unsupported: BlockIcon, } as const; /** @@ -83,21 +83,44 @@ export function isFolder(treeData: TreeData): treeData is TreeFolder { * @returns The corresponding file type. */ export function getFileType(treeData: TreeData): FileType { + if (isFolder(treeData)) { + return "folder"; + } + if (typeof treeData === "string") { + // Handle matrix files if ( treeData.startsWith("matrix://") || treeData.startsWith("matrixfile://") ) { return "matrix"; } + + // Handle files displayed as JSON by the API even though they are .ini files in the filesystem. + // The json:// prefix or .json extension indicates the content should be viewed as JSON. if (treeData.startsWith("json://") || treeData.endsWith(".json")) { return "json"; } - if (treeData.startsWith("file://") && treeData.endsWith(".ico")) { - return "image"; + + // Handle regular files with file:// prefix + // All files except matrices and json-formatted content use this prefix + // We filter to only allow extensions that can be properly displayed (.txt, .log, .csv, .tsv, .ini) + // Other extensions (like .RDS or .xlsx) are marked as unsupported since they can't be shown in the UI + if (treeData.startsWith("file://")) { + const supportedTextExtensions = [".txt", ".log", ".csv", ".tsv", ".ini"]; + + // Check if the file ends with any of the supported extensions + if (supportedTextExtensions.some((ext) => treeData.endsWith(ext))) { + return "text"; + } + + // Any other extension with file:// prefix is unsupported + return "unsupported"; } } - return isFolder(treeData) ? "folder" : "text"; + + // Default to text for any other string content + return "text"; } ////////////////////////////////////////////////////////////////