diff --git a/api/src/ws/index.ts b/api/src/ws/index.ts index 0351a499..55825a7a 100644 --- a/api/src/ws/index.ts +++ b/api/src/ws/index.ts @@ -138,6 +138,13 @@ export function attachWebsocketServer(server: Server, dal: DataAccessLayer) { server.tellClientsToRefetch("links", { objectType, objectId }); }); + dal.flowService.on("updated-for", ({ modelId, dataFlowId }) => { + const server = wssRegistry.get(modelId); + log.debug(`flows was updated for ${modelId} ${dataFlowId}`); + if (!server) return; + server.tellClientsToRefetch("flows", { modelId, dataFlowId }); + }); + // Clean up leftover websocket servers const cleanupInterval = setInterval(() => { log.debug(`Number active channels: ${wssRegistry.size}`); diff --git a/app/src/api/gram/api.js b/app/src/api/gram/api.js index 43c27d2a..395c303f 100644 --- a/app/src/api/gram/api.js +++ b/app/src/api/gram/api.js @@ -7,8 +7,7 @@ export const BASE_URL = `${window.location.origin}`; export const api = createApi({ tagTypes: [ "ActionItems", - "Controls", - "Flow", + "Controls", "Flows", "Mitigations", "Model", diff --git a/app/src/api/gram/flows.js b/app/src/api/gram/flows.js index a9db09e2..127a0e57 100644 --- a/app/src/api/gram/flows.js +++ b/app/src/api/gram/flows.js @@ -10,8 +10,7 @@ const flowsApi = api.injectEndpoints({ return response.flows; }, providesTags: (result, error, arg) => [ - { type: "Flows", id: `${arg.modelId}-${arg.dataFlowId}` }, - ...result.map((flow) => ({ type: "Flow", id: flow.id })), + { type: "Flows", id: `${arg.modelId}-${arg.dataFlowId}` }, ], }), createFlow: build.mutation({ @@ -39,8 +38,7 @@ const flowsApi = api.injectEndpoints({ }), transformResponse: (response, meta, arg) => response, // providesTags: (result, error, arg) => [{ type: "Flow", id: arg.flowId }], - invalidatesTags: (result, error, arg) => [ - { type: "Flow", id: arg.flowId }, + invalidatesTags: (result, error, arg) => [ { type: "Flows" }, ], }), diff --git a/app/src/components/model/board/Board.js b/app/src/components/model/board/Board.js index e83fd96c..2bd7b241 100644 --- a/app/src/components/model/board/Board.js +++ b/app/src/components/model/board/Board.js @@ -170,7 +170,7 @@ export default function Board() { useEffect(() => { setStage((prevStage) => ({ ...prevStage, - panning: cursorType === CURSOR_PAN ? true : false, + panning: cursorType === CURSOR_PAN, })); }, [cursorType]); diff --git a/app/src/components/model/panels/left/Flow.js b/app/src/components/model/panels/left/Flow.js index 936199ca..46d63948 100644 --- a/app/src/components/model/panels/left/Flow.js +++ b/app/src/components/model/panels/left/Flow.js @@ -8,17 +8,15 @@ import { Box, Divider, FormControl, - FormControlLabel, IconButton, InputLabel, MenuItem, Paper, Select, - Switch, TextField, - Tooltip, + Tooltip } from "@mui/material"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useGetFlowAttributesQuery } from "../../../../api/gram/attributes"; import { useDeleteFlowMutation, @@ -27,25 +25,14 @@ import { import { useReadOnly } from "../../../../hooks/useReadOnly"; import { EditableTypography } from "../../../elements/EditableTypography"; -function DynamicSwitch({ value, onChange, label, ...props }) { - return ( - onChange({ target: { value: e.target.checked } })} - {...props} - /> - } - label={label} - /> - ); -} - function DynamicDropdown({ value, onChange, label, attribute, ...props }) { const { options, allowMultiple, allowCustomValue } = attribute; const [val, setVal] = useState(value); + + useEffect(() => { + setVal(value) + }, [value]); + return ( { + setVal(value) + }, [value]); + return ( { const query = ` - UPDATE flows SET summary = $1, origin_component_id = $2, attributes = $3 WHERE id = $4 + UPDATE flows SET summary = $1, origin_component_id = $2, attributes = $3 WHERE id = $4 RETURNING * `; - - await this.pool.query(query, [summary, originComponentId, attributes, id]); + const res = await this.pool.query(query, [summary, originComponentId, attributes, id]); + this.emit("updated-for", { modelId: res.rows[0].model_id, dataFlowId: res.rows[0].data_flow_id }); } async deleteFlow(id: number): Promise { const query = ` DELETE FROM flows WHERE id = $1 RETURNING * `; - - await this.pool.query(query, [id]); - // const res = await this.pool.query(query, [id]); - // if (res.rows.length > 0) { - // const objectType = res.rows[0].object_type; - // const objectId = res.rows[0].object_id; - - // // this.notifyUpdatedFor(objectType, objectId); - // } + const res = await this.pool.query(query, [id]); + this.emit("updated-for", { modelId: res.rows[0].model_id, dataFlowId: res.rows[0].data_flow_id }); } - // async notifyUpdatedFor(objectType: LinkObjectType, objectId: LinkObjectId) { - // let modelId: string | undefined; - // if (objectType === LinkObjectType.Threat) { - // const threat = await this.dal.threatService.getById(objectId); - // if (threat) { - // modelId = threat.modelId; - // } - // } else if (objectType === LinkObjectType.Control) { - // const control = await this.dal.controlService.getById(objectId); - // if (control) { - // modelId = control.modelId; - // } - // } else if (objectType === LinkObjectType.Model) { - // modelId = objectId; - // } - - // if (modelId) { - // this.emit("updated-for", { modelId, objectType, objectId }); - // } - // } - async copyFlowsBetweenModels( srcModelId: string, targetModelId: string,