Skip to content

Commit

Permalink
feat(ui-debug): add unsupported files handling
Browse files Browse the repository at this point in the history
  • Loading branch information
hdinia committed Dec 4, 2024
1 parent fe4bf0a commit 645dc44
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 53 deletions.
1 change: 1 addition & 0 deletions webapp/public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions webapp/public/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 ?",
Expand Down
34 changes: 0 additions & 34 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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 <Matrix title={filename} url={filePath} canImport={!canEdit} />;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<string>(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 (
<Flex>
<Menubar>
<Filename>{filename}</Filename>
<UploadFileButton
studyId={studyId}
path={filePath}
accept={{ "text/plain": [".txt"] }}
onUploadSuccessful={handleUploadSuccessful}
/>
<DownloadButton onClick={handleDownload} />
</Menubar>
<EmptyView icon={BlockIcon} title={t("study.debug.file.unsupported")} />
</Flex>
);
}

export default Unsupported;
20 changes: 8 additions & 12 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,40 @@
* 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;
setSelectedFile: (file: FileInfo) => void;
reloadTreeData: () => void;
}

type DataComponent = React.ComponentType<DataCompProps>;

const componentByFileType: Record<FileType, DataComponent> = {
const componentByFileType: Record<FileType, ComponentType<DataCompProps>> = {
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 (
<ViewWrapper>
<DataViewer
{...fileInfo}
studyId={study.id}
canEdit={canEdit}
canEdit={canEditFile(study, fileInfo.filePath)}
setSelectedFile={setSelectedFile}
reloadTreeData={reloadTreeData}
/>
Expand Down
35 changes: 29 additions & 6 deletions webapp/src/components/App/Singlestudy/explore/Debug/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;
Expand All @@ -58,8 +58,8 @@ const iconByFileType: Record<FileType, SvgIconComponent> = {
matrix: DatasetIcon,
json: DataObjectIcon,
text: TextSnippetIcon,
image: ImageIcon,
folder: FolderIcon,
unsupported: BlockIcon,
} as const;

/**
Expand All @@ -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";
}

////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 645dc44

Please sign in to comment.