From 298f8831922ced7c99ee3cffddcd9b219cd6fc73 Mon Sep 17 00:00:00 2001 From: Samir Kamal <1954121+skamril@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:29:34 +0200 Subject: [PATCH] feat(ui-debug): add export button for json and text files --- .../Singlestudy/explore/Debug/Data/Folder.tsx | 79 +++++++++---------- .../Singlestudy/explore/Debug/Data/Image.tsx | 7 +- .../Singlestudy/explore/Debug/Data/Json.tsx | 58 +++++++++----- .../Singlestudy/explore/Debug/Data/Matrix.tsx | 17 ++-- .../Singlestudy/explore/Debug/Data/Text.tsx | 35 +++++--- .../Singlestudy/explore/Debug/Data/index.tsx | 15 ++-- .../Singlestudy/explore/Debug/Data/styles.ts | 13 +++ 7 files changed, 130 insertions(+), 94 deletions(-) create mode 100644 webapp/src/components/App/Singlestudy/explore/Debug/Data/styles.ts diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Folder.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Folder.tsx index 3aa92463c5..e52a403c90 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Folder.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Folder.tsx @@ -13,7 +13,6 @@ import { type TreeFolder, type DataCompProps, } from "../utils"; -import ViewWrapper from "../../../../../common/page/ViewWrapper"; import { Fragment } from "react"; import EmptyView from "../../../../../common/page/SimpleContent"; import { useTranslation } from "react-i18next"; @@ -28,47 +27,45 @@ function Folder({ const list = Object.entries(treeData as TreeFolder); return ( - - {filename}} - 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; + {filename}} + 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 ( - - - setSelectedFile({ - fileType, - filename, - filePath: `${filePath}/${filename}`, - treeData: data, - }) - } - > - - - - - - {!isLast && } - - ); - }) - ) : ( - - )} - - + return ( + + + setSelectedFile({ + fileType, + filename, + filePath: `${filePath}/${filename}`, + treeData: data, + }) + } + > + + + + + + {!isLast && } + + ); + }) + ) : ( + + )} + ); } diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx index 874cb7691a..8ef8ea39c1 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Image.tsx @@ -1,16 +1,11 @@ import { useTranslation } from "react-i18next"; import EmptyView from "../../../../../common/page/SimpleContent"; -import ViewWrapper from "../../../../../common/page/ViewWrapper"; import ImageIcon from "@mui/icons-material/Image"; function Image() { const { t } = useTranslation(); - return ( - - - - ); + return ; } export default Image; diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Json.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Json.tsx index 463a605855..6863fd92b1 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Json.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Json.tsx @@ -1,16 +1,19 @@ import { useTranslation } from "react-i18next"; import { useSnackbar } from "notistack"; -import { Box } from "@mui/material"; import { editStudy, getStudyData } from "../../../../../../services/api/study"; import JSONEditor, { JSONEditorProps } from "../../../../../common/JSONEditor"; import usePromiseWithSnackbarError from "../../../../../../hooks/usePromiseWithSnackbarError"; import UsePromiseCond from "../../../../../common/utils/UsePromiseCond"; -import ViewWrapper from "../../../../../common/page/ViewWrapper"; 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"; -function Json({ filePath, studyId }: DataCompProps) { +function Json({ filePath, filename, studyId }: DataCompProps) { const [t] = useTranslation(); const { enqueueSnackbar } = useSnackbar(); + const [currentJson, setCurrentJson] = useState(); const res = usePromiseWithSnackbarError( () => getStudyData(studyId, filePath, -1), @@ -20,6 +23,10 @@ function Json({ filePath, studyId }: DataCompProps) { }, ); + useEffect(() => { + setCurrentJson(res.data); + }, [res.data]); + //////////////////////////////////////////////////////////////// // Event Handlers //////////////////////////////////////////////////////////////// @@ -28,34 +35,43 @@ function Json({ filePath, studyId }: DataCompProps) { return editStudy(json, studyId, filePath); }; - const handleSaveSuccessful = () => { + const handleSaveSuccessful: JSONEditorProps["onSaveSuccessful"] = (json) => { + setCurrentJson(json); + enqueueSnackbar(t("studies.success.saveData"), { variant: "success", }); }; + const handleDownload = () => { + if (currentJson !== undefined) { + downloadFile(JSON.stringify(currentJson, null, 2), `${filename}.json`); + } + }; + //////////////////////////////////////////////////////////////// // JSX //////////////////////////////////////////////////////////////// return ( - - ( - - - - )} - /> - + ( + + + + + + + )} + /> ); } 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 efcdd7089d..f48e93cca0 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Matrix.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Matrix.tsx @@ -1,19 +1,16 @@ import { MatrixStats } from "../../../../../../common/types"; import MatrixInput from "../../../../../common/MatrixInput"; -import ViewWrapper from "../../../../../common/page/ViewWrapper"; import type { DataCompProps } from "../utils"; function Matrix({ studyId, filename, filePath, enableImport }: DataCompProps) { return ( - - - + ); } diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx index 9674993132..3a8e17169e 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/Text.tsx @@ -3,7 +3,6 @@ import { Box, useTheme } from "@mui/material"; import { getStudyData } from "../../../../../../services/api/study"; import usePromiseWithSnackbarError from "../../../../../../hooks/usePromiseWithSnackbarError"; import UsePromiseCond from "../../../../../common/utils/UsePromiseCond"; -import ViewWrapper from "../../../../../common/page/ViewWrapper"; import { Light as SyntaxHighlighter, type SyntaxHighlighterProps, @@ -14,6 +13,9 @@ import ini from "react-syntax-highlighter/dist/esm/languages/hljs/ini"; import properties from "react-syntax-highlighter/dist/esm/languages/hljs/properties"; 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"; SyntaxHighlighter.registerLanguage("xml", xml); SyntaxHighlighter.registerLanguage("plaintext", plaintext); @@ -46,7 +48,7 @@ function getSyntaxProps(data: string | string[]): SyntaxHighlighterProps { }; } -function Text({ studyId, filePath }: DataCompProps) { +function Text({ studyId, filePath, filename }: DataCompProps) { const { t } = useTranslation(); const theme = useTheme(); @@ -58,15 +60,28 @@ function Text({ studyId, filePath }: DataCompProps) { }, ); + //////////////////////////////////////////////////////////////// + // Event Handlers + //////////////////////////////////////////////////////////////// + + const handleDownload = () => { + if (res.data) { + downloadFile(res.data, `${filename}.txt`); + } + }; + //////////////////////////////////////////////////////////////// // JSX //////////////////////////////////////////////////////////////// return ( - - ( + ( + + + + - )} - /> - + + )} + /> ); } 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 be4dc19c54..1423274252 100644 --- a/webapp/src/components/App/Singlestudy/explore/Debug/Data/index.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/index.tsx @@ -5,6 +5,7 @@ import Matrix from "./Matrix"; import Folder from "./Folder"; import type { FileInfo, FileType } from "../utils"; import type { DataCompProps } from "../utils"; +import ViewWrapper from "../../../../../common/page/ViewWrapper"; interface Props extends FileInfo { studyId: string; @@ -30,12 +31,14 @@ function Data({ studyId, setSelectedFile, ...fileInfo }: Props) { const DataViewer = componentByFileType[fileType]; return ( - + + + ); } diff --git a/webapp/src/components/App/Singlestudy/explore/Debug/Data/styles.ts b/webapp/src/components/App/Singlestudy/explore/Debug/Data/styles.ts new file mode 100644 index 0000000000..416233c03c --- /dev/null +++ b/webapp/src/components/App/Singlestudy/explore/Debug/Data/styles.ts @@ -0,0 +1,13 @@ +import { styled } from "@mui/material"; + +export const Flex = styled("div")(({ theme }) => ({ + height: "100%", + display: "flex", + flexDirection: "column", + gap: theme.spacing(1), +})); + +export const Menubar = styled("div")({ + display: "flex", + justifyContent: "flex-end", +});