diff --git a/README.md b/README.md index 0ca3a05e..5d791fee 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Discord][discord-image]][discord-url] [![Developed at Klarna][klarna-image]][klarna-url] -Gram is Klarna's own [threat model][owasp-tm] diagramming tool developed internally by Klarna's Secure Development team. It is a webapp for engineers to collaboratively create threat models for their systems, providing a easy-to-understand way to document a system as a dataflow diagram with threats/controls attached. +Gram is Klarna's own [threat model][owasp-tm] diagramming tool developed internally by Klarna's Secure Development team. It is a web app for engineers to collaboratively create threat models for their systems, providing a easy-to-understand way to document a system as a dataflow diagram with threats/controls attached. ![Screenshot](screenshot.png) diff --git a/app/src/App.js b/app/src/App.js index e96a78ab..5278b543 100644 --- a/app/src/App.js +++ b/app/src/App.js @@ -95,8 +95,8 @@ export default function App() { sx={{ display: "flex", flexDirection: "column", - height: "calc(100% - 64px)", // 64px is the height of Navbar - maxHeight: "calc(100% - 64px)", + height: isFramed ? "100%" : "calc(100% - 64px)", // 64px is the height of Navbar + maxHeight: isFramed ? "100%" : "calc(100% - 64px)", // 64px is the height of Navbar width: "100%", }} > diff --git a/app/src/components/admin/AdminPage.css b/app/src/components/admin/AdminPage.css deleted file mode 100644 index 7d294201..00000000 --- a/app/src/components/admin/AdminPage.css +++ /dev/null @@ -1,13 +0,0 @@ -.row { - display: flex; - justify-content: space-between; - gap: 15px; -} - -.column { - flex: auto; -} - -#intro { - margin-bottom: 30px; -} diff --git a/app/src/components/admin/AdminPage.js b/app/src/components/admin/AdminPage.js index 9b4eaa7c..194ddc25 100644 --- a/app/src/components/admin/AdminPage.js +++ b/app/src/components/admin/AdminPage.js @@ -1,10 +1,18 @@ -import { Button } from "@mui/material"; +import { + Button, + Typography, + ButtonGroup, + List, + Link, + ListItemText, + ListItem, +} from "@mui/material"; import React from "react"; import { useSetRolesMutation } from "../../api/gram/admin"; import { useGetUserQuery } from "../../api/gram/user"; import { useGetTemplatesQuery } from "../../api/gram/model"; -import "./AdminPage.css"; import { CenteredPage } from "../elements/CenteredPage"; +import Grid from "@mui/material/Grid2"; export default function AdminPage() { const { data: user } = useGetUserQuery(); @@ -14,52 +22,53 @@ export default function AdminPage() { return ( -

- Admin{" "} - {user?.roles.includes("admin") - ? "" - : "(You are not admin, some of the functions here won't work)"} -

+ + Admin + + {user?.roles.includes("admin") + ? "" + : "(You are not admin, some of the functions here won't work)"} + + + This page contains some admin widgets to help with day-to-day + operations of Gram. By design, these shouldn't be anything too + sensitive, just stuff to help debug / maintain the application. + + + + Change Role + + Useful if you need to debug authz. Use the below form to set your new + roles. Login again to get back your admin role. + -

- This page contains some admin widgets to help with day-to-day operations - of Gram. By design, these shouldn't be anyhing too sensitive, - just stuff to help debug / maintain the application. -

- -
-
-

Change Role

-
-

- Useful if you need to debug authz. Use the below form to set your - new roles. Login again to get back your admin role. -

-
- - -
-
-
-

Templates

-
-

Models listed as templates.

-
- -
-
-
+ + + + +
+ + Templates + + Models listed as templates. + + + {templates?.map((template) => ( + + + + + + ))} + +
); } diff --git a/app/src/components/elements/CenteredPage.js b/app/src/components/elements/CenteredPage.js index 58f178f6..a33930d9 100644 --- a/app/src/components/elements/CenteredPage.js +++ b/app/src/components/elements/CenteredPage.js @@ -1,20 +1,18 @@ import React from "react"; -import { useIsFramed } from "../../hooks/useIsFramed"; import Grid from "@mui/material/Grid2"; -export function CenteredPage({ children }) { - const isFramed = useIsFramed(); +export function CenteredPage({ children, marginTop = true }) { return ( - - {children} - + {children} ); } diff --git a/app/src/components/home/Home.js b/app/src/components/home/Home.js index e710dd0c..0f49031b 100644 --- a/app/src/components/home/Home.js +++ b/app/src/components/home/Home.js @@ -21,58 +21,52 @@ export default function Home() { return ( - + + Recent Threat Models + + Threat models you recently interacted with + + + + {user?.teams?.length > 0 && ( - Recent Threat Models + Team Systems - Threat models you recently interacted with + Systems owned by the accountable teams you're in - - - {user?.teams?.length > 0 && ( - - Team Systems - - Systems owned by the accountable teams you're in - - - - {user?.teams && - user.teams.map((team, i) => ( - - 1 ? 5 : 10} - /> - - ))} - - - - )} - + + {user?.teams && + user.teams.map((team, i) => ( + + 1 ? 5 : 10} + /> + + ))} + + + + )} ); } diff --git a/app/src/components/home/__snapshots__/Home.spec.js.snap b/app/src/components/home/__snapshots__/Home.spec.js.snap index 54b203fe..2d799d28 100644 --- a/app/src/components/home/__snapshots__/Home.spec.js.snap +++ b/app/src/components/home/__snapshots__/Home.spec.js.snap @@ -6,49 +6,41 @@ exports[`Home renders Home 1`] = ` "baseElement":
+
+ Recent Threat Models +
+

+ Threat models you recently interacted with +

-
- Recent Threat Models -
-

- Threat models you recently interacted with -

-
-
    -
    - - No models exist - -
    -
+ No models exist +
-
+
@@ -57,49 +49,41 @@ exports[`Home renders Home 1`] = ` , "container":
+
+ Recent Threat Models +
+

