-
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
439 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Tooltip, type ButtonProps, Button } from "@mui/material"; | ||
import React, { useCallback } from "react"; | ||
|
||
interface Props extends ButtonProps { | ||
base64_content: string; | ||
file_type: string; | ||
} | ||
|
||
export const DownloadB64Button: React.FC<Props> = ({ | ||
base64_content, | ||
file_type, | ||
...props | ||
}) => { | ||
const downloadContent = useCallback(() => { | ||
let href = ""; | ||
switch (file_type) { | ||
case "txt": | ||
href = `data:text/plain;base64,${base64_content}`; | ||
break; | ||
case "plotly_json": | ||
case "json": | ||
href = `data:application/json;base64,${base64_content}`; | ||
break; | ||
case "jpeg": | ||
case "jpg": | ||
case "png": | ||
case "bmp": | ||
case "gif": | ||
case "tiff": | ||
href = `data:image/${file_type};base64,${base64_content}`; | ||
break; | ||
case "svg": | ||
href = `data:image/svg+xml;base64,${base64_content}`; | ||
break; | ||
case "md": | ||
href = `data:text/markdown;base64,${base64_content}`; | ||
break; | ||
case "pdf": | ||
href = `data:application/pdf;base64,${base64_content}`; | ||
break; | ||
case "html": | ||
href = `data:text/html;base64,${base64_content}`; | ||
break; | ||
default: | ||
href = `data:text/plain;base64,${base64_content}`; | ||
break; | ||
} | ||
|
||
const a = document.createElement("a"); // Create <a> | ||
a.href = href; // Image Base64 Goes here | ||
a.download = `download.${file_type}`; // File name Here | ||
a.click(); // Downloaded file | ||
}, [base64_content, file_type]); | ||
|
||
return ( | ||
<Tooltip | ||
title={ | ||
!base64_content || !file_type | ||
? "Missing base64_content of file_type" | ||
: "Will download the raw result content " | ||
} | ||
> | ||
<Button | ||
variant="contained" | ||
onClick={downloadContent} | ||
disabled={!base64_content || !file_type} | ||
{...props} | ||
> | ||
Download content | ||
</Button> | ||
</Tooltip> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { Typography } from "@mui/material"; | ||
import { RenderPDF } from "components/RenderPDF"; | ||
import DOMPurify from "dompurify"; | ||
import React, { type CSSProperties } from "react"; | ||
import ReactMarkdown from "react-markdown"; | ||
import Plot from "react-plotly.js"; | ||
import remarkGfm from "remark-gfm"; | ||
|
||
interface Props { | ||
base64_content: string; | ||
file_type: string; | ||
style?: CSSProperties; | ||
} | ||
|
||
export const RenderB64: React.FC<Props> = ({ | ||
base64_content, | ||
file_type, | ||
style, | ||
}) => { | ||
if (!base64_content || !file_type) { | ||
return <Typography variant="h2">No content</Typography>; | ||
} | ||
switch (file_type) { | ||
case "txt": | ||
return <pre style={style}>{window.atob(base64_content)}</pre>; | ||
case "json": | ||
return ( | ||
<pre style={style}> | ||
{JSON.stringify(JSON.parse(window.atob(base64_content)), null, 2)} | ||
</pre> | ||
); | ||
case "jpeg": | ||
case "jpg": | ||
case "png": | ||
case "bmp": | ||
case "gif": | ||
case "tiff": | ||
return ( | ||
<img | ||
src={`data:image/${file_type};base64,${base64_content}`} | ||
alt="Content" | ||
style={{ maxWidth: "100%", maxHeight: "100%", ...style }} | ||
/> | ||
); | ||
case "svg": | ||
return ( | ||
<object | ||
type="image/svg+xml" | ||
data={`data:image/svg+xml;base64,${base64_content}`} | ||
style={{ maxWidth: "100%", maxHeight: "100%", ...style }} | ||
> | ||
Your browser does not support SVG | ||
</object> | ||
); | ||
case "md": | ||
return ( | ||
<div | ||
style={{ overflow: "auto", maxWidth: "100%", width: "100%" }} | ||
className="markdown-container" | ||
> | ||
<ReactMarkdown | ||
className="react-markdown-component" | ||
remarkPlugins={[remarkGfm]} | ||
> | ||
{window.atob(base64_content)} | ||
</ReactMarkdown> | ||
; | ||
</div> | ||
); | ||
|
||
case "pdf": | ||
return <RenderPDF base64Content={base64_content} />; | ||
case "html": { | ||
const decodedHTML = atob(base64_content); | ||
const sanitizedHTML = DOMPurify.sanitize(decodedHTML); | ||
|
||
return <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />; | ||
} | ||
case "plotly_json": { | ||
const utf8String = atob(base64_content); | ||
const decodedJSON = JSON.parse(utf8String); | ||
return ( | ||
<Plot | ||
data={decodedJSON.data} | ||
layout={decodedJSON.layout} | ||
style={{ width: "100%", height: "100%" }} | ||
/> | ||
); | ||
} | ||
default: | ||
return <div>Unsupported file type</div>; | ||
} | ||
}; |
75 changes: 75 additions & 0 deletions
75
frontend/src/features/myWorkflows/api/runs/getWorkflowRunReport.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { type AxiosResponse } from "axios"; | ||
import { useWorkspaces } from "context/workspaces"; | ||
import { dominoApiClient } from "services/clients/domino.client"; | ||
import useSWR from "swr"; | ||
|
||
export interface IGetWorkflowRunResultReportParams { | ||
workflowId: string; | ||
runId: string; | ||
} | ||
|
||
const getWorkflowRunResultReportUrl = ({ | ||
workspace, | ||
workflowId, | ||
runId, | ||
}: Partial<IGetWorkflowRunResultReportParams & { workspace: string }>) => { | ||
if (workspace && workflowId && runId) { | ||
return `/workspaces/${workspace}/workflows/${workflowId}/runs/${runId}/tasks/report`; | ||
} else { | ||
return null; | ||
} | ||
}; | ||
|
||
/** | ||
* Get workflows using GET /workflows | ||
* @returns workflow | ||
*/ | ||
const getWorkflowRunResultReport: ({ | ||
workspace, | ||
workflowId, | ||
runId, | ||
}: Partial< | ||
IGetWorkflowRunResultReportParams & { workspace: string } | ||
>) => Promise< | ||
| AxiosResponse<{ | ||
data: Array<{ base64_content: string; file_type: string }>; | ||
}> | ||
| undefined | ||
> = async ({ workspace, workflowId, runId }) => { | ||
if (workspace && workflowId && runId) { | ||
const url = getWorkflowRunResultReportUrl({ | ||
workspace, | ||
workflowId, | ||
runId, | ||
}); | ||
if (url) return await dominoApiClient.get(url); | ||
} | ||
}; | ||
|
||
/** | ||
* Get workflow runs | ||
* @returns runs as swr response | ||
*/ | ||
export const useAuthenticatedGetWorkflowRunResultReport = ( | ||
params: Partial<IGetWorkflowRunResultReportParams>, | ||
) => { | ||
const { workspace } = useWorkspaces(); | ||
if (!workspace) | ||
throw new Error( | ||
"Impossible to fetch workflows without specifying a workspace", | ||
); | ||
|
||
const url = getWorkflowRunResultReportUrl({ | ||
workspace: workspace.id, | ||
...params, | ||
}); | ||
|
||
return useSWR( | ||
url, | ||
async () => | ||
await getWorkflowRunResultReport({ | ||
workspace: workspace.id, | ||
...params, | ||
}).then((data) => data?.data), | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
frontend/src/features/myWorkflows/components/ResultsReport/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { Grid, Paper } from "@mui/material"; | ||
import { RenderPDF } from "components/RenderPDF"; | ||
import DOMPurify from "dompurify"; | ||
import { useAuthenticatedGetWorkflowRunResultReport } from "features/myWorkflows/api"; | ||
import React from "react"; | ||
import ReactMarkdown from "react-markdown"; | ||
import Plot from "react-plotly.js"; | ||
import { useParams } from "react-router-dom"; | ||
import remarkGfm from "remark-gfm"; | ||
|
||
export const ResultsReport: React.FC = () => { | ||
const { id, runId } = useParams<{ id: string; runId: string }>(); | ||
const { data } = useAuthenticatedGetWorkflowRunResultReport({ | ||
workflowId: id, | ||
runId, | ||
}); | ||
return ( | ||
<Paper sx={{ height: "88vh", overflowX: "scroll" }}> | ||
<Grid container> | ||
{data?.data?.map((d) => { | ||
switch (d.file_type) { | ||
case "txt": | ||
return <pre>{window.atob(d.base64_content)}</pre>; | ||
case "json": | ||
return ( | ||
<pre> | ||
{JSON.stringify( | ||
JSON.parse(window.atob(d.base64_content)), | ||
null, | ||
2, | ||
)} | ||
</pre> | ||
); | ||
case "jpeg": | ||
case "jpg": | ||
case "png": | ||
case "bmp": | ||
case "gif": | ||
case "tiff": | ||
return ( | ||
<img | ||
src={`data:image/${d.file_type};base64,${d.base64_content}`} | ||
alt="Content" | ||
style={{ maxWidth: "100%", maxHeight: "100%" }} | ||
/> | ||
); | ||
case "svg": | ||
return ( | ||
<object | ||
type="image/svg+xml" | ||
data={`data:image/svg+xml;base64,${d.base64_content}`} | ||
style={{ maxWidth: "100%", maxHeight: "100%" }} | ||
> | ||
Your browser does not support SVG | ||
</object> | ||
); | ||
case "md": | ||
return ( | ||
<div | ||
style={{ | ||
overflow: "auto", | ||
maxWidth: "100%", | ||
width: "100%", | ||
}} | ||
className="markdown-container" | ||
> | ||
<ReactMarkdown | ||
className="react-markdown-component" | ||
remarkPlugins={[remarkGfm]} | ||
> | ||
{window.atob(d.base64_content)} | ||
</ReactMarkdown> | ||
; | ||
</div> | ||
); | ||
|
||
case "pdf": | ||
return <RenderPDF base64Content={d.base64_content} />; | ||
case "html": { | ||
const decodedHTML = atob(d.base64_content); | ||
const sanitizedHTML = DOMPurify.sanitize(decodedHTML); | ||
|
||
return ( | ||
<div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} /> | ||
); | ||
} | ||
case "plotly_json": { | ||
const utf8String = atob(d.base64_content); | ||
const decodedJSON = JSON.parse(utf8String); | ||
return ( | ||
<Plot | ||
data={decodedJSON.data} | ||
layout={decodedJSON.layout} | ||
style={{ width: "100%", height: "100%" }} | ||
/> | ||
); | ||
} | ||
default: | ||
return <div>Unsupported file type: {d.file_type}</div>; | ||
} | ||
})} | ||
</Grid> | ||
</Paper> | ||
); | ||
}; |
Oops, something went wrong.