diff --git a/frontend/src/components/CaseImporterFlow.jsx b/frontend/src/components/CaseImporterFlow.jsx index a685824e..061ef7d1 100644 --- a/frontend/src/components/CaseImporterFlow.jsx +++ b/frontend/src/components/CaseImporterFlow.jsx @@ -41,7 +41,7 @@ function CaseImporterFlow({ titleId, onClose }) { if (svgElement && svgElement.hasAttribute("data-metadata")) { const metadataStr = svgElement.getAttribute("data-metadata"); try { - return JSON.parse(decodeFromHtml(metadataStr)); + return JSON.parse(JSON.parse(decodeFromHtml(metadataStr))); } catch (err) { console.error("Error parsing metadata:", err); } @@ -76,14 +76,14 @@ function CaseImporterFlow({ titleId, onClose }) { ); const postCaseJSON = useCallback( - (json_str) => { + (json) => { const requestOptions = { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Token ${token}`, }, - body: json_str, + body: JSON.stringify(json), }; setLoading(true); @@ -123,7 +123,7 @@ function CaseImporterFlow({ titleId, onClose }) { if (uploadType === "url") { getUrlContent(url).then((json) => { if (json) { - postCaseJSON(JSON.stringify(json)); + postCaseJSON(json); } }); } else { @@ -160,7 +160,7 @@ function CaseImporterFlow({ titleId, onClose }) { const metadataStr = svgElement.getAttribute("data-metadata"); try { const metadataJSON = JSON.parse(metadataStr); - setFileJson(metadataJSON); + setFileJson(JSON.parse(metadataJSON)); } catch (err) { // TODO error could be better setFileError("File is not a valid SVG"); diff --git a/frontend/src/components/CaseMediaPreview.jsx b/frontend/src/components/CaseMediaPreview.jsx new file mode 100644 index 00000000..46aa2b1e --- /dev/null +++ b/frontend/src/components/CaseMediaPreview.jsx @@ -0,0 +1,77 @@ +import configData from "../config.json"; +import { CardMedia } from "@mui/material"; +import mockup_diagram from "../images/mockup-diagram.png"; +import { useTheme } from "@emotion/react"; +import { useEffect, useState } from "react"; +import MermaidChart from "./Mermaid"; +import { useLoginToken } from "../hooks/useAuth"; +import { getCase } from "./caseApi"; +import { Box } from "@mui/material"; +import { LoadingCard } from "./ManageCases"; + +export const CaseMediaPreview = ({ caseObj }) => { + const theme = useTheme(); + const [token] = useLoginToken(); + const [assuranceCase, setAssuranceCase] = useState(); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + if (token) { + let isMounted = true; + getCase(token, caseObj.id) + .then((json) => { + if (!isMounted) { + return; + } + setAssuranceCase(json); + setIsLoading(false); + }) + .catch((err) => { + console.error(err); + // TODO show error to user + }); + + return () => { + isMounted = false; + }; + } + }, [token, caseObj]); + + if (configData.use_case_preview_svg) { + return ( + <> + {isLoading ? ( + + ) : ( + + {}} + setMermaidFocus={() => {}} + /> + + )} + + ); + } else { + return ( + + ); + } +}; diff --git a/frontend/src/components/ManageCases.jsx b/frontend/src/components/ManageCases.jsx index 90afe2dc..b37576ba 100644 --- a/frontend/src/components/ManageCases.jsx +++ b/frontend/src/components/ManageCases.jsx @@ -24,6 +24,7 @@ import CommentSection from "./CommentSection"; import CasePermissionsManager from "./CasePermissionsManager"; import DeleteCaseModal from "./DeleteCaseModal"; import ErrorMessage from "./common/ErrorMessage"; +import { CaseMediaPreview } from "./CaseMediaPreview"; const ThemedCard = ({ sx, ...props }) => { return ( @@ -77,7 +78,7 @@ const formatter = new Intl.DateTimeFormat(undefined, { year: "numeric", }); -const CaseCard = ({ id, name, description, createdDate, reload }) => { +const CaseCard = ({ caseObj, reload }) => { const theme = useTheme(); const [menuOpen, setMenuOpen] = useState(false); @@ -135,16 +136,11 @@ const CaseCard = ({ id, name, description, createdDate, reload }) => { - + + { textDecoration: "none", color: "unset", overflow: "hidden", + zIndex: 99, }} > - {name} + {caseObj.name} { minHeight: 0, }} > - {description?.split("\n").map((str) => ( + {caseObj.description?.split("\n").map((str) => ( <> {str}
@@ -183,7 +180,7 @@ const CaseCard = ({ id, name, description, createdDate, reload }) => {
{/* TODO, designs would prefer the updated date */} - Created: {formatter.format(createdDate)} + Created: {formatter.format(caseObj.createdDate)}
@@ -221,26 +218,30 @@ const CaseCard = ({ id, name, description, createdDate, reload }) => { + -
); }; -const LoadingCard = () => { +export const LoadingCard = () => { return ( @@ -353,8 +354,8 @@ const ManageCases = () => { ) : ( <> - {cases.map(({ id, ...props }) => ( - + {cases.map((caseObj) => ( + ))} )} diff --git a/frontend/src/components/Mermaid.js b/frontend/src/components/Mermaid.js index e2271825..7455dede 100644 --- a/frontend/src/components/Mermaid.js +++ b/frontend/src/components/Mermaid.js @@ -13,11 +13,14 @@ function MermaidChart({ }) { const [collapsedNodes, setCollapsedNodes] = useState([]); - const chartmd = useMemo( - () => - jsonToMermaid(assuranceCase, selectedType, selectedId, collapsedNodes), - [assuranceCase, selectedType, selectedId, collapsedNodes], - ); + const chartmd = useMemo(() => { + return jsonToMermaid( + assuranceCase, + selectedType, + selectedId, + collapsedNodes, + ); + }, [assuranceCase, selectedType, selectedId, collapsedNodes]); // refresh state useEffect(() => { @@ -81,7 +84,7 @@ function MermaidChart({ // trigger mermaid reload useEffect(() => { try { - const mermaidDiv = document.querySelector(".mermaid"); + const mermaidDiv = document.querySelector(`.mermaid-${caseId}`); if (mermaidDiv) { // inject the markdown here, rather than via react // so in between render and the effect you don't see the text @@ -108,12 +111,14 @@ function MermaidChart({ key={chartmd} style={{ display: "flex", + flexDirection: "column", height: "100%", width: "100%", - justifyContent: "center", + justifyContent: "start", + alignItems: "start", overflow: "visible", }} - className="mermaid" + className={`mermaid-${caseId} mermaid`} /> ); } diff --git a/frontend/src/config.json b/frontend/src/config.json index 37ff7616..d257be46 100644 --- a/frontend/src/config.json +++ b/frontend/src/config.json @@ -149,5 +149,6 @@ "desc_char_max_len": 40, "evidence_url_char_max_len": 250 } - } + }, + "use_case_preview_svg": true }