+ Threat models you recently interacted with +

-
- Recent Threat Models -
-

- Threat models you recently interacted with -

-
-
    -
    - - No models exist - -
    -
+ No models exist +
-
+
diff --git a/app/src/components/model/Model.js b/app/src/components/model/Model.js index 08d29226..4018f2f9 100644 --- a/app/src/components/model/Model.js +++ b/app/src/components/model/Model.js @@ -27,8 +27,12 @@ import { useSelector } from "react-redux"; function setGridArea( leftPanelCollapsed, rightPanelCollapsed, - bottomPanelCollapsed + bottomPanelCollapsed, + isFramed ) { + if (isFramed) { + return `'board board board' 'board board board'`; + } // Add first row let firstRow = `'${leftPanelCollapsed ? "board" : "left"} board ${ rightPanelCollapsed ? "board" : "right" @@ -139,7 +143,8 @@ export function Model() { gridTemplateAreas: setGridArea( leftPanelCollapsed, rightPanelCollapsed, - bottomPanelCollapsed + bottomPanelCollapsed, + isFramed ), }} > diff --git a/app/src/components/model/ModelPreview.js b/app/src/components/model/ModelPreview.js index e120b0d1..da67c888 100644 --- a/app/src/components/model/ModelPreview.js +++ b/app/src/components/model/ModelPreview.js @@ -1,9 +1,13 @@ +import { Box } from "@mui/material"; + export function ModelPreview({ modelId, ...props }) { return ( - + + + ); } diff --git a/app/src/components/model/New.js b/app/src/components/model/New.js index c3f77b06..0267f730 100644 --- a/app/src/components/model/New.js +++ b/app/src/components/model/New.js @@ -7,7 +7,7 @@ import InputLabel from "@mui/material/InputLabel"; import MenuItem from "@mui/material/MenuItem"; import Select from "@mui/material/Select"; import TextField from "@mui/material/TextField"; -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useRef } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { useCreateModelMutation, @@ -92,115 +92,125 @@ export function NewWizard() { // Renders // ----------------------------------------------------------------------- + const refContainer = useRef(); + const [dimensions, setDimensions] = useState({ + width: 0, + height: 0, + }); + useEffect(() => { + if (refContainer.current) { + setDimensions({ + width: refContainer.current.offsetWidth, + height: refContainer.current.offsetHeight, + }); + } + }, [refContainer]); + console.log({ dimensions }); return ( - - - {result && result.error && ( - - )} - -

New Threat Model

- {system && system.system && systemId && ( -

{system.system.displayName}

- )} - {(models?.length > 0 || templates?.length > 0) && ( -

Import from another Gram model (optional)

- )} - {templates?.length > 0 && ( - - - Import from a template - - + + Do not import + + {templates.map((template) => ( + + {template.version} - {templates.map((template) => ( - - {template.version} - - ))} - - {!!sourceModelId && ( - - Disabled because you selected previous model - - )} - - )} - {system && system.pending && } - {systemId && ( - <> - {templates?.length > 0 && models?.length ? ( - OR - ) : ( - <> - )} - {models?.length > 0 && ( - - - Import from a previous threat model for this system - - - {!!sourceTemplateId && ( - - Disabled because you selected a template. - - )} - - )} - - )} - -

Provide a version name to identify this threat model by.

- + {!!sourceModelId && ( + + Disabled because you selected previous model + + )} + + )} + {system && system.pending && } + {systemId && ( + <> + {templates?.length > 0 && models?.length ? ( + OR + ) : ( + <> + )} + {models?.length > 0 && ( + + + Import from a previous threat model for this system + + + {!!sourceTemplateId && ( + + Disabled because you selected a template. + + )} + + )} + + )} + +

Provide a version name to identify this threat model by.

+ + +
+ + {(sourceModelId || sourceTemplateId) && ( + - - - - {(sourceModelId || sourceTemplateId) && ( - - )} - + )}
); diff --git a/app/src/components/model/board/Board.js b/app/src/components/model/board/Board.js index 17de1013..b1d40fa4 100644 --- a/app/src/components/model/board/Board.js +++ b/app/src/components/model/board/Board.js @@ -783,7 +783,7 @@ export default function Board() { )} - + {!isFramed && } )} diff --git a/app/src/components/model/board/components/ControlsToolBar.js b/app/src/components/model/board/components/ControlsToolBar.js index d0310223..3758f2b0 100644 --- a/app/src/components/model/board/components/ControlsToolBar.js +++ b/app/src/components/model/board/components/ControlsToolBar.js @@ -80,16 +80,18 @@ export function ControlsToolBar({ zoomInCenter, onAddComponent }) { - { - dispatch(togglePanel(TOGGLE_BOTTOM_PANEL, !bottomPanelCollapsed)); - }} - > - - - - + {!isFramed && ( + { + dispatch(togglePanel(TOGGLE_BOTTOM_PANEL, !bottomPanelCollapsed)); + }} + > + + + + + )} {!readOnly && } diff --git a/app/src/components/reviews/Reviews.js b/app/src/components/reviews/Reviews.js index 9fe8a2a9..c0bc70a6 100644 --- a/app/src/components/reviews/Reviews.js +++ b/app/src/components/reviews/Reviews.js @@ -17,6 +17,7 @@ import { TablePaginationActions } from "./TablePaginationActions"; import { TableRow } from "./TableRow"; import { TableToolbar } from "./TableToolbar"; import { CenteredPage } from "../elements/CenteredPage"; +import Grid from "@mui/material/Grid2"; export function Reviews() { useTitle("Reviews"); @@ -121,41 +122,43 @@ export function Reviews() { return ( - - - - - - - - {reviews?.total === 0 && } - {reviews?.items.map((review) => ( - - ))} - - - - - - -
-
-
+ + + + + + + + + {reviews?.total === 0 && } + {reviews?.items.map((review) => ( + + ))} + + + + + + +
+
+
+
); } diff --git a/app/src/components/search/__snapshots__/SearchPage.spec.js.snap b/app/src/components/search/__snapshots__/SearchPage.spec.js.snap index dbe9ba33..72859f6c 100644 --- a/app/src/components/search/__snapshots__/SearchPage.spec.js.snap +++ b/app/src/components/search/__snapshots__/SearchPage.spec.js.snap @@ -6,50 +6,7 @@ exports[`Search renders Search 1`] = ` "baseElement":
-
-
-
-
- Search results for " - - " -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- , - "container":
-
-
+ , + "container":
+
+
+
+
+ Search results for " + + " +
+
+
+
+
+
+
+
+
+
+
+
+
, "debug": [Function], "findAllByAltText": [Function], diff --git a/app/src/components/system/System.js b/app/src/components/system/System.js index 071c669c..3cea66e0 100644 --- a/app/src/components/system/System.js +++ b/app/src/components/system/System.js @@ -55,41 +55,39 @@ export function System() { return ( - - - - {system.displayName}{" "} - — {system.shortName} - + + + {system.displayName}{" "} + — {system.shortName} + - - {system.owners?.map((owner) => ( - - {owner.name} - - ))}{" "} - —{" "} - - {system.description || "(system has no description)"} - - + + {system.owners?.map((owner) => ( + + {owner.name} + + ))}{" "} + —{" "} + + {system.description || "(system has no description)"} + + - {permissions.includes(PERMISSIONS.WRITE) && ( - - - - - - )} + {permissions.includes(PERMISSIONS.WRITE) && ( + + + + + + )} - Threat Models + Threat Models - - + ); diff --git a/app/src/components/systems/TeamSystems/TeamSystemPage.js b/app/src/components/systems/TeamSystems/TeamSystemPage.js index df0c1355..74fdc5f4 100644 --- a/app/src/components/systems/TeamSystems/TeamSystemPage.js +++ b/app/src/components/systems/TeamSystems/TeamSystemPage.js @@ -22,24 +22,25 @@ export function TeamSystemsPage() { useTitle("Team"); return ( - - {!teamId ? ( - <> - Your Team Systems - - Systems belonging to your team{teams.length > 1 ? "s" : ""} - - - ) : ( - - )} + + + {!teamId ? ( + + Your Team Systems + + Systems belonging to your team{teams.length > 1 ? "s" : ""} + + + ) : ( + + + + )} - {/* Some employees have more than one team */} {teams.map((tid) => ( diff --git a/app/src/components/user-models/UserModels/UserModels.js b/app/src/components/user-models/UserModels/UserModels.js index fc6f2c26..ebdcd738 100644 --- a/app/src/components/user-models/UserModels/UserModels.js +++ b/app/src/components/user-models/UserModels/UserModels.js @@ -18,33 +18,31 @@ export default function UserModels() { return ( - - - Your Models - - These models are bound to your account and not bound to a specific - system. - - -
- - - - - - - -
- - - - -
+ + Your Models + + These models are bound to your account and not bound to a specific + system. + + +
+ + + + + + + +
+ + + +
); diff --git a/app/src/components/user-models/UserModels/__snapshots__/UserModels.spec.js.snap b/app/src/components/user-models/UserModels/__snapshots__/UserModels.spec.js.snap index 2a5b6213..b496e103 100644 --- a/app/src/components/user-models/UserModels/__snapshots__/UserModels.spec.js.snap +++ b/app/src/components/user-models/UserModels/__snapshots__/UserModels.spec.js.snap @@ -6,77 +6,69 @@ exports[`UserModels renders 1`] = ` "baseElement":
+
+ Your Models +
+

+ These models are bound to your account and not bound to a specific system. +

+
-
-
- Your Models -
-

- These models are bound to your account and not bound to a specific system. -

-
+ Create New Model + + +
+
+
+
+
- - - +
+
+
+
-
-
-
-
-
-
-
-
-
-
    -
    - - No models exist - -
    -
+ No models exist +
-
+
@@ -85,77 +77,69 @@ exports[`UserModels renders 1`] = ` , "container":
+
+ Your Models +
+

+ These models are bound to your account and not bound to a specific system. +

+
-
-
- Your Models -
-

- These models are bound to your account and not bound to a specific system. -

-
+ Create New Model + + +
+
+
+
+
- - - +
+
+
+
-
-
-
-
-
-
-
-
-
-
    -
    - - No models exist - -
    -
+ No models exist +
-
+