Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
skamril committed Sep 15, 2024
1 parent 4aa068a commit ddf1368
Show file tree
Hide file tree
Showing 17 changed files with 398 additions and 121 deletions.
4 changes: 3 additions & 1 deletion webapp/public/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"global.archive": "Archive",
"global.unarchive": "Unarchive",
"global.export": "Export",
"global.export.error": "Export failed",
"global.filter": "Filter",
"global.apply": "Apply",
"global.change": "Change",
Expand All @@ -34,6 +35,8 @@
"global.import": "Import",
"global.import.fromFile": "From a file",
"global.import.fromDatabase": "From database",
"global.import.success": "Import successful",
"global.import.error": "Import failed",
"global.launch": "Launch",
"global.jobs": "Jobs",
"global.unknown": "Unknown",
Expand All @@ -49,7 +52,6 @@
"global.emptyString": "Empty string",
"global.edit": "Edit",
"global.download": "Download",
"global.download.error": "Download failed",
"global.generate": "Generate",
"global.user": "User",
"global.users": "Users",
Expand Down
6 changes: 4 additions & 2 deletions webapp/public/locales/fr/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"global.archive": "Archiver",
"global.unarchive": "Désarchiver",
"global.export": "Exporter",
"global.export.error": "L'export a échoué",
"global.filter": "Filtrer",
"global.apply": "Appliquer",
"global.change": "Changer",
Expand All @@ -34,6 +35,8 @@
"global.import": "Importer",
"global.import.fromFile": "Depuis un fichier",
"global.import.fromDatabase": "Depuis la base de donnée",
"global.import.success": "Importation réussie",
"global.import.error": "Échec de l'importation",
"global.launch": "Lancer",
"global.jobs": "Tâches",
"global.unknown": "Inconnu",
Expand All @@ -49,7 +52,6 @@
"global.emptyString": "Chaine de caractères vide",
"global.edit": "Editer",
"global.download": "Télécharger",
"global.download.error": "Le téléchargement a échoué",
"global.generate": "Générer",
"global.user": "Utilisateur",
"global.users": "Utilisateurs",
Expand Down Expand Up @@ -755,7 +757,7 @@
"data.message.uploadHelp": "Le fichier doit être une matrice simple ou un zip contenant à plat des fichiers de matrices",
"results.error.jobs": "Erreur lors de la récupération des tâches de lancement",
"results.error.outputs": "Erreur lors de la récupération des sorties de l'étude",
"results.noOutputs": "Aucune sorties",
"results.noOutputs": "Aucune sortie",
"results.question.deleteOutput": "Êtes-vous sûr de vouloir supprimer le résultat de simulation {{outputname}} ?",
"tableMode.type.areas": "Zones",
"tableMode.type.links": "Liens",
Expand Down
177 changes: 131 additions & 46 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Folder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,144 @@ import {
type TreeFolder,
type DataCompProps,
} from "../utils";
import { Fragment } from "react";
import { Fragment, useRef, useState } from "react";
import EmptyView from "../../../../../common/page/SimpleContent";
import { useTranslation } from "react-i18next";
import { Filename, Menubar } from "./styles";
import UploadFileButton from "../../../../../common/buttons/UploadFileButton";
import ConfirmationDialog from "../../../../../common/dialogs/ConfirmationDialog";
import { voidFn } from "../../../../../../utils/fnUtils";

function usePromiseObject<T = void>() {
const [isPending, setIsPending] = useState(false);
const resolveRef = useRef(voidFn<[T]>);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const rejectRef = useRef(voidFn<Partial<[any]>>);

const init = () => {
setIsPending(true);

return new Promise<T>((resolve, reject) => {
resolveRef.current = (value: T) => {
resolve(value);
setIsPending(false);
};
rejectRef.current = (reason) => {
reject(reason);
setIsPending(false);
};
});
};

return {
init,
isPending,
resolve: resolveRef.current,
reject: rejectRef.current,
};
}

function Folder(props: DataCompProps) {
const {
filename,
filePath,
treeData,
enableImport,
setSelectedFile,
reloadTreeData,
studyId,
} = props;

function Folder({
filename,
filePath,
treeData,
setSelectedFile,
}: DataCompProps) {
const { t } = useTranslation();
const list = Object.entries(treeData as TreeFolder);
const replaceFileConfirm = usePromiseObject();
const treeFolder = treeData as TreeFolder;
const list = Object.entries(treeFolder);

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

const handleValidateUpload = (file: File) => {
if (treeFolder[file.name]) {
return replaceFileConfirm
.init()
.then(() => true)
.catch(() => false);
}
};

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

return (
<List
subheader={<ListSubheader>{filename}</ListSubheader>}
sx={{
height: 1,
overflow: "auto",
}}
dense
>
{list.length > 0 ? (
list.map(([filename, data], index, arr) => {
const fileType = getFileType(data);
const Icon = getFileIcon(fileType);
const isLast = index === arr.length - 1;
<>
<List
subheader={
<ListSubheader>
<Menubar>
<Filename>{filename}</Filename>
{enableImport && (
<UploadFileButton
studyId={studyId}
path={(file) => `${filePath}/${file.name}`}
onUploadSuccessful={reloadTreeData}
validate={handleValidateUpload}
/>
)}
</Menubar>
</ListSubheader>
}
sx={{
height: 1,
overflow: "auto",
}}
dense
>
{list.length > 0 ? (
list.map(([filename, data], index, arr) => {
const fileType = getFileType(data);
const Icon = getFileIcon(fileType);
const isLast = index === arr.length - 1;

return (
<Fragment key={filename}>
<ListItemButton
onClick={() =>
setSelectedFile({
fileType,
filename,
filePath: `${filePath}/${filename}`,
treeData: data,
})
}
>
<ListItemIcon>
<Icon />
</ListItemIcon>
<ListItemText primary={filename} />
</ListItemButton>
{!isLast && <Divider variant="fullWidth" />}
</Fragment>
);
})
) : (
<EmptyView title={t("study.debug.folder.empty")} icon={FolderIcon} />
)}
</List>
return (
<Fragment key={filename}>
<ListItemButton
onClick={() =>
setSelectedFile({
fileType,
filename,
filePath: `${filePath}/${filename}`,
treeData: data,
})
}
>
<ListItemIcon>
<Icon />
</ListItemIcon>
<ListItemText primary={filename} />
</ListItemButton>
{!isLast && <Divider variant="fullWidth" />}
</Fragment>
);
})
) : (
<EmptyView title={t("study.debug.folder.empty")} icon={FolderIcon} />
)}
</List>
<ConfirmationDialog
title="Replace File?"
confirmButtonText="Replace"
cancelButtonText="Cancel"
maxWidth="xs"
open={replaceFileConfirm.isPending}
onConfirm={replaceFileConfirm.resolve}
onCancel={replaceFileConfirm.reject}
>
Another file with the same name already exists. Replacing it will
overwrite its content.
</ConfirmationDialog>
</>
);
}

Expand Down
13 changes: 11 additions & 2 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
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() {
function Image({ filename }: DataCompProps) {
const { t } = useTranslation();

return <EmptyView icon={ImageIcon} title={t("study.debug.file.image")} />;
return (
<Flex>
<Menubar>
<Filename>{filename}</Filename>
</Menubar>
<EmptyView icon={ImageIcon} title={t("study.debug.file.image")} />
</Flex>
);
}

export default Image;
23 changes: 20 additions & 3 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Json.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import type { DataCompProps } from "../utils";
import DownloadButton from "../../../../../common/buttons/DownloadButton";
import { downloadFile } from "../../../../../../utils/fileUtils";
import { useEffect, useState } from "react";
import { Flex, Menubar } from "./styles";
import { Filename, Flex, Menubar } from "./styles";
import UploadFileButton from "../../../../../common/buttons/UploadFileButton";

function Json({ filePath, filename, studyId }: DataCompProps) {
function Json({ filePath, filename, studyId, enableImport }: DataCompProps) {
const [t] = useTranslation();
const { enqueueSnackbar } = useSnackbar();
const [currentJson, setCurrentJson] = useState<JSONEditorProps["json"]>();
Expand Down Expand Up @@ -45,10 +46,17 @@ function Json({ filePath, filename, studyId }: DataCompProps) {

const handleDownload = () => {
if (currentJson !== undefined) {
downloadFile(JSON.stringify(currentJson, null, 2), `${filename}.json`);
downloadFile(
JSON.stringify(currentJson, null, 2),
filename.endsWith(".json") ? filename : `${filename}.json`,
);
}
};

const handleUploadSuccessful = () => {
res.reload();
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////
Expand All @@ -59,6 +67,15 @@ function Json({ filePath, filename, studyId }: DataCompProps) {
ifResolved={(json) => (
<Flex>
<Menubar>
<Filename>{filename}</Filename>
{enableImport && (
<UploadFileButton
studyId={studyId}
path={filePath}
accept={{ "application/json": [".json"] }}
onUploadSuccessful={handleUploadSuccessful}
/>
)}
<DownloadButton onClick={handleDownload} />
</Menubar>
<JSONEditor
Expand Down
23 changes: 20 additions & 3 deletions webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
import type { DataCompProps } from "../utils";
import DownloadButton from "../../../../../common/buttons/DownloadButton";
import { downloadFile } from "../../../../../../utils/fileUtils";
import { Flex, Menubar } from "./styles";
import { Filename, Flex, Menubar } from "./styles";
import UploadFileButton from "../../../../../common/buttons/UploadFileButton";

SyntaxHighlighter.registerLanguage("xml", xml);
SyntaxHighlighter.registerLanguage("plaintext", plaintext);
Expand Down Expand Up @@ -48,7 +49,7 @@ function getSyntaxProps(data: string | string[]): SyntaxHighlighterProps {
};
}

function Text({ studyId, filePath, filename }: DataCompProps) {
function Text({ studyId, filePath, filename, enableImport }: DataCompProps) {
const { t } = useTranslation();
const theme = useTheme();

Expand All @@ -66,10 +67,17 @@ function Text({ studyId, filePath, filename }: DataCompProps) {

const handleDownload = () => {
if (res.data) {
downloadFile(res.data, `${filename}.txt`);
downloadFile(
res.data,
filename.endsWith(".txt") ? filename : `${filename}.txt`,
);
}
};

const handleUploadSuccessful = () => {
res.reload();
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////
Expand All @@ -80,6 +88,15 @@ function Text({ studyId, filePath, filename }: DataCompProps) {
ifResolved={(text) => (
<Flex>
<Menubar>
<Filename>{filename}</Filename>
{enableImport && (
<UploadFileButton
studyId={studyId}
path={filePath}
accept={{ "text/plain": [".txt"] }}
onUploadSuccessful={handleUploadSuccessful}
/>
)}
<DownloadButton onClick={handleDownload} />
</Menubar>
<Box sx={{ height: 1, display: "flex", flexDirection: "column" }}>
Expand Down
Loading

0 comments on commit ddf1368

Please sign in to comment.