@kartverket/backstage-plugin-risk-scorecard 1.0.14 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/{index-b5d09407.esm.js → index-99d0fef8.esm.js} +1128 -1014
- package/dist/esm/index-99d0fef8.esm.js.map +1 -0
- package/dist/esm/{index-d8d91dc1.esm.js → index-c11a7a42.esm.js} +23 -10
- package/dist/esm/index-c11a7a42.esm.js.map +1 -0
- package/dist/index.esm.js +1 -1
- package/package.json +5 -2
- package/src/index.ts +1 -1
- package/dist/esm/index-b5d09407.esm.js.map +0 -1
- package/dist/esm/index-d8d91dc1.esm.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback,
|
|
2
|
-
import { makeStyles, FormControl, FormLabel, FormHelperText, TextField as TextField$1, Grid, Typography, Box as Box$1,
|
|
1
|
+
import React, { useState, useEffect, useCallback, Fragment, useRef, forwardRef } from 'react';
|
|
2
|
+
import { makeStyles, FormControl, FormLabel, FormHelperText, TextField as TextField$1, Grid, Typography, Box as Box$1, Paper, Button, useTheme, Radio, CircularProgress, Dialog, DialogTitle, DialogActions, Stepper, Step, StepButton, List, ListSubheader, ListItem, ListItemText as ListItemText$2, ClickAwayListener, Tooltip, DialogContent, DialogContentText, IconButton as IconButton$1, Tab, Link as Link$1, LinearProgress } from '@material-ui/core';
|
|
3
3
|
import { InfoCard, ContentHeader, SupportButton } from '@backstage/core-components';
|
|
4
4
|
import { useEntity } from '@backstage/plugin-catalog-react';
|
|
5
5
|
import { useRouteRef, useApi, googleAuthApiRef, identityApiRef, fetchApiRef, configApiRef } from '@backstage/core-plugin-api';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { r as riScRouteRef, s as scenarioRouteRef, p as pluginRiScTranslationRef } from './index-c11a7a42.esm.js';
|
|
7
|
+
import { useLocation, useNavigate, useParams } from 'react-router';
|
|
8
8
|
import { useEffectOnce } from 'react-use';
|
|
9
9
|
import { useSearchParams, Routes, Route } from 'react-router-dom';
|
|
10
10
|
import Box from '@material-ui/core/Box';
|
|
@@ -15,25 +15,38 @@ import FormLabel$1 from '@material-ui/core/FormLabel';
|
|
|
15
15
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
|
16
16
|
import ListItemText from '@material-ui/core/ListItemText';
|
|
17
17
|
import MenuItem from '@material-ui/core/MenuItem';
|
|
18
|
-
import Select from '@material-ui/core/Select';
|
|
18
|
+
import Select$1 from '@material-ui/core/Select';
|
|
19
19
|
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
20
20
|
import Divider from '@mui/material/Divider';
|
|
21
21
|
import Grid$1 from '@mui/material/Grid';
|
|
22
22
|
import AddCircle from '@material-ui/icons/AddCircle';
|
|
23
23
|
import DeleteIcon from '@material-ui/icons/Delete';
|
|
24
|
-
import { LocalizationProvider, DatePicker } from '@mui/x-date-pickers';
|
|
25
|
-
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3';
|
|
26
|
-
import { nb } from 'date-fns/locale/nb';
|
|
27
24
|
import Button$1 from '@mui/material/Button';
|
|
28
25
|
import Alert from '@mui/material/Alert';
|
|
29
26
|
import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
|
|
30
27
|
import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
|
|
31
28
|
import Box$2 from '@mui/material/Box';
|
|
29
|
+
import Paper$1 from '@mui/material/Paper';
|
|
30
|
+
import Typography$1 from '@mui/material/Typography';
|
|
32
31
|
import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight';
|
|
33
|
-
import
|
|
34
|
-
import
|
|
35
|
-
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
|
32
|
+
import Chip$1 from '@mui/material/Chip';
|
|
33
|
+
import Link from '@mui/material/Link';
|
|
36
34
|
import DeleteIcon$1 from '@mui/icons-material/Delete';
|
|
35
|
+
import Dialog$1 from '@mui/material/Dialog';
|
|
36
|
+
import DialogTitle$1 from '@mui/material/DialogTitle';
|
|
37
|
+
import DialogActions$1 from '@mui/material/DialogActions';
|
|
38
|
+
import { useController, useFieldArray, useForm } from 'react-hook-form';
|
|
39
|
+
import FormControl$2 from '@mui/material/FormControl';
|
|
40
|
+
import FormHelperText$1 from '@mui/material/FormHelperText';
|
|
41
|
+
import FormLabel$2 from '@mui/material/FormLabel';
|
|
42
|
+
import MUISelect from '@mui/material/Select';
|
|
43
|
+
import Checkbox$1 from '@mui/material/Checkbox';
|
|
44
|
+
import MenuItem$1 from '@mui/material/MenuItem';
|
|
45
|
+
import ListItemText$1 from '@mui/material/ListItemText';
|
|
46
|
+
import TextField$2 from '@mui/material/TextField';
|
|
47
|
+
import { AddCircle as AddCircle$1 } from '@mui/icons-material';
|
|
48
|
+
import IconButton from '@mui/material/IconButton';
|
|
49
|
+
import Drawer from '@mui/material/Drawer';
|
|
37
50
|
import CircleIcon from '@material-ui/icons/FiberManualRecord';
|
|
38
51
|
import InfoIcon from '@mui/icons-material/Info';
|
|
39
52
|
import TabContext from '@material-ui/lab/TabContext';
|
|
@@ -45,8 +58,10 @@ import TableCell from '@mui/material/TableCell';
|
|
|
45
58
|
import TableContainer from '@mui/material/TableContainer';
|
|
46
59
|
import TableHead from '@mui/material/TableHead';
|
|
47
60
|
import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline';
|
|
48
|
-
import
|
|
49
|
-
import
|
|
61
|
+
import CheckIcon from '@mui/icons-material/Check';
|
|
62
|
+
import EditIcon from '@mui/icons-material/Edit';
|
|
63
|
+
import { CacheProvider } from '@emotion/react';
|
|
64
|
+
import createCache from '@emotion/cache';
|
|
50
65
|
|
|
51
66
|
var RiScStatus = /* @__PURE__ */ ((RiScStatus2) => {
|
|
52
67
|
RiScStatus2["Draft"] = "Draft";
|
|
@@ -78,7 +93,7 @@ var ContentStatus = /* @__PURE__ */ ((ContentStatus2) => {
|
|
|
78
93
|
})(ContentStatus || {});
|
|
79
94
|
|
|
80
95
|
var $schema = "https://json-schema.org/draft/2020-12/schema";
|
|
81
|
-
var $id = "https://kartverket.github.io/backstage-plugin-risk-scorecard-backend/
|
|
96
|
+
var $id = "https://kartverket.github.io/backstage-plugin-risk-scorecard-backend/risc_schema_en_v3_3.json";
|
|
82
97
|
var title = "Risk Scorecard (RiSc)";
|
|
83
98
|
var description = "Schema for risk scorecard";
|
|
84
99
|
var type = "object";
|
|
@@ -86,7 +101,7 @@ var properties = {
|
|
|
86
101
|
schemaVersion: {
|
|
87
102
|
description: "Schema version",
|
|
88
103
|
type: "string",
|
|
89
|
-
"default": "'3.
|
|
104
|
+
"default": "'3.3'"
|
|
90
105
|
},
|
|
91
106
|
title: {
|
|
92
107
|
description: "Title of the risk scorecard",
|
|
@@ -390,13 +405,6 @@ const formatter = new Intl.NumberFormat("nb-NO", {
|
|
|
390
405
|
function formatNOK(amount) {
|
|
391
406
|
return formatter.format(amount);
|
|
392
407
|
}
|
|
393
|
-
function formatDate(date) {
|
|
394
|
-
return new Date(date).toLocaleDateString("nb-NO", {
|
|
395
|
-
year: "numeric",
|
|
396
|
-
month: "2-digit",
|
|
397
|
-
day: "2-digit"
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
408
|
function getAlertSeverity(status) {
|
|
401
409
|
switch (status) {
|
|
402
410
|
case ProcessingStatus.UpdatedRiSc:
|
|
@@ -415,39 +423,12 @@ function getRiskMatrixColor(risiko) {
|
|
|
415
423
|
const getProbabilityLevel = (risiko) => probabilityOptions.indexOf(risiko.probability) + 1;
|
|
416
424
|
const getConsequenceLevel = (risiko) => consequenceOptions.indexOf(risiko.consequence) + 1;
|
|
417
425
|
const emptyRiSc = () => ({
|
|
418
|
-
schemaVersion: "3.
|
|
426
|
+
schemaVersion: "3.3",
|
|
419
427
|
title: "",
|
|
420
428
|
scope: "",
|
|
421
429
|
valuations: [],
|
|
422
430
|
scenarios: []
|
|
423
431
|
});
|
|
424
|
-
const emptyScenario = () => ({
|
|
425
|
-
ID: generateRandomId(),
|
|
426
|
-
title: "",
|
|
427
|
-
description: "",
|
|
428
|
-
threatActors: [],
|
|
429
|
-
vulnerabilities: [],
|
|
430
|
-
risk: {
|
|
431
|
-
summary: "",
|
|
432
|
-
probability: 0.01,
|
|
433
|
-
consequence: 1e3
|
|
434
|
-
},
|
|
435
|
-
existingActions: "",
|
|
436
|
-
actions: [],
|
|
437
|
-
remainingRisk: {
|
|
438
|
-
summary: "",
|
|
439
|
-
probability: 0.01,
|
|
440
|
-
consequence: 1e3
|
|
441
|
-
}
|
|
442
|
-
});
|
|
443
|
-
const emptyAction = () => ({
|
|
444
|
-
ID: generateRandomId(),
|
|
445
|
-
title: "",
|
|
446
|
-
description: "",
|
|
447
|
-
owner: "",
|
|
448
|
-
deadline: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
449
|
-
status: "Not started"
|
|
450
|
-
});
|
|
451
432
|
const requiresNewApproval = (oldRiSc, updatedRiSc) => {
|
|
452
433
|
if (oldRiSc.scenarios.length !== updatedRiSc.scenarios.length) {
|
|
453
434
|
return true;
|
|
@@ -505,8 +486,8 @@ function formatNumber(cost, t) {
|
|
|
505
486
|
function dtoToRiSc(riScDTO) {
|
|
506
487
|
return {
|
|
507
488
|
...riScDTO,
|
|
508
|
-
// TODO implementere løsning for migrering, kan bumpe fra 3.
|
|
509
|
-
// skjemaVersjon: '3.
|
|
489
|
+
// TODO implementere løsning for migrering, kan bumpe fra 3.2 til 3.3 på denne måten manuelt ved å åpne og lagre riscen:
|
|
490
|
+
// skjemaVersjon: '3.3',
|
|
510
491
|
scenarios: riScDTO.scenarios.map(dtoToScenario)
|
|
511
492
|
};
|
|
512
493
|
}
|
|
@@ -573,7 +554,8 @@ function actionToDTO(action) {
|
|
|
573
554
|
description: action.description,
|
|
574
555
|
owner: action.owner,
|
|
575
556
|
deadline: action.deadline,
|
|
576
|
-
status: action.status
|
|
557
|
+
status: action.status,
|
|
558
|
+
url: action.url
|
|
577
559
|
}
|
|
578
560
|
};
|
|
579
561
|
}
|
|
@@ -651,7 +633,7 @@ const useFetch = () => {
|
|
|
651
633
|
if (onError)
|
|
652
634
|
onError();
|
|
653
635
|
setResponse({
|
|
654
|
-
statusMessage: "Failed to fetch JSON schema. Fallback value 3.
|
|
636
|
+
statusMessage: "Failed to fetch JSON schema. Fallback value 3.3 for schema version used",
|
|
655
637
|
status: ProcessingStatus.ErrorWhenFetchingJSONSchema
|
|
656
638
|
});
|
|
657
639
|
});
|
|
@@ -717,223 +699,6 @@ const useFetch = () => {
|
|
|
717
699
|
fetchLatestJSONSchema
|
|
718
700
|
};
|
|
719
701
|
};
|
|
720
|
-
var ScenarioDrawerState = /* @__PURE__ */ ((ScenarioDrawerState2) => {
|
|
721
|
-
ScenarioDrawerState2[ScenarioDrawerState2["Closed"] = 0] = "Closed";
|
|
722
|
-
ScenarioDrawerState2[ScenarioDrawerState2["Edit"] = 1] = "Edit";
|
|
723
|
-
ScenarioDrawerState2[ScenarioDrawerState2["View"] = 2] = "View";
|
|
724
|
-
return ScenarioDrawerState2;
|
|
725
|
-
})(ScenarioDrawerState || {});
|
|
726
|
-
const emptyScenarioErrors = () => ({
|
|
727
|
-
title: false
|
|
728
|
-
});
|
|
729
|
-
const useScenarioDrawer = (riSc, updateRiSc, scenarioIdFromParams) => {
|
|
730
|
-
const [scenarioDrawerState, setScenarioDrawerState] = useState(
|
|
731
|
-
0 /* Closed */
|
|
732
|
-
);
|
|
733
|
-
const [isNewScenario, setIsNewScenario] = useState(false);
|
|
734
|
-
const [scenario, setScenario] = useState(emptyScenario());
|
|
735
|
-
const [originalScenario, setOriginalScenario] = useState(emptyScenario());
|
|
736
|
-
const [deleteConfirmationIsOpen, setDeleteConfirmationIsOpen] = useState(false);
|
|
737
|
-
const [, setSearchParams] = useSearchParams();
|
|
738
|
-
const [scenarioErrors, setScenarioErrors] = useState(emptyScenarioErrors());
|
|
739
|
-
const navigate = useNavigate();
|
|
740
|
-
const getScenarioPath = useRouteRef(scenarioRouteRef);
|
|
741
|
-
const getRiScPath = useRouteRef(riScRouteRef);
|
|
742
|
-
useEffect(() => {
|
|
743
|
-
if (riSc) {
|
|
744
|
-
if (!scenarioIdFromParams) {
|
|
745
|
-
setScenarioDrawerState(0 /* Closed */);
|
|
746
|
-
const s = emptyScenario();
|
|
747
|
-
setScenario(s);
|
|
748
|
-
setOriginalScenario(s);
|
|
749
|
-
setScenarioErrors(emptyScenarioErrors());
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
if (isNewScenario) {
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
const selectedScenario = riSc.content.scenarios.find(
|
|
756
|
-
(s) => s.ID === scenarioIdFromParams
|
|
757
|
-
);
|
|
758
|
-
if (!selectedScenario) {
|
|
759
|
-
navigate(getRiScPath({ riScId: riSc.id }), {
|
|
760
|
-
state: "Risikoscenarioet du pr\xF8ver \xE5 \xE5pne eksisterer ikke"
|
|
761
|
-
});
|
|
762
|
-
return;
|
|
763
|
-
}
|
|
764
|
-
setScenario(selectedScenario);
|
|
765
|
-
setOriginalScenario(selectedScenario);
|
|
766
|
-
setScenarioDrawerState(2 /* View */);
|
|
767
|
-
}
|
|
768
|
-
}, [riSc, scenarioIdFromParams, getRiScPath, navigate, isNewScenario]);
|
|
769
|
-
const openScenario = (id) => {
|
|
770
|
-
if (riSc) {
|
|
771
|
-
navigate(getScenarioPath({ riScId: riSc.id, scenarioId: id }));
|
|
772
|
-
}
|
|
773
|
-
};
|
|
774
|
-
const openNewScenarioWizard = (id, step) => {
|
|
775
|
-
if (riSc) {
|
|
776
|
-
navigate(`${getScenarioPath({ riScId: riSc.id, scenarioId: id })}?step=${step}`);
|
|
777
|
-
}
|
|
778
|
-
};
|
|
779
|
-
const closeScenario = () => {
|
|
780
|
-
if (riSc) {
|
|
781
|
-
setIsNewScenario(false);
|
|
782
|
-
navigate(getRiScPath({ riScId: riSc.id }));
|
|
783
|
-
}
|
|
784
|
-
};
|
|
785
|
-
const editScenario = (step) => {
|
|
786
|
-
setScenarioDrawerState(0 /* Closed */);
|
|
787
|
-
setSearchParams({ step });
|
|
788
|
-
};
|
|
789
|
-
const validateScenario = () => {
|
|
790
|
-
if (scenario.title === "") {
|
|
791
|
-
setScenarioErrors({
|
|
792
|
-
...scenarioErrors,
|
|
793
|
-
title: true
|
|
794
|
-
});
|
|
795
|
-
return false;
|
|
796
|
-
}
|
|
797
|
-
return true;
|
|
798
|
-
};
|
|
799
|
-
const saveScenario = () => {
|
|
800
|
-
if (riSc) {
|
|
801
|
-
if (validateScenario()) {
|
|
802
|
-
const updatedScenarios = riSc.content.scenarios.some(
|
|
803
|
-
(s) => s.ID === scenario.ID
|
|
804
|
-
) ? riSc.content.scenarios.map(
|
|
805
|
-
(s) => s.ID === scenario.ID ? scenario : s
|
|
806
|
-
) : riSc.content.scenarios.concat(scenario);
|
|
807
|
-
updateRiSc({ ...riSc.content, scenarios: updatedScenarios });
|
|
808
|
-
return true;
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
return false;
|
|
812
|
-
};
|
|
813
|
-
const openDeleteConfirmation = () => setDeleteConfirmationIsOpen(true);
|
|
814
|
-
const abortDeletion = () => setDeleteConfirmationIsOpen(false);
|
|
815
|
-
const confirmDeletion = () => {
|
|
816
|
-
if (riSc) {
|
|
817
|
-
setDeleteConfirmationIsOpen(false);
|
|
818
|
-
closeScenario();
|
|
819
|
-
const updatedScenarios = riSc.content.scenarios.filter(
|
|
820
|
-
(s) => s.ID !== scenario.ID
|
|
821
|
-
);
|
|
822
|
-
updateRiSc({ ...riSc.content, scenarios: updatedScenarios });
|
|
823
|
-
}
|
|
824
|
-
};
|
|
825
|
-
const newScenario = () => {
|
|
826
|
-
if (riSc) {
|
|
827
|
-
setIsNewScenario(true);
|
|
828
|
-
const s = emptyScenario();
|
|
829
|
-
setScenario(s);
|
|
830
|
-
setOriginalScenario(s);
|
|
831
|
-
openNewScenarioWizard(s.ID, "scenario");
|
|
832
|
-
}
|
|
833
|
-
};
|
|
834
|
-
const setTitle = (title) => {
|
|
835
|
-
setScenarioErrors({
|
|
836
|
-
...scenarioErrors,
|
|
837
|
-
title: false
|
|
838
|
-
});
|
|
839
|
-
setScenario({
|
|
840
|
-
...scenario,
|
|
841
|
-
title
|
|
842
|
-
});
|
|
843
|
-
};
|
|
844
|
-
const setDescription = (description) => {
|
|
845
|
-
setScenario({
|
|
846
|
-
...scenario,
|
|
847
|
-
description
|
|
848
|
-
});
|
|
849
|
-
};
|
|
850
|
-
const setThreatActors = (threatActors) => {
|
|
851
|
-
setScenario({
|
|
852
|
-
...scenario,
|
|
853
|
-
threatActors
|
|
854
|
-
});
|
|
855
|
-
};
|
|
856
|
-
const setVulnerabilities = (vulnerabilities) => {
|
|
857
|
-
setScenario({
|
|
858
|
-
...scenario,
|
|
859
|
-
vulnerabilities
|
|
860
|
-
});
|
|
861
|
-
};
|
|
862
|
-
const setProbability = (probabilityLevel) => setScenario({
|
|
863
|
-
...scenario,
|
|
864
|
-
risk: {
|
|
865
|
-
...scenario.risk,
|
|
866
|
-
probability: probabilityOptions[probabilityLevel - 1]
|
|
867
|
-
}
|
|
868
|
-
});
|
|
869
|
-
const setConsequence = (consequenceLevel) => setScenario({
|
|
870
|
-
...scenario,
|
|
871
|
-
risk: {
|
|
872
|
-
...scenario.risk,
|
|
873
|
-
consequence: consequenceOptions[consequenceLevel - 1]
|
|
874
|
-
}
|
|
875
|
-
});
|
|
876
|
-
const setExistingActions = (existingActions) => {
|
|
877
|
-
setScenario({
|
|
878
|
-
...scenario,
|
|
879
|
-
existingActions
|
|
880
|
-
});
|
|
881
|
-
};
|
|
882
|
-
const addAction = () => setScenario({ ...scenario, actions: [...scenario.actions, emptyAction()] });
|
|
883
|
-
const updateAction = (action) => {
|
|
884
|
-
const updatedAction = scenario.actions.some((a) => a.ID === action.ID) ? scenario.actions.map((a) => a.ID === action.ID ? action : a) : [...scenario.actions, action];
|
|
885
|
-
setScenario({ ...scenario, actions: updatedAction });
|
|
886
|
-
};
|
|
887
|
-
const deleteAction = (action) => {
|
|
888
|
-
const updatedAction = scenario.actions.filter((a) => a.ID !== action.ID);
|
|
889
|
-
setScenario({ ...scenario, actions: updatedAction });
|
|
890
|
-
};
|
|
891
|
-
const updateRemainingRisk = (remainingRisk) => setScenario({ ...scenario, remainingRisk });
|
|
892
|
-
const setRemainingProbability = (probabilityLevel) => setScenario({
|
|
893
|
-
...scenario,
|
|
894
|
-
remainingRisk: {
|
|
895
|
-
...scenario.remainingRisk,
|
|
896
|
-
probability: probabilityOptions[probabilityLevel - 1]
|
|
897
|
-
}
|
|
898
|
-
});
|
|
899
|
-
const setRemainingConsequence = (consequenceLevel) => setScenario({
|
|
900
|
-
...scenario,
|
|
901
|
-
remainingRisk: {
|
|
902
|
-
...scenario.remainingRisk,
|
|
903
|
-
consequence: consequenceOptions[consequenceLevel - 1]
|
|
904
|
-
}
|
|
905
|
-
});
|
|
906
|
-
return {
|
|
907
|
-
scenarioDrawerState,
|
|
908
|
-
scenario,
|
|
909
|
-
originalScenario,
|
|
910
|
-
newScenario,
|
|
911
|
-
saveScenario,
|
|
912
|
-
editScenario,
|
|
913
|
-
isNewScenario,
|
|
914
|
-
openScenario,
|
|
915
|
-
closeScenario,
|
|
916
|
-
scenarioErrors,
|
|
917
|
-
validateScenario,
|
|
918
|
-
deleteConfirmationIsOpen,
|
|
919
|
-
openDeleteConfirmation,
|
|
920
|
-
abortDeletion,
|
|
921
|
-
confirmDeletion,
|
|
922
|
-
setTitle,
|
|
923
|
-
setDescription,
|
|
924
|
-
setThreatActors,
|
|
925
|
-
setVulnerabilities,
|
|
926
|
-
setProbability,
|
|
927
|
-
setConsequence,
|
|
928
|
-
setExistingActions,
|
|
929
|
-
addAction,
|
|
930
|
-
updateAction,
|
|
931
|
-
deleteAction,
|
|
932
|
-
updateRemainingRisk,
|
|
933
|
-
setRemainingProbability,
|
|
934
|
-
setRemainingConsequence
|
|
935
|
-
};
|
|
936
|
-
};
|
|
937
702
|
const useFetchRiScs = (riScIdFromParams) => {
|
|
938
703
|
const location = useLocation();
|
|
939
704
|
const navigate = useNavigate();
|
|
@@ -975,7 +740,8 @@ const useFetchRiScs = (riScIdFromParams) => {
|
|
|
975
740
|
return {
|
|
976
741
|
id: riScDTO.riScId,
|
|
977
742
|
content,
|
|
978
|
-
status: riScDTO.riScStatus
|
|
743
|
+
status: riScDTO.riScStatus,
|
|
744
|
+
pullRequestUrl: riScDTO.pullRequestUrl
|
|
979
745
|
};
|
|
980
746
|
});
|
|
981
747
|
setRiScs(fetchedRiScs);
|
|
@@ -1043,7 +809,7 @@ const useFetchRiScs = (riScIdFromParams) => {
|
|
|
1043
809
|
);
|
|
1044
810
|
const newRiSc = {
|
|
1045
811
|
...riSc,
|
|
1046
|
-
schemaVersion: schemaVersion ? schemaVersion : "3.
|
|
812
|
+
schemaVersion: schemaVersion ? schemaVersion : "3.3"
|
|
1047
813
|
};
|
|
1048
814
|
postRiScs(
|
|
1049
815
|
newRiSc,
|
|
@@ -1070,7 +836,7 @@ const useFetchRiScs = (riScIdFromParams) => {
|
|
|
1070
836
|
);
|
|
1071
837
|
},
|
|
1072
838
|
() => {
|
|
1073
|
-
const fallBackSchemaVersion = "3.
|
|
839
|
+
const fallBackSchemaVersion = "3.3";
|
|
1074
840
|
const newRiSc = {
|
|
1075
841
|
...riSc,
|
|
1076
842
|
schemaVersion: fallBackSchemaVersion
|
|
@@ -1172,53 +938,314 @@ const useFetchRiScs = (riScIdFromParams) => {
|
|
|
1172
938
|
};
|
|
1173
939
|
};
|
|
1174
940
|
|
|
1175
|
-
const
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
941
|
+
const emptyAction = () => ({
|
|
942
|
+
ID: generateRandomId(),
|
|
943
|
+
title: "",
|
|
944
|
+
description: "",
|
|
945
|
+
owner: "",
|
|
946
|
+
deadline: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
947
|
+
status: "Not started",
|
|
948
|
+
url: ""
|
|
949
|
+
});
|
|
950
|
+
const emptyScenario = () => ({
|
|
951
|
+
ID: generateRandomId(),
|
|
952
|
+
title: "",
|
|
953
|
+
description: "",
|
|
954
|
+
threatActors: [],
|
|
955
|
+
vulnerabilities: [],
|
|
956
|
+
risk: {
|
|
957
|
+
summary: "",
|
|
958
|
+
probability: 0.01,
|
|
959
|
+
consequence: 1e3
|
|
960
|
+
},
|
|
961
|
+
existingActions: "",
|
|
962
|
+
actions: [],
|
|
963
|
+
remainingRisk: {
|
|
964
|
+
summary: "",
|
|
965
|
+
probability: 0.01,
|
|
966
|
+
consequence: 1e3
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
const ScenarioContext = React.createContext(
|
|
970
|
+
void 0
|
|
971
|
+
);
|
|
972
|
+
const ScenarioProvider = ({
|
|
973
|
+
riSc,
|
|
974
|
+
updateRiSc,
|
|
975
|
+
scenarioIdFromParams,
|
|
976
|
+
children
|
|
977
|
+
}) => {
|
|
978
|
+
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
|
979
|
+
const [isNewScenario, setIsNewScenario] = useState(false);
|
|
980
|
+
const [formErrors, _setFormErrors] = useState({});
|
|
981
|
+
const [scenario, setScenario] = useState(emptyScenario());
|
|
982
|
+
const [originalScenario, setOriginalScenario] = useState(emptyScenario());
|
|
983
|
+
const [deleteConfirmationIsOpen, setDeleteConfirmationIsOpen] = useState(false);
|
|
984
|
+
const [, setSearchParams] = useSearchParams();
|
|
985
|
+
const navigate = useNavigate();
|
|
986
|
+
const getScenarioPath = useRouteRef(scenarioRouteRef);
|
|
987
|
+
const getRiScPath = useRouteRef(riScRouteRef);
|
|
988
|
+
useEffect(() => {
|
|
989
|
+
if (riSc) {
|
|
990
|
+
if (!scenarioIdFromParams) {
|
|
991
|
+
setIsDrawerOpen(false);
|
|
992
|
+
const s = emptyScenario();
|
|
993
|
+
setScenario(s);
|
|
994
|
+
setOriginalScenario(s);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (isNewScenario) {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
const selectedScenario = riSc.content.scenarios.find(
|
|
1001
|
+
(s) => s.ID === scenarioIdFromParams
|
|
1002
|
+
);
|
|
1003
|
+
if (!selectedScenario) {
|
|
1004
|
+
navigate(getRiScPath({ riScId: riSc.id }), {
|
|
1005
|
+
state: "Risikoscenarioet du pr\xF8ver \xE5 \xE5pne eksisterer ikke"
|
|
1006
|
+
});
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
setScenario(selectedScenario);
|
|
1010
|
+
setOriginalScenario(selectedScenario);
|
|
1011
|
+
setIsDrawerOpen(true);
|
|
1012
|
+
}
|
|
1013
|
+
}, [riSc, scenarioIdFromParams, getRiScPath, navigate, isNewScenario]);
|
|
1014
|
+
const openScenario = (id) => {
|
|
1015
|
+
if (riSc) {
|
|
1016
|
+
navigate(getScenarioPath({ riScId: riSc.id, scenarioId: id }));
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
const openNewScenarioWizard = (id, step) => {
|
|
1020
|
+
if (riSc) {
|
|
1021
|
+
navigate(
|
|
1022
|
+
`${getScenarioPath({ riScId: riSc.id, scenarioId: id })}?step=${step}`
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
const closeScenario = () => {
|
|
1027
|
+
if (riSc) {
|
|
1028
|
+
setIsNewScenario(false);
|
|
1029
|
+
navigate(getRiScPath({ riScId: riSc.id }));
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
const editScenario = (step) => {
|
|
1033
|
+
setSearchParams({ step });
|
|
1034
|
+
};
|
|
1035
|
+
const validateScenario = () => {
|
|
1036
|
+
if (scenario.title === "") {
|
|
1037
|
+
return false;
|
|
1038
|
+
}
|
|
1039
|
+
return true;
|
|
1040
|
+
};
|
|
1041
|
+
const saveScenario = () => {
|
|
1042
|
+
if (riSc) {
|
|
1043
|
+
if (validateScenario()) {
|
|
1044
|
+
const updatedScenarios = riSc.content.scenarios.some(
|
|
1045
|
+
(s) => s.ID === scenario.ID
|
|
1046
|
+
) ? riSc.content.scenarios.map(
|
|
1047
|
+
(s) => s.ID === scenario.ID ? scenario : s
|
|
1048
|
+
) : riSc.content.scenarios.concat(scenario);
|
|
1049
|
+
updateRiSc({ ...riSc.content, scenarios: updatedScenarios });
|
|
1050
|
+
return true;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
return false;
|
|
1054
|
+
};
|
|
1055
|
+
const submitEditedScenarioToRiSc = (editedScenario) => {
|
|
1056
|
+
if (riSc) {
|
|
1057
|
+
updateRiSc({
|
|
1058
|
+
...riSc.content,
|
|
1059
|
+
scenarios: riSc.content.scenarios.map(
|
|
1060
|
+
(s) => s.ID === editedScenario.ID ? editedScenario : s
|
|
1061
|
+
)
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
const openDeleteConfirmation = () => setDeleteConfirmationIsOpen(true);
|
|
1066
|
+
const abortDeletion = () => setDeleteConfirmationIsOpen(false);
|
|
1067
|
+
const confirmDeletion = () => {
|
|
1068
|
+
if (riSc) {
|
|
1069
|
+
setDeleteConfirmationIsOpen(false);
|
|
1070
|
+
closeScenario();
|
|
1071
|
+
const updatedScenarios = riSc.content.scenarios.filter(
|
|
1072
|
+
(s) => s.ID !== scenario.ID
|
|
1073
|
+
);
|
|
1074
|
+
updateRiSc({ ...riSc.content, scenarios: updatedScenarios });
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
const newScenario = () => {
|
|
1078
|
+
if (riSc) {
|
|
1079
|
+
setIsNewScenario(true);
|
|
1080
|
+
const s = emptyScenario();
|
|
1081
|
+
setScenario(s);
|
|
1082
|
+
setOriginalScenario(s);
|
|
1083
|
+
openNewScenarioWizard(s.ID, "scenario");
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
const setScenarioValue = (key, value2) => {
|
|
1087
|
+
setScenario({
|
|
1088
|
+
...scenario,
|
|
1089
|
+
[key]: value2
|
|
1090
|
+
});
|
|
1091
|
+
};
|
|
1092
|
+
const addAction = () => setScenario({ ...scenario, actions: [...scenario.actions, emptyAction()] });
|
|
1093
|
+
const updateAction = (action) => {
|
|
1094
|
+
const updatedAction = scenario.actions.some((a) => a.ID === action.ID) ? scenario.actions.map((a) => a.ID === action.ID ? action : a) : [...scenario.actions, action];
|
|
1095
|
+
setScenario({ ...scenario, actions: updatedAction });
|
|
1096
|
+
};
|
|
1097
|
+
const deleteAction = (action) => {
|
|
1098
|
+
const updatedAction = scenario.actions.filter((a) => a.ID !== action.ID);
|
|
1099
|
+
setScenario({ ...scenario, actions: updatedAction });
|
|
1100
|
+
};
|
|
1101
|
+
const setProbability = (probabilityLevel) => setScenario({
|
|
1102
|
+
...scenario,
|
|
1103
|
+
risk: {
|
|
1104
|
+
...scenario.risk,
|
|
1105
|
+
probability: probabilityOptions[probabilityLevel - 1]
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
const setConsequence = (consequenceLevel) => setScenario({
|
|
1109
|
+
...scenario,
|
|
1110
|
+
risk: {
|
|
1111
|
+
...scenario.risk,
|
|
1112
|
+
consequence: consequenceOptions[consequenceLevel - 1]
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
const setRemainingProbability = (probabilityLevel) => setScenario({
|
|
1116
|
+
...scenario,
|
|
1117
|
+
remainingRisk: {
|
|
1118
|
+
...scenario.remainingRisk,
|
|
1119
|
+
probability: probabilityOptions[probabilityLevel - 1]
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
const setRemainingConsequence = (consequenceLevel) => setScenario({
|
|
1123
|
+
...scenario,
|
|
1124
|
+
remainingRisk: {
|
|
1125
|
+
...scenario.remainingRisk,
|
|
1126
|
+
consequence: consequenceOptions[consequenceLevel - 1]
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
const setProbabilityAndRemainingProbability = (probabilityLevel) => setScenario({
|
|
1130
|
+
...scenario,
|
|
1131
|
+
risk: {
|
|
1132
|
+
...scenario.risk,
|
|
1133
|
+
probability: probabilityOptions[probabilityLevel - 1]
|
|
1134
|
+
},
|
|
1135
|
+
remainingRisk: {
|
|
1136
|
+
...scenario.remainingRisk,
|
|
1137
|
+
probability: probabilityOptions[probabilityLevel - 1]
|
|
1138
|
+
}
|
|
1139
|
+
});
|
|
1140
|
+
const setConsequenceAndRemainingConsequence = (consequenceLevel) => setScenario({
|
|
1141
|
+
...scenario,
|
|
1142
|
+
risk: {
|
|
1143
|
+
...scenario.risk,
|
|
1144
|
+
consequence: consequenceOptions[consequenceLevel - 1]
|
|
1145
|
+
},
|
|
1146
|
+
remainingRisk: {
|
|
1147
|
+
...scenario.remainingRisk,
|
|
1148
|
+
consequence: consequenceOptions[consequenceLevel - 1]
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
const setFormError = (key) => {
|
|
1152
|
+
_setFormErrors({ ...formErrors, [key]: true });
|
|
1153
|
+
};
|
|
1154
|
+
const removeFormError = (key) => {
|
|
1155
|
+
delete formErrors[key];
|
|
1156
|
+
_setFormErrors({ ...formErrors });
|
|
1157
|
+
};
|
|
1158
|
+
const formFieldHasErrors = (key) => Object.keys(formErrors).includes(key);
|
|
1159
|
+
const hasFormErrors = () => Object.keys(formErrors).length > 0;
|
|
1160
|
+
const value = {
|
|
1161
|
+
isDrawerOpen,
|
|
1162
|
+
scenario,
|
|
1163
|
+
originalScenario,
|
|
1164
|
+
newScenario,
|
|
1165
|
+
saveScenario,
|
|
1166
|
+
editScenario,
|
|
1167
|
+
isNewScenario,
|
|
1168
|
+
submitEditedScenarioToRiSc,
|
|
1169
|
+
openScenario,
|
|
1170
|
+
closeScenario,
|
|
1171
|
+
validateScenario,
|
|
1172
|
+
deleteConfirmationIsOpen,
|
|
1173
|
+
openDeleteConfirmation,
|
|
1174
|
+
abortDeletion,
|
|
1175
|
+
confirmDeletion,
|
|
1176
|
+
setScenarioValue,
|
|
1177
|
+
addAction,
|
|
1178
|
+
updateAction,
|
|
1179
|
+
deleteAction,
|
|
1180
|
+
setProbability,
|
|
1181
|
+
setConsequence,
|
|
1182
|
+
setRemainingProbability,
|
|
1183
|
+
setRemainingConsequence,
|
|
1184
|
+
setProbabilityAndRemainingProbability,
|
|
1185
|
+
setConsequenceAndRemainingConsequence,
|
|
1186
|
+
setFormError,
|
|
1187
|
+
hasFormErrors,
|
|
1188
|
+
removeFormError,
|
|
1189
|
+
formFieldHasErrors
|
|
1190
|
+
};
|
|
1191
|
+
return /* @__PURE__ */ React.createElement(ScenarioContext.Provider, { value }, children);
|
|
1192
|
+
};
|
|
1193
|
+
const useScenario = () => {
|
|
1194
|
+
const context = React.useContext(ScenarioContext);
|
|
1195
|
+
if (context === void 0) {
|
|
1196
|
+
throw new Error("useScenario must be used within a ScenarioProvider");
|
|
1197
|
+
}
|
|
1198
|
+
return context;
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1201
|
+
const menuProps = {
|
|
1202
|
+
PaperProps: {
|
|
1203
|
+
style: {
|
|
1204
|
+
maxHeight: 255
|
|
1205
|
+
}
|
|
1206
|
+
},
|
|
1207
|
+
getContentAnchorEl: null,
|
|
1208
|
+
anchorOrigin: {
|
|
1209
|
+
vertical: "bottom",
|
|
1210
|
+
horizontal: "center"
|
|
1211
|
+
},
|
|
1212
|
+
transformOrigin: {
|
|
1213
|
+
vertical: "top",
|
|
1214
|
+
horizontal: "center"
|
|
1215
|
+
},
|
|
1216
|
+
variant: "menu"
|
|
1217
|
+
};
|
|
1218
|
+
const useFontStyles = makeStyles((theme) => ({
|
|
1219
|
+
h1: {
|
|
1220
|
+
fontSize: theme.spacing(4),
|
|
1221
|
+
fontWeight: 700
|
|
1222
|
+
},
|
|
1223
|
+
h2: {
|
|
1224
|
+
fontSize: theme.spacing(3.5),
|
|
1225
|
+
fontWeight: 500
|
|
1226
|
+
},
|
|
1227
|
+
h3: {
|
|
1228
|
+
fontSize: theme.spacing(2.5),
|
|
1229
|
+
fontWeight: 500
|
|
1230
|
+
},
|
|
1231
|
+
body1: {
|
|
1232
|
+
fontSize: theme.spacing(2),
|
|
1233
|
+
fontWeight: 500
|
|
1208
1234
|
},
|
|
1209
1235
|
body2: {
|
|
1210
1236
|
fontSize: theme.spacing(2),
|
|
1211
|
-
fontWeight: 400
|
|
1237
|
+
fontWeight: 400,
|
|
1238
|
+
whiteSpace: "pre-line"
|
|
1212
1239
|
},
|
|
1213
1240
|
label: {
|
|
1214
1241
|
fontSize: theme.spacing(1.75),
|
|
1215
|
-
fontWeight:
|
|
1242
|
+
fontWeight: 700,
|
|
1216
1243
|
textTransform: "uppercase",
|
|
1217
1244
|
color: theme.palette.type === "dark" ? "#F8F8F8" : "rgba(0, 0, 0, 0.87)",
|
|
1218
1245
|
paddingBottom: "0.4rem"
|
|
1219
1246
|
},
|
|
1220
1247
|
labelSubtitle: {
|
|
1221
|
-
fontSize: theme.spacing(1.
|
|
1248
|
+
fontSize: theme.spacing(1.75),
|
|
1222
1249
|
fontWeight: 400,
|
|
1223
1250
|
color: theme.palette.type === "dark" ? "#F8F8F8" : "rgba(0, 0, 0, 0.87)",
|
|
1224
1251
|
paddingBottom: "0.4rem",
|
|
@@ -1244,9 +1271,6 @@ const useFontStyles = makeStyles((theme) => ({
|
|
|
1244
1271
|
paddingBottom: "1rem",
|
|
1245
1272
|
marginTop: "-0.2rem"
|
|
1246
1273
|
},
|
|
1247
|
-
button: {
|
|
1248
|
-
textTransform: "none"
|
|
1249
|
-
},
|
|
1250
1274
|
risikoLevel: {
|
|
1251
1275
|
fontSize: theme.spacing(2.25),
|
|
1252
1276
|
fontWeight: 700,
|
|
@@ -1299,14 +1323,40 @@ const TextField = ({
|
|
|
1299
1323
|
label,
|
|
1300
1324
|
subtitle,
|
|
1301
1325
|
value,
|
|
1302
|
-
error,
|
|
1303
1326
|
required,
|
|
1304
1327
|
minRows = 1,
|
|
1305
|
-
handleChange
|
|
1328
|
+
handleChange,
|
|
1329
|
+
validateInput,
|
|
1330
|
+
errorMessage,
|
|
1331
|
+
errorKey
|
|
1306
1332
|
}) => {
|
|
1333
|
+
const [hasError, setHasError] = useState(false);
|
|
1334
|
+
const { setFormError, removeFormError, formFieldHasErrors } = useScenario();
|
|
1307
1335
|
const { formLabel, formControl, root } = useInputFieldStyles();
|
|
1308
1336
|
const { labelSubtitle } = useFontStyles();
|
|
1309
|
-
const onChange = (event) =>
|
|
1337
|
+
const onChange = (event) => {
|
|
1338
|
+
if (handleChange) {
|
|
1339
|
+
handleChange(event.target.value);
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
const onBlur = (event) => {
|
|
1343
|
+
if (!validateInput && !required) {
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
const isValid = validateInput ? validateInput(event.target.value) : true;
|
|
1347
|
+
const requiredValid = required ? event.target.value.length > 0 : true;
|
|
1348
|
+
const validationResult = isValid && requiredValid;
|
|
1349
|
+
setHasError(!validationResult);
|
|
1350
|
+
if (!errorKey) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
if (validationResult) {
|
|
1354
|
+
removeFormError(errorKey);
|
|
1355
|
+
} else {
|
|
1356
|
+
setFormError(errorKey);
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
1359
|
+
const fieldError = hasError || (errorKey ? formFieldHasErrors(errorKey) : false);
|
|
1310
1360
|
return /* @__PURE__ */ React.createElement(FormControl, { className: formControl }, label && /* @__PURE__ */ React.createElement(FormLabel, { className: formLabel, required }, label), subtitle && /* @__PURE__ */ React.createElement(FormHelperText, { className: labelSubtitle }, subtitle), /* @__PURE__ */ React.createElement(
|
|
1311
1361
|
TextField$1,
|
|
1312
1362
|
{
|
|
@@ -1319,10 +1369,11 @@ const TextField = ({
|
|
|
1319
1369
|
minRows,
|
|
1320
1370
|
variant: "outlined",
|
|
1321
1371
|
onChange,
|
|
1322
|
-
error:
|
|
1372
|
+
error: fieldError,
|
|
1373
|
+
onBlur,
|
|
1323
1374
|
InputProps: { className: root }
|
|
1324
1375
|
}
|
|
1325
|
-
),
|
|
1376
|
+
), fieldError && /* @__PURE__ */ React.createElement(FormHelperText, { error: true }, errorMessage));
|
|
1326
1377
|
};
|
|
1327
1378
|
|
|
1328
1379
|
const Dropdown = ({
|
|
@@ -1363,7 +1414,7 @@ const Dropdown = ({
|
|
|
1363
1414
|
selected.map((value) => /* @__PURE__ */ React.createElement(Chip, { key: value, label: renderSelectedValueHandler(value) }))
|
|
1364
1415
|
) : selected;
|
|
1365
1416
|
return /* @__PURE__ */ React.createElement(FormControl$1, { className: formControl }, label && /* @__PURE__ */ React.createElement(FormLabel$1, { className: formLabel, required }, label), /* @__PURE__ */ React.createElement(
|
|
1366
|
-
Select,
|
|
1417
|
+
Select$1,
|
|
1367
1418
|
{
|
|
1368
1419
|
multiple,
|
|
1369
1420
|
value: selectedValues,
|
|
@@ -1380,23 +1431,19 @@ const Dropdown = ({
|
|
|
1380
1431
|
}
|
|
1381
1432
|
} : {}
|
|
1382
1433
|
},
|
|
1383
|
-
options.map((name) => /* @__PURE__ */ React.createElement(MenuItem, { key: getOptionsValue(name), value: getOptionsValue(name) }, multiple && /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(
|
|
1434
|
+
options.map((name) => /* @__PURE__ */ React.createElement(MenuItem, { key: getOptionsValue(name), value: getOptionsValue(name) }, multiple && /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(
|
|
1435
|
+
Checkbox,
|
|
1436
|
+
{
|
|
1437
|
+
checked: selectedValues.indexOf(getOptionsValue(name)) > -1
|
|
1438
|
+
}
|
|
1439
|
+
)), /* @__PURE__ */ React.createElement(ListItemText, { primary: getOptionsRenderValue(name) })))
|
|
1384
1440
|
), error && /* @__PURE__ */ React.createElement(FormHelperText, { error: true }, error));
|
|
1385
1441
|
};
|
|
1386
1442
|
|
|
1387
|
-
const ScenarioContext = createContext(null);
|
|
1388
|
-
|
|
1389
1443
|
const ScenarioStep = () => {
|
|
1390
1444
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
1391
1445
|
const { labelSubtitle, label, h2, subtitle2 } = useFontStyles();
|
|
1392
|
-
const {
|
|
1393
|
-
scenario,
|
|
1394
|
-
scenarioErrors,
|
|
1395
|
-
setTitle,
|
|
1396
|
-
setDescription,
|
|
1397
|
-
setThreatActors,
|
|
1398
|
-
setVulnerabilities
|
|
1399
|
-
} = useContext(ScenarioContext);
|
|
1446
|
+
const { scenario, setScenarioValue } = useScenario();
|
|
1400
1447
|
const translatedThreatActors = threatActorsOptions.map((threatActor) => {
|
|
1401
1448
|
return {
|
|
1402
1449
|
value: threatActor,
|
|
@@ -1404,22 +1451,25 @@ const ScenarioStep = () => {
|
|
|
1404
1451
|
renderedValue: t(`threatActors.${threatActor}`)
|
|
1405
1452
|
};
|
|
1406
1453
|
});
|
|
1407
|
-
const translatedVulnerabilities = vulnerabilitiesOptions.map(
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1454
|
+
const translatedVulnerabilities = vulnerabilitiesOptions.map(
|
|
1455
|
+
(vulnerability) => {
|
|
1456
|
+
return {
|
|
1457
|
+
value: vulnerability,
|
|
1458
|
+
/* @ts-ignore Because ts can't typecheck strings agains our keys */
|
|
1459
|
+
renderedValue: t(`vulnerabilities.${vulnerability}`)
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
);
|
|
1414
1463
|
return /* @__PURE__ */ React.createElement(Grid, { container: true }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography, { className: h2 }, t("scenarioDrawer.title")), /* @__PURE__ */ React.createElement(Typography, { className: subtitle2 }, t("scenarioDrawer.subtitle"))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
|
|
1415
1464
|
TextField,
|
|
1416
1465
|
{
|
|
1417
1466
|
label: t("dictionary.title"),
|
|
1418
1467
|
value: scenario.title,
|
|
1419
|
-
|
|
1468
|
+
errorMessage: t("scenarioDrawer.titleError"),
|
|
1469
|
+
errorKey: "scenario-title",
|
|
1420
1470
|
required: true,
|
|
1421
1471
|
minRows: 1,
|
|
1422
|
-
handleChange:
|
|
1472
|
+
handleChange: (value) => setScenarioValue("title", value)
|
|
1423
1473
|
}
|
|
1424
1474
|
)), /* @__PURE__ */ React.createElement(
|
|
1425
1475
|
Grid,
|
|
@@ -1438,7 +1488,7 @@ const ScenarioStep = () => {
|
|
|
1438
1488
|
{
|
|
1439
1489
|
selectedValues: scenario.threatActors,
|
|
1440
1490
|
options: translatedThreatActors,
|
|
1441
|
-
handleChange:
|
|
1491
|
+
handleChange: (value) => setScenarioValue("threatActors", value),
|
|
1442
1492
|
renderSelectedValue: (value) => {
|
|
1443
1493
|
return t(`threatActors.${value}`);
|
|
1444
1494
|
}
|
|
@@ -1461,7 +1511,7 @@ const ScenarioStep = () => {
|
|
|
1461
1511
|
{
|
|
1462
1512
|
selectedValues: scenario.vulnerabilities,
|
|
1463
1513
|
options: translatedVulnerabilities,
|
|
1464
|
-
handleChange:
|
|
1514
|
+
handleChange: (value) => setScenarioValue("vulnerabilities", value),
|
|
1465
1515
|
renderSelectedValue: (value) => {
|
|
1466
1516
|
return t(`vulnerabilities.${value}`);
|
|
1467
1517
|
}
|
|
@@ -1473,7 +1523,7 @@ const ScenarioStep = () => {
|
|
|
1473
1523
|
label: t("dictionary.description"),
|
|
1474
1524
|
value: scenario.description,
|
|
1475
1525
|
minRows: 4,
|
|
1476
|
-
handleChange:
|
|
1526
|
+
handleChange: (value) => setScenarioValue("description", value)
|
|
1477
1527
|
}
|
|
1478
1528
|
)));
|
|
1479
1529
|
};
|
|
@@ -1485,30 +1535,13 @@ const ActionEdit = ({
|
|
|
1485
1535
|
deleteAction
|
|
1486
1536
|
}) => {
|
|
1487
1537
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
1488
|
-
const { paper
|
|
1489
|
-
const { label
|
|
1490
|
-
const
|
|
1491
|
-
const
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
});
|
|
1495
|
-
const setStatus = (status) => updateAction({
|
|
1496
|
-
...action,
|
|
1497
|
-
status
|
|
1498
|
-
});
|
|
1499
|
-
const setDeadline = (deadline) => {
|
|
1500
|
-
if (deadline) {
|
|
1501
|
-
const formattedDeadline = new Date(deadline).toISOString().split("T")[0];
|
|
1502
|
-
updateAction({
|
|
1503
|
-
...action,
|
|
1504
|
-
deadline: formattedDeadline
|
|
1505
|
-
});
|
|
1506
|
-
}
|
|
1538
|
+
const { paper } = useInputFieldStyles();
|
|
1539
|
+
const { label } = useFontStyles();
|
|
1540
|
+
const setActionField = (field, value) => updateAction({ ...action, [field]: value });
|
|
1541
|
+
const validateUrl = (value) => {
|
|
1542
|
+
const urlRegex = /^https?:\/\/[a-z\d.-]+\.[a-z]{2,6}(\/[\w .-]*)*\/?$/;
|
|
1543
|
+
return urlRegex.test(value);
|
|
1507
1544
|
};
|
|
1508
|
-
const setOwner = (owner) => updateAction({
|
|
1509
|
-
...action,
|
|
1510
|
-
owner
|
|
1511
|
-
});
|
|
1512
1545
|
return /* @__PURE__ */ React.createElement(Paper, { className: paper }, /* @__PURE__ */ React.createElement(Grid, { container: true, style: { display: "flex", rowGap: "0.7rem" } }, /* @__PURE__ */ React.createElement(
|
|
1513
1546
|
Grid,
|
|
1514
1547
|
{
|
|
@@ -1536,24 +1569,24 @@ const ActionEdit = ({
|
|
|
1536
1569
|
{
|
|
1537
1570
|
label: t("dictionary.description"),
|
|
1538
1571
|
value: action.description,
|
|
1539
|
-
handleChange:
|
|
1540
|
-
|
|
1572
|
+
handleChange: (value) => setActionField("description", value),
|
|
1573
|
+
errorMessage: t("scenarioDrawer.action.descriptionError"),
|
|
1574
|
+
errorKey: `${index}-action-description`,
|
|
1575
|
+
minRows: 1,
|
|
1576
|
+
required: true
|
|
1541
1577
|
}
|
|
1542
|
-
)), /* @__PURE__ */ React.createElement(
|
|
1543
|
-
|
|
1578
|
+
)), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 9, xs: 12 }, /* @__PURE__ */ React.createElement(
|
|
1579
|
+
TextField,
|
|
1544
1580
|
{
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
/* @__PURE__ */ React.createElement(Typography, { className: labelSubtitle }, t("scenarioDrawer.measureTab.measureOwnerDescription")),
|
|
1555
|
-
/* @__PURE__ */ React.createElement(TextField, { value: action.owner, handleChange: setOwner, minRows: 1 })
|
|
1556
|
-
), /* @__PURE__ */ React.createElement(
|
|
1581
|
+
label: t("dictionary.url"),
|
|
1582
|
+
value: action.url,
|
|
1583
|
+
handleChange: (value) => setActionField("url", value),
|
|
1584
|
+
validateInput: validateUrl,
|
|
1585
|
+
errorMessage: t("scenarioDrawer.action.urlError"),
|
|
1586
|
+
minRows: 1,
|
|
1587
|
+
errorKey: `${index}-action-url`
|
|
1588
|
+
}
|
|
1589
|
+
)), /* @__PURE__ */ React.createElement(
|
|
1557
1590
|
Grid,
|
|
1558
1591
|
{
|
|
1559
1592
|
item: true,
|
|
@@ -1561,75 +1594,33 @@ const ActionEdit = ({
|
|
|
1561
1594
|
xs: 12,
|
|
1562
1595
|
style: {
|
|
1563
1596
|
display: "flex",
|
|
1564
|
-
flexDirection: "column"
|
|
1565
|
-
justifyContent: "flex-end"
|
|
1597
|
+
flexDirection: "column"
|
|
1566
1598
|
}
|
|
1567
1599
|
},
|
|
1568
|
-
/* @__PURE__ */ React.createElement(Typography, { className: label }, t("dictionary.status")),
|
|
1569
1600
|
/* @__PURE__ */ React.createElement(
|
|
1570
1601
|
Dropdown,
|
|
1571
1602
|
{
|
|
1572
|
-
options: actionStatusOptions,
|
|
1573
|
-
selectedValues: action.status,
|
|
1574
|
-
handleChange:
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
), /* @__PURE__ */ React.createElement(
|
|
1578
|
-
Grid,
|
|
1579
|
-
{
|
|
1580
|
-
item: true,
|
|
1581
|
-
md: 3,
|
|
1582
|
-
xs: 12,
|
|
1583
|
-
style: {
|
|
1584
|
-
display: "flex",
|
|
1585
|
-
flexDirection: "column",
|
|
1586
|
-
justifyContent: "flex-end"
|
|
1587
|
-
}
|
|
1588
|
-
},
|
|
1589
|
-
/* @__PURE__ */ React.createElement(Typography, { className: label }, t("dictionary.deadline")),
|
|
1590
|
-
/* @__PURE__ */ React.createElement(FormControl$1, { className: formControl }, /* @__PURE__ */ React.createElement(LocalizationProvider, { dateAdapter: AdapterDateFns, adapterLocale: nb }, /* @__PURE__ */ React.createElement(
|
|
1591
|
-
DatePicker,
|
|
1592
|
-
{
|
|
1593
|
-
value: action.deadline,
|
|
1594
|
-
onChange: setDeadline,
|
|
1595
|
-
sx: {
|
|
1596
|
-
".MuiInputBase-root": {
|
|
1597
|
-
color: theme.palette.type === "dark" ? "white" : "black"
|
|
1598
|
-
},
|
|
1599
|
-
".MuiOutlinedInput-notchedOutline": {
|
|
1600
|
-
borderColor: theme.palette.type === "dark" ? "#616161" : "#0000003b"
|
|
1601
|
-
},
|
|
1602
|
-
".MuiOutlinedInput-root": {
|
|
1603
|
-
"&:hover .MuiOutlinedInput-notchedOutline": {
|
|
1604
|
-
borderColor: theme.palette.type === "dark" ? "white" : "black"
|
|
1605
|
-
}
|
|
1606
|
-
},
|
|
1607
|
-
".MuiIconButton-root": {
|
|
1608
|
-
color: theme.palette.type === "dark" ? "white" : "black"
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1603
|
+
options: actionStatusOptions,
|
|
1604
|
+
selectedValues: action.status,
|
|
1605
|
+
handleChange: (value) => setActionField("status", value),
|
|
1606
|
+
label: t("dictionary.status"),
|
|
1607
|
+
required: true
|
|
1611
1608
|
}
|
|
1612
|
-
)
|
|
1609
|
+
)
|
|
1613
1610
|
)));
|
|
1614
1611
|
};
|
|
1615
1612
|
|
|
1616
1613
|
const ActionsStep = () => {
|
|
1617
1614
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
1618
1615
|
const { h2, subtitle2, actionSubtitle } = useFontStyles();
|
|
1619
|
-
const {
|
|
1620
|
-
scenario,
|
|
1621
|
-
setExistingActions,
|
|
1622
|
-
updateAction,
|
|
1623
|
-
deleteAction,
|
|
1624
|
-
addAction
|
|
1625
|
-
} = useContext(ScenarioContext);
|
|
1616
|
+
const { scenario, setScenarioValue, updateAction, deleteAction, addAction } = useScenario();
|
|
1626
1617
|
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { className: h2 }, t("dictionary.measure")), /* @__PURE__ */ React.createElement(Typography, { className: subtitle2 }, t("scenarioDrawer.measureTab.subtitle")), /* @__PURE__ */ React.createElement(Grid$1, { item: true, xs: 12, style: { paddingTop: "1.5rem" } }, /* @__PURE__ */ React.createElement(
|
|
1627
1618
|
TextField,
|
|
1628
1619
|
{
|
|
1629
1620
|
label: t("scenarioDrawer.measureTab.existingMeasure"),
|
|
1630
1621
|
subtitle: t("scenarioDrawer.measureTab.existingMeasureSubtitle"),
|
|
1631
1622
|
value: scenario.existingActions,
|
|
1632
|
-
handleChange:
|
|
1623
|
+
handleChange: (value) => setScenarioValue("existingActions", value),
|
|
1633
1624
|
minRows: 3
|
|
1634
1625
|
}
|
|
1635
1626
|
)), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: actionSubtitle }, t("scenarioDrawer.measureTab.plannedMeasures")), scenario.actions.map((action, index) => /* @__PURE__ */ React.createElement(
|
|
@@ -1690,12 +1681,11 @@ const ProbabilityTable = ({
|
|
|
1690
1681
|
const theme = useTheme();
|
|
1691
1682
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
1692
1683
|
const { table, cell, radio } = useTableStyles$1();
|
|
1693
|
-
const handleChangeRow = (row) => () => handleChange(row);
|
|
1694
1684
|
const radioCell = (row) => /* @__PURE__ */ React.createElement("th", { scope: "col" }, /* @__PURE__ */ React.createElement("div", { className: radio }, /* @__PURE__ */ React.createElement(
|
|
1695
1685
|
Radio,
|
|
1696
1686
|
{
|
|
1697
1687
|
checked: selectedValue === row,
|
|
1698
|
-
onChange:
|
|
1688
|
+
onChange: () => handleChange(row),
|
|
1699
1689
|
style: {
|
|
1700
1690
|
padding: 0,
|
|
1701
1691
|
color: theme.palette.type === "dark" ? "#9BC9FE" : theme.palette.primary.main
|
|
@@ -1713,13 +1703,12 @@ const ConsequenceTable = ({
|
|
|
1713
1703
|
const theme = useTheme();
|
|
1714
1704
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
1715
1705
|
const { table, labelCell, cell, voidCell, radio } = useTableStyles$1();
|
|
1716
|
-
const handleChangeRow = (row) => () => handleChange(row);
|
|
1717
1706
|
const getRadioCell = (row) => {
|
|
1718
1707
|
return /* @__PURE__ */ React.createElement("th", { scope: "col" }, /* @__PURE__ */ React.createElement("div", { className: radio }, /* @__PURE__ */ React.createElement(
|
|
1719
1708
|
Radio,
|
|
1720
1709
|
{
|
|
1721
1710
|
checked: selectedValue === row,
|
|
1722
|
-
onChange:
|
|
1711
|
+
onChange: () => handleChange(row),
|
|
1723
1712
|
style: {
|
|
1724
1713
|
padding: 0,
|
|
1725
1714
|
color: theme.palette.type === "dark" ? theme.palette.primary.light : theme.palette.primary.main
|
|
@@ -1758,41 +1747,45 @@ const RiskStep = ({ riskType, restEqualsInitial }) => {
|
|
|
1758
1747
|
setConsequence,
|
|
1759
1748
|
setProbability,
|
|
1760
1749
|
setRemainingConsequence,
|
|
1761
|
-
setRemainingProbability
|
|
1762
|
-
|
|
1750
|
+
setRemainingProbability,
|
|
1751
|
+
setProbabilityAndRemainingProbability,
|
|
1752
|
+
setConsequenceAndRemainingConsequence
|
|
1753
|
+
} = useScenario();
|
|
1763
1754
|
const resourceKey = riskType === "initial" ? "initialRiskStep" : "restRiskStep";
|
|
1764
1755
|
const risk = riskType === "initial" ? scenario.risk : scenario.remainingRisk;
|
|
1765
|
-
|
|
1766
|
-
if (
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1756
|
+
const handleProbabilityChange = (probabilityLevel) => {
|
|
1757
|
+
if (riskType === "initial") {
|
|
1758
|
+
if (restEqualsInitial) {
|
|
1759
|
+
setProbabilityAndRemainingProbability(probabilityLevel);
|
|
1760
|
+
} else {
|
|
1761
|
+
setProbability(probabilityLevel);
|
|
1762
|
+
}
|
|
1763
|
+
} else {
|
|
1764
|
+
setRemainingProbability(probabilityLevel);
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
const handleConsequenceChange = (consequenceLevel) => {
|
|
1768
|
+
if (riskType === "initial") {
|
|
1769
|
+
if (restEqualsInitial) {
|
|
1770
|
+
setConsequenceAndRemainingConsequence(consequenceLevel);
|
|
1771
|
+
} else {
|
|
1772
|
+
setConsequence(consequenceLevel);
|
|
1773
|
+
}
|
|
1774
|
+
} else {
|
|
1775
|
+
setRemainingConsequence(consequenceLevel);
|
|
1776
|
+
}
|
|
1777
|
+
};
|
|
1785
1778
|
return /* @__PURE__ */ React.createElement(Fragment, null, /* @__PURE__ */ React.createElement(Box, { className: box }, /* @__PURE__ */ React.createElement(Typography, { className: h2 }, t(`scenarioStepper.${resourceKey}.title`)), /* @__PURE__ */ React.createElement(Typography, { className: subtitle2 }, t(`scenarioStepper.${resourceKey}.subtitle`))), /* @__PURE__ */ React.createElement(Box, { className: box }, /* @__PURE__ */ React.createElement(Typography, { className: h3 }, t("dictionary.probability")), /* @__PURE__ */ React.createElement(Typography, { className: subtitle2 }, t(`scenarioStepper.${resourceKey}.probabilitySubtitle`))), /* @__PURE__ */ React.createElement(Box, { className: box }, /* @__PURE__ */ React.createElement(
|
|
1786
1779
|
ProbabilityTable,
|
|
1787
1780
|
{
|
|
1788
1781
|
selectedValue: getProbabilityLevel(risk),
|
|
1789
|
-
handleChange:
|
|
1782
|
+
handleChange: handleProbabilityChange
|
|
1790
1783
|
}
|
|
1791
1784
|
)), /* @__PURE__ */ React.createElement(Box, { className: box }, /* @__PURE__ */ React.createElement(Typography, { className: h3 }, t("dictionary.consequence")), /* @__PURE__ */ React.createElement(Typography, { className: subtitle2 }, t(`scenarioStepper.${resourceKey}.consequenceSubtitle`))), /* @__PURE__ */ React.createElement(Box, { className: box }, /* @__PURE__ */ React.createElement(
|
|
1792
1785
|
ConsequenceTable,
|
|
1793
1786
|
{
|
|
1794
1787
|
selectedValue: getConsequenceLevel(risk),
|
|
1795
|
-
handleChange:
|
|
1788
|
+
handleChange: handleConsequenceChange
|
|
1796
1789
|
}
|
|
1797
1790
|
)));
|
|
1798
1791
|
};
|
|
@@ -1889,8 +1882,9 @@ const ScenarioWizard = ({
|
|
|
1889
1882
|
saveScenario,
|
|
1890
1883
|
closeScenario,
|
|
1891
1884
|
editScenario,
|
|
1892
|
-
validateScenario
|
|
1893
|
-
|
|
1885
|
+
validateScenario,
|
|
1886
|
+
hasFormErrors
|
|
1887
|
+
} = useScenario();
|
|
1894
1888
|
const [showCloseConfirmation, setShowCloseConfirmation] = useState(false);
|
|
1895
1889
|
const [restEqualsInitial, setRestEqualsInitial] = useState(isNewScenario);
|
|
1896
1890
|
const [canCloseIfSuccessfull, setCanCloseIfSuccessfull] = useState(false);
|
|
@@ -1911,6 +1905,9 @@ const ScenarioWizard = ({
|
|
|
1911
1905
|
}
|
|
1912
1906
|
}, [canCloseIfSuccessfull, close, updateStatus]);
|
|
1913
1907
|
const saveAndClose = () => {
|
|
1908
|
+
if (hasFormErrors()) {
|
|
1909
|
+
return;
|
|
1910
|
+
}
|
|
1914
1911
|
saveScenario();
|
|
1915
1912
|
setCanCloseIfSuccessfull(true);
|
|
1916
1913
|
};
|
|
@@ -2023,396 +2020,555 @@ const ScenarioWizard = ({
|
|
|
2023
2020
|
));
|
|
2024
2021
|
};
|
|
2025
2022
|
|
|
2026
|
-
const
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2023
|
+
const section = {
|
|
2024
|
+
display: "flex",
|
|
2025
|
+
flexDirection: "column",
|
|
2026
|
+
gap: "16px",
|
|
2027
|
+
width: "100%",
|
|
2028
|
+
padding: 2
|
|
2029
|
+
};
|
|
2030
|
+
|
|
2031
|
+
const formLabel = (theme) => ({
|
|
2032
|
+
fontSize: theme.spacing(1.75),
|
|
2033
|
+
fontWeight: 700,
|
|
2034
|
+
textTransform: "uppercase",
|
|
2035
|
+
marginBottom: theme.spacing(1),
|
|
2036
|
+
color: theme.palette.mode === "dark" ? "#F8F8F8" : "rgba(0, 0, 0, 0.87)"
|
|
2037
|
+
});
|
|
2038
|
+
const heading1 = (theme) => ({
|
|
2039
|
+
fontSize: theme.spacing(4),
|
|
2040
|
+
fontWeight: 700
|
|
2041
|
+
});
|
|
2042
|
+
const heading3 = (theme) => ({
|
|
2043
|
+
fontSize: theme.spacing(2.5),
|
|
2044
|
+
fontWeight: 500
|
|
2045
|
+
});
|
|
2046
|
+
const body1 = (theme) => ({
|
|
2047
|
+
fontSize: theme.spacing(2),
|
|
2048
|
+
fontWeight: 500
|
|
2049
|
+
});
|
|
2050
|
+
const body2 = (theme) => ({
|
|
2051
|
+
fontSize: theme.spacing(2),
|
|
2052
|
+
fontWeight: 400,
|
|
2053
|
+
whiteSpace: "pre-line"
|
|
2054
|
+
});
|
|
2055
|
+
const label = (theme) => ({
|
|
2056
|
+
fontSize: theme.spacing(1.75),
|
|
2057
|
+
fontWeight: 700,
|
|
2058
|
+
textTransform: "uppercase",
|
|
2059
|
+
color: theme.palette.mode === "dark" ? "#F8F8F8" : "rgba(0, 0, 0, 0.87)",
|
|
2060
|
+
paddingBottom: "0.4rem"
|
|
2061
|
+
});
|
|
2062
|
+
const labelSubtitle = (theme) => ({
|
|
2063
|
+
fontSize: theme.spacing(1.75),
|
|
2064
|
+
fontWeight: 400,
|
|
2065
|
+
color: theme.palette.mode === "dark" ? "#F8F8F8" : "rgba(0, 0, 0, 0.87)",
|
|
2066
|
+
paddingBottom: "0.4rem",
|
|
2067
|
+
marginTop: "-0.2rem"
|
|
2068
|
+
});
|
|
2069
|
+
const label2 = (theme) => ({
|
|
2070
|
+
fontSize: theme.spacing(1.75),
|
|
2071
|
+
fontWeight: 700,
|
|
2072
|
+
textTransform: "uppercase",
|
|
2073
|
+
color: theme.palette.mode === "dark" ? "#F8F8F8" : "rgba(0, 0, 0, 0.87)"
|
|
2074
|
+
});
|
|
2070
2075
|
|
|
2071
|
-
const RiskBox = ({ risk, riskType
|
|
2072
|
-
const { risikoBadge, titleAndButton, section, editIcon } = useScenarioDrawerStyles();
|
|
2073
|
-
const { h3, body1, label, button } = useFontStyles();
|
|
2076
|
+
const RiskBox = ({ risk, riskType }) => {
|
|
2074
2077
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2075
|
-
return /* @__PURE__ */ React.createElement(Paper, {
|
|
2076
|
-
|
|
2077
|
-
{
|
|
2078
|
-
className: button,
|
|
2079
|
-
variant: "text",
|
|
2080
|
-
color: "primary",
|
|
2081
|
-
onClick: () => editScenario(riskType),
|
|
2082
|
-
startIcon: /* @__PURE__ */ React.createElement(EditIcon, { className: editIcon, "aria-label": "Edit" })
|
|
2083
|
-
}
|
|
2084
|
-
)), /* @__PURE__ */ React.createElement(Grid, { container: true }, /* @__PURE__ */ React.createElement(
|
|
2085
|
-
Grid,
|
|
2078
|
+
return /* @__PURE__ */ React.createElement(Paper$1, { sx: section }, /* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t(`dictionary.${riskType}`)), /* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(
|
|
2079
|
+
Box$2,
|
|
2086
2080
|
{
|
|
2087
|
-
|
|
2088
|
-
xs: 12,
|
|
2089
|
-
style: {
|
|
2081
|
+
sx: {
|
|
2090
2082
|
display: "flex",
|
|
2091
|
-
|
|
2092
|
-
gap:
|
|
2093
|
-
alignItems: "center"
|
|
2083
|
+
alignItems: "center",
|
|
2084
|
+
gap: 1
|
|
2094
2085
|
}
|
|
2095
2086
|
},
|
|
2096
2087
|
/* @__PURE__ */ React.createElement(
|
|
2097
2088
|
Box$2,
|
|
2098
2089
|
{
|
|
2099
|
-
|
|
2100
|
-
|
|
2090
|
+
sx: {
|
|
2091
|
+
width: "20px",
|
|
2092
|
+
height: "48px",
|
|
2093
|
+
borderRadius: 1,
|
|
2101
2094
|
backgroundColor: getRiskMatrixColor(risk)
|
|
2102
2095
|
}
|
|
2103
2096
|
}
|
|
2104
2097
|
),
|
|
2105
2098
|
/* @__PURE__ */ React.createElement(
|
|
2106
|
-
|
|
2099
|
+
Box$2,
|
|
2107
2100
|
{
|
|
2108
|
-
|
|
2109
|
-
xs: 12,
|
|
2110
|
-
style: {
|
|
2101
|
+
sx: {
|
|
2111
2102
|
display: "flex",
|
|
2112
2103
|
flexDirection: "column",
|
|
2113
|
-
alignItems: "start"
|
|
2104
|
+
alignItems: "start",
|
|
2105
|
+
gap: 0.5
|
|
2114
2106
|
}
|
|
2115
2107
|
},
|
|
2116
|
-
/* @__PURE__ */ React.createElement(Typography, {
|
|
2117
|
-
/* @__PURE__ */ React.createElement(Typography, {
|
|
2108
|
+
/* @__PURE__ */ React.createElement(Typography$1, { sx: label2 }, t("dictionary.probability"), ": ", getProbabilityLevel(risk)),
|
|
2109
|
+
/* @__PURE__ */ React.createElement(Typography$1, { sx: label2 }, t("dictionary.consequence"), ": ", getConsequenceLevel(risk))
|
|
2118
2110
|
)
|
|
2119
|
-
), /* @__PURE__ */ React.createElement(
|
|
2111
|
+
)), /* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(Typography$1, { sx: label }, t("dictionary.estimatedRisk")), /* @__PURE__ */ React.createElement(Typography$1, { sx: body1 }, formatNOK(risk.consequence * risk.probability), " ", t("riskMatrix.estimatedRisk.unit.nokPerYear"))));
|
|
2120
2112
|
};
|
|
2121
2113
|
const RiskSection = () => {
|
|
2122
|
-
const { scenario
|
|
2123
|
-
return /* @__PURE__ */ React.createElement(React.
|
|
2114
|
+
const { scenario } = useScenario();
|
|
2115
|
+
return /* @__PURE__ */ React.createElement(Box$2, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ React.createElement(RiskBox, { risk: scenario.risk, riskType: "initialRisk" }), /* @__PURE__ */ React.createElement(KeyboardDoubleArrowRightIcon, { sx: { fontSize: "48px" } }), /* @__PURE__ */ React.createElement(RiskBox, { risk: scenario.remainingRisk, riskType: "restRisk" }));
|
|
2116
|
+
};
|
|
2117
|
+
|
|
2118
|
+
const ActionBox = ({ action, index, saveScenario }) => {
|
|
2119
|
+
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2120
|
+
const [previousAction, setPreviousAction] = useState(action);
|
|
2121
|
+
useEffect(() => {
|
|
2122
|
+
if (previousAction !== action) {
|
|
2123
|
+
saveScenario();
|
|
2124
|
+
setPreviousAction(action);
|
|
2125
|
+
}
|
|
2126
|
+
}, [action, saveScenario, previousAction]);
|
|
2127
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(Typography$1, { sx: label }, t("dictionary.measure"), " ", index), /* @__PURE__ */ React.createElement(Typography$1, { sx: body2 }, action.description)), /* @__PURE__ */ React.createElement(
|
|
2124
2128
|
Box$2,
|
|
2125
2129
|
{
|
|
2126
|
-
|
|
2130
|
+
sx: {
|
|
2127
2131
|
display: "flex",
|
|
2128
|
-
|
|
2129
|
-
alignItems: "
|
|
2132
|
+
justifyContent: "space-between",
|
|
2133
|
+
alignItems: "end"
|
|
2130
2134
|
}
|
|
2131
2135
|
},
|
|
2132
|
-
/* @__PURE__ */ React.createElement(
|
|
2133
|
-
|
|
2134
|
-
{
|
|
2135
|
-
risk: scenario.risk,
|
|
2136
|
-
riskType: "initialRisk",
|
|
2137
|
-
editScenario
|
|
2138
|
-
}
|
|
2139
|
-
),
|
|
2140
|
-
/* @__PURE__ */ React.createElement(
|
|
2141
|
-
Grid,
|
|
2136
|
+
/* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(Typography$1, { sx: label }, t("dictionary.url")), action.url ? /* @__PURE__ */ React.createElement(
|
|
2137
|
+
Link,
|
|
2142
2138
|
{
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
justifyContent: "center",
|
|
2148
|
-
alignItems: "center"
|
|
2149
|
-
}
|
|
2139
|
+
sx: body2,
|
|
2140
|
+
target: "_blank",
|
|
2141
|
+
rel: "noreferrer",
|
|
2142
|
+
href: action.url.startsWith("http") ? action.url : `//${action.url}`
|
|
2150
2143
|
},
|
|
2151
|
-
|
|
2152
|
-
),
|
|
2144
|
+
action.url
|
|
2145
|
+
) : /* @__PURE__ */ React.createElement(Typography$1, { sx: body2 }, t("dictionary.emptyUrl"))),
|
|
2153
2146
|
/* @__PURE__ */ React.createElement(
|
|
2154
|
-
|
|
2147
|
+
Chip$1,
|
|
2155
2148
|
{
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2149
|
+
label: action.status,
|
|
2150
|
+
sx: {
|
|
2151
|
+
margin: 0,
|
|
2152
|
+
backgroundColor: action.status === "Completed" ? { backgroundColor: "#6BC6A4" } : void 0
|
|
2153
|
+
}
|
|
2159
2154
|
}
|
|
2160
2155
|
)
|
|
2161
2156
|
));
|
|
2162
2157
|
};
|
|
2163
2158
|
|
|
2164
|
-
const
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
}
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
},
|
|
2187
|
-
|
|
2188
|
-
marginTop: theme.spacing(-2)
|
|
2189
|
-
},
|
|
2190
|
-
chipDropdown: {
|
|
2191
|
-
display: "flex",
|
|
2192
|
-
flexDirection: "row",
|
|
2193
|
-
justifyContent: "flex-end"
|
|
2194
|
-
}
|
|
2195
|
-
}));
|
|
2159
|
+
const ActionsSection = () => {
|
|
2160
|
+
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2161
|
+
const { scenario, saveScenario } = useScenario();
|
|
2162
|
+
return /* @__PURE__ */ React.createElement(Paper$1, { sx: section }, /* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t("scenarioDrawer.measureTab.title")), scenario.existingActions && /* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(Typography$1, { sx: label }, t("scenarioDrawer.measureTab.existingMeasure")), /* @__PURE__ */ React.createElement(Typography$1, { sx: body2 }, scenario.existingActions)), scenario.actions.map((action, index) => /* @__PURE__ */ React.createElement(Fragment, { key: action.ID }, /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(
|
|
2163
|
+
ActionBox,
|
|
2164
|
+
{
|
|
2165
|
+
action,
|
|
2166
|
+
index: index + 1,
|
|
2167
|
+
saveScenario
|
|
2168
|
+
}
|
|
2169
|
+
))));
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
const DeleteConfirmation = () => {
|
|
2173
|
+
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2174
|
+
const { deleteConfirmationIsOpen, abortDeletion, confirmDeletion } = useScenario();
|
|
2175
|
+
return /* @__PURE__ */ React.createElement(Dialog$1, { open: deleteConfirmationIsOpen }, /* @__PURE__ */ React.createElement(DialogTitle$1, null, t("scenarioDrawer.deleteScenarioConfirmation")), /* @__PURE__ */ React.createElement(DialogActions$1, { sx: { gap: 1, paddingX: 3, paddingY: 2 } }, /* @__PURE__ */ React.createElement(Button$1, { onClick: abortDeletion }, t("dictionary.cancel")), /* @__PURE__ */ React.createElement(Button$1, { onClick: confirmDeletion, variant: "contained", color: "error" }, t("scenarioDrawer.deleteScenarioButton"))));
|
|
2176
|
+
};
|
|
2177
|
+
|
|
2178
|
+
const ScopeSection = () => {
|
|
2179
|
+
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2180
|
+
const { scenario } = useScenario();
|
|
2181
|
+
return /* @__PURE__ */ React.createElement(Paper$1, { sx: section }, /* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t("scenarioDrawer.title")), /* @__PURE__ */ React.createElement(Typography$1, { sx: heading1 }, scenario.title), /* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(Typography$1, { sx: label }, t("dictionary.description")), /* @__PURE__ */ React.createElement(Typography$1, { sx: body2 }, scenario.description)), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(Box$2, { sx: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 2 } }, /* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(Typography$1, { sx: label }, t("dictionary.threatActors")), scenario.threatActors.map((threatActor) => /* @__PURE__ */ React.createElement(Typography$1, { key: threatActor, sx: body2 }, threatActor))), /* @__PURE__ */ React.createElement(Box$2, null, /* @__PURE__ */ React.createElement(Typography$1, { sx: label }, t("dictionary.vulnerabilities")), scenario.vulnerabilities.map((vulnerability) => /* @__PURE__ */ React.createElement(Typography$1, { key: vulnerability, sx: body2 }, vulnerability)))));
|
|
2182
|
+
};
|
|
2196
2183
|
|
|
2197
|
-
const
|
|
2184
|
+
const Select = ({
|
|
2185
|
+
label,
|
|
2186
|
+
sublabel,
|
|
2187
|
+
error,
|
|
2188
|
+
helperText,
|
|
2189
|
+
required,
|
|
2190
|
+
control,
|
|
2191
|
+
name,
|
|
2192
|
+
multiple,
|
|
2193
|
+
labelTranslationKey,
|
|
2198
2194
|
options,
|
|
2199
|
-
|
|
2200
|
-
handleChange
|
|
2195
|
+
...props
|
|
2201
2196
|
}) => {
|
|
2202
|
-
const
|
|
2203
|
-
const
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
};
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
setAnchorEl(e.currentTarget);
|
|
2220
|
-
setMenuAnchorEl(e.currentTarget);
|
|
2197
|
+
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2198
|
+
const { field } = useController({
|
|
2199
|
+
name,
|
|
2200
|
+
control,
|
|
2201
|
+
rules: { required }
|
|
2202
|
+
});
|
|
2203
|
+
const renderValue = (values) => {
|
|
2204
|
+
var _a;
|
|
2205
|
+
return multiple ? /* @__PURE__ */ React.createElement(
|
|
2206
|
+
Box$2,
|
|
2207
|
+
{
|
|
2208
|
+
sx: {
|
|
2209
|
+
display: "flex",
|
|
2210
|
+
flexWrap: "wrap",
|
|
2211
|
+
marginBottom: 0,
|
|
2212
|
+
paddingBottom: 0
|
|
2213
|
+
}
|
|
2221
2214
|
},
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2215
|
+
values.map((value) => /* @__PURE__ */ React.createElement(
|
|
2216
|
+
Chip$1,
|
|
2217
|
+
{
|
|
2218
|
+
key: value,
|
|
2219
|
+
label: (
|
|
2220
|
+
/* @ts-ignore Because ts can't typecheck strings against our keys */
|
|
2221
|
+
labelTranslationKey ? t(`${labelTranslationKey}.${value}`) : value
|
|
2222
|
+
)
|
|
2223
|
+
}
|
|
2224
|
+
))
|
|
2225
|
+
) : (_a = options.find((option) => option.value === values)) == null ? void 0 : _a.renderedValue;
|
|
2226
|
+
};
|
|
2227
|
+
const handleChecked = (fieldValue, optionValue) => {
|
|
2228
|
+
if (Array.isArray(fieldValue))
|
|
2229
|
+
return fieldValue.includes(optionValue);
|
|
2230
|
+
return fieldValue === optionValue;
|
|
2231
|
+
};
|
|
2232
|
+
return /* @__PURE__ */ React.createElement(FormControl$2, { sx: { width: "100%" } }, label && /* @__PURE__ */ React.createElement(FormLabel$2, { sx: formLabel, required }, label), sublabel && /* @__PURE__ */ React.createElement(FormHelperText$1, { sx: labelSubtitle }, sublabel), /* @__PURE__ */ React.createElement(
|
|
2233
|
+
MUISelect,
|
|
2226
2234
|
{
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
onClose: () => setAnchorEl(null),
|
|
2230
|
-
getContentAnchorEl: null,
|
|
2231
|
-
anchorOrigin: {
|
|
2232
|
-
vertical: "bottom",
|
|
2233
|
-
horizontal: "center"
|
|
2235
|
+
MenuProps: {
|
|
2236
|
+
disablePortal: true
|
|
2234
2237
|
},
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2238
|
+
variant: "outlined",
|
|
2239
|
+
renderValue,
|
|
2240
|
+
multiple,
|
|
2241
|
+
SelectDisplayProps: multiple ? {
|
|
2242
|
+
style: {
|
|
2243
|
+
paddingBottom: 8,
|
|
2244
|
+
paddingTop: 16,
|
|
2245
|
+
minHeight: 40
|
|
2246
|
+
}
|
|
2247
|
+
} : {},
|
|
2248
|
+
inputRef: field.ref,
|
|
2249
|
+
...field,
|
|
2250
|
+
...props
|
|
2239
2251
|
},
|
|
2240
|
-
options.map((
|
|
2241
|
-
));
|
|
2252
|
+
options.map((option) => /* @__PURE__ */ React.createElement(MenuItem$1, { key: option.value, value: option.value }, multiple && /* @__PURE__ */ React.createElement(Checkbox$1, { checked: handleChecked(field.value, option.value) }), /* @__PURE__ */ React.createElement(ListItemText$1, { primary: option.renderedValue })))
|
|
2253
|
+
), error && /* @__PURE__ */ React.createElement(FormHelperText$1, { error: true }, helperText));
|
|
2242
2254
|
};
|
|
2243
2255
|
|
|
2244
|
-
const
|
|
2245
|
-
|
|
2246
|
-
index,
|
|
2247
|
-
updateAction,
|
|
2248
|
-
saveScenario
|
|
2256
|
+
const ScenarioForm = ({
|
|
2257
|
+
formMethods
|
|
2249
2258
|
}) => {
|
|
2250
2259
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2251
|
-
const {
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
saveScenario();
|
|
2265
|
-
setPreviousAction(action);
|
|
2266
|
-
}
|
|
2267
|
-
}, [action, saveScenario, previousAction]);
|
|
2268
|
-
const setStatus = (status) => {
|
|
2269
|
-
updateAction({
|
|
2270
|
-
...action,
|
|
2271
|
-
status
|
|
2272
|
-
});
|
|
2273
|
-
};
|
|
2274
|
-
return /* @__PURE__ */ React.createElement(Grid, { container: true, className: gridContainer }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, className: alignCenter }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 6, className: paddingTop }, /* @__PURE__ */ React.createElement(Typography, { className: label }, t("dictionary.measure"), " ", index))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, className: actionDescription }, /* @__PURE__ */ React.createElement(Typography, { className: body2 }, action.description)), /* @__PURE__ */ React.createElement(Grid, { container: true, xs: 12, className: row }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 4 }, /* @__PURE__ */ React.createElement(Typography, { className: label }, t("dictionary.measureOwner")), /* @__PURE__ */ React.createElement(Typography, { className: body2 }, action.owner)), /* @__PURE__ */ React.createElement(Grid, { container: true, xs: 4, className: column }, /* @__PURE__ */ React.createElement(Typography, { className: label }, t("dictionary.deadline")), /* @__PURE__ */ React.createElement(Typography, { className: body2 }, formatDate(action.deadline))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 3, className: chipDropdown }, /* @__PURE__ */ React.createElement(
|
|
2275
|
-
ChipDropdown,
|
|
2260
|
+
const { control } = formMethods;
|
|
2261
|
+
const probabilityValues = probabilityOptions.map((value, index) => ({
|
|
2262
|
+
value,
|
|
2263
|
+
/* @ts-ignore Because ts can't typecheck strings against our keys */
|
|
2264
|
+
renderedValue: `${index + 1}: ${t(`probabilityTable.rows.${index + 1}`)}`
|
|
2265
|
+
}));
|
|
2266
|
+
const consequenceValues = consequenceOptions.map((value, index) => ({
|
|
2267
|
+
value,
|
|
2268
|
+
/* @ts-ignore Because ts can't typecheck strings against our keys */
|
|
2269
|
+
renderedValue: `${index + 1}: ${t(`consequenceTable.rows.${index + 1}`)}`
|
|
2270
|
+
}));
|
|
2271
|
+
return /* @__PURE__ */ React.createElement(
|
|
2272
|
+
Box$2,
|
|
2276
2273
|
{
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2274
|
+
sx: {
|
|
2275
|
+
display: "flex",
|
|
2276
|
+
gap: "24px"
|
|
2277
|
+
}
|
|
2278
|
+
},
|
|
2279
|
+
/* @__PURE__ */ React.createElement(Paper$1, { sx: section }, /* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t("dictionary.initialRisk")), /* @__PURE__ */ React.createElement(
|
|
2280
|
+
Select,
|
|
2281
|
+
{
|
|
2282
|
+
control,
|
|
2283
|
+
name: "risk.probability",
|
|
2284
|
+
label: t("dictionary.probability"),
|
|
2285
|
+
options: probabilityValues
|
|
2286
|
+
}
|
|
2287
|
+
), /* @__PURE__ */ React.createElement(
|
|
2288
|
+
Select,
|
|
2289
|
+
{
|
|
2290
|
+
control,
|
|
2291
|
+
name: "risk.consequence",
|
|
2292
|
+
label: t("dictionary.consequence"),
|
|
2293
|
+
options: consequenceValues
|
|
2294
|
+
}
|
|
2295
|
+
)),
|
|
2296
|
+
/* @__PURE__ */ React.createElement(Paper$1, { sx: section }, /* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t("dictionary.restRisk")), /* @__PURE__ */ React.createElement(
|
|
2297
|
+
Select,
|
|
2298
|
+
{
|
|
2299
|
+
control,
|
|
2300
|
+
name: "remainingRisk.probability",
|
|
2301
|
+
label: t("dictionary.probability"),
|
|
2302
|
+
options: probabilityValues
|
|
2303
|
+
}
|
|
2304
|
+
), /* @__PURE__ */ React.createElement(
|
|
2305
|
+
Select,
|
|
2306
|
+
{
|
|
2307
|
+
control,
|
|
2308
|
+
name: "remainingRisk.consequence",
|
|
2309
|
+
label: t("dictionary.consequence"),
|
|
2310
|
+
options: consequenceValues
|
|
2311
|
+
}
|
|
2312
|
+
))
|
|
2313
|
+
);
|
|
2282
2314
|
};
|
|
2283
2315
|
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2286
|
-
})
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2316
|
+
const Input = forwardRef(
|
|
2317
|
+
({ label, sublabel, error, helperText, required, ...props }, ref) => {
|
|
2318
|
+
return /* @__PURE__ */ React.createElement(FormControl$2, { sx: { width: "100%" }, error, required }, label && /* @__PURE__ */ React.createElement(FormLabel$2, { required, sx: formLabel }, label), sublabel && /* @__PURE__ */ React.createElement(FormHelperText$1, { sx: labelSubtitle }, sublabel), /* @__PURE__ */ React.createElement(
|
|
2319
|
+
TextField$2,
|
|
2320
|
+
{
|
|
2321
|
+
id: "filled-multiline-static",
|
|
2322
|
+
error,
|
|
2323
|
+
multiline: true,
|
|
2324
|
+
fullWidth: true,
|
|
2325
|
+
variant: "outlined",
|
|
2326
|
+
inputRef: ref,
|
|
2327
|
+
InputProps: {
|
|
2328
|
+
sx: (theme) => ({
|
|
2329
|
+
"&.Mui-disabled": {
|
|
2330
|
+
color: theme.palette.mode === "dark" ? "#FFFFFF80" : "#757575"
|
|
2331
|
+
}
|
|
2332
|
+
})
|
|
2333
|
+
},
|
|
2334
|
+
...props
|
|
2335
|
+
}
|
|
2336
|
+
), helperText && /* @__PURE__ */ React.createElement(FormHelperText$1, null, helperText));
|
|
2337
|
+
}
|
|
2338
|
+
);
|
|
2292
2339
|
|
|
2293
|
-
const
|
|
2340
|
+
const ActionFormSection = ({
|
|
2341
|
+
formMethods
|
|
2342
|
+
}) => {
|
|
2294
2343
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2295
|
-
const {
|
|
2296
|
-
const {
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2344
|
+
const { control, register } = formMethods;
|
|
2345
|
+
const { fields, append, remove } = useFieldArray({
|
|
2346
|
+
control,
|
|
2347
|
+
name: "actions"
|
|
2348
|
+
});
|
|
2349
|
+
return /* @__PURE__ */ React.createElement(Paper$1, { sx: section }, /* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t("dictionary.measure")), /* @__PURE__ */ React.createElement(
|
|
2350
|
+
Input,
|
|
2300
2351
|
{
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2352
|
+
...register("existingActions"),
|
|
2353
|
+
label: t("scenarioDrawer.measureTab.existingMeasure"),
|
|
2354
|
+
minRows: 3
|
|
2355
|
+
}
|
|
2356
|
+
), fields.map((field, index) => /* @__PURE__ */ React.createElement(Fragment, { key: field.ID }, /* @__PURE__ */ React.createElement(Divider, { variant: "fullWidth" }), /* @__PURE__ */ React.createElement(
|
|
2357
|
+
Box$2,
|
|
2358
|
+
{
|
|
2359
|
+
sx: {
|
|
2360
|
+
display: "grid",
|
|
2361
|
+
gap: "24px",
|
|
2362
|
+
padding: 0
|
|
2306
2363
|
}
|
|
2307
2364
|
},
|
|
2308
|
-
/* @__PURE__ */ React.createElement(Typography, { className: h3 }, t("scenarioDrawer.measureTab.actionsTitle")),
|
|
2309
2365
|
/* @__PURE__ */ React.createElement(
|
|
2310
|
-
|
|
2366
|
+
Box$2,
|
|
2311
2367
|
{
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2368
|
+
sx: {
|
|
2369
|
+
display: "flex",
|
|
2370
|
+
justifyContent: "space-between",
|
|
2371
|
+
alignItems: "center"
|
|
2372
|
+
}
|
|
2373
|
+
},
|
|
2374
|
+
/* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t("scenarioDrawer.measureTab.title"), " ", index),
|
|
2375
|
+
/* @__PURE__ */ React.createElement(IconButton, { onClick: () => remove(index), color: "primary" }, /* @__PURE__ */ React.createElement(DeleteIcon$1, { "aria-label": "Edit" }))
|
|
2376
|
+
),
|
|
2377
|
+
/* @__PURE__ */ React.createElement(
|
|
2378
|
+
Input,
|
|
2379
|
+
{
|
|
2380
|
+
required: true,
|
|
2381
|
+
...register(`actions.${index}.description`, { required: true }),
|
|
2382
|
+
label: t("dictionary.description")
|
|
2317
2383
|
}
|
|
2384
|
+
),
|
|
2385
|
+
/* @__PURE__ */ React.createElement(
|
|
2386
|
+
Box$2,
|
|
2387
|
+
{
|
|
2388
|
+
sx: {
|
|
2389
|
+
display: "grid",
|
|
2390
|
+
gridTemplateColumns: "2fr 1fr",
|
|
2391
|
+
gap: "24px"
|
|
2392
|
+
}
|
|
2393
|
+
},
|
|
2394
|
+
/* @__PURE__ */ React.createElement(
|
|
2395
|
+
Input,
|
|
2396
|
+
{
|
|
2397
|
+
required: true,
|
|
2398
|
+
...register(`actions.${index}.url`, { required: true }),
|
|
2399
|
+
label: t("dictionary.url")
|
|
2400
|
+
}
|
|
2401
|
+
),
|
|
2402
|
+
/* @__PURE__ */ React.createElement(
|
|
2403
|
+
Select,
|
|
2404
|
+
{
|
|
2405
|
+
required: true,
|
|
2406
|
+
control,
|
|
2407
|
+
name: `actions.${index}.status`,
|
|
2408
|
+
label: t("dictionary.status"),
|
|
2409
|
+
options: actionStatusOptions.map((value) => ({
|
|
2410
|
+
value,
|
|
2411
|
+
renderedValue: value
|
|
2412
|
+
}))
|
|
2413
|
+
}
|
|
2414
|
+
)
|
|
2318
2415
|
)
|
|
2319
|
-
)
|
|
2320
|
-
|
|
2416
|
+
))), /* @__PURE__ */ React.createElement(
|
|
2417
|
+
Button$1,
|
|
2321
2418
|
{
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
)
|
|
2328
|
-
};
|
|
2329
|
-
|
|
2330
|
-
const DeleteConfirmation = () => {
|
|
2331
|
-
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2332
|
-
const { deleteConfirmationIsOpen, abortDeletion, confirmDeletion } = useContext(ScenarioContext);
|
|
2333
|
-
return /* @__PURE__ */ React.createElement(Dialog, { open: deleteConfirmationIsOpen }, /* @__PURE__ */ React.createElement(DialogTitle, null, t("scenarioDrawer.deleteScenarioConfirmation")), /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(Button, { style: { textTransform: "none" }, onClick: abortDeletion }, t("dictionary.cancel")), /* @__PURE__ */ React.createElement(Button, { style: { textTransform: "none" }, onClick: confirmDeletion }, t("scenarioDrawer.deleteScenarioButton"))));
|
|
2419
|
+
startIcon: /* @__PURE__ */ React.createElement(AddCircle$1, null),
|
|
2420
|
+
color: "primary",
|
|
2421
|
+
onClick: () => append(emptyAction())
|
|
2422
|
+
},
|
|
2423
|
+
t("scenarioDrawer.measureTab.addMeasureButton")
|
|
2424
|
+
));
|
|
2334
2425
|
};
|
|
2335
2426
|
|
|
2336
|
-
const
|
|
2427
|
+
const ScenarioFormSection = ({
|
|
2428
|
+
formMethods
|
|
2429
|
+
}) => {
|
|
2337
2430
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2338
|
-
const {
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2431
|
+
const {
|
|
2432
|
+
control,
|
|
2433
|
+
register,
|
|
2434
|
+
formState: { errors }
|
|
2435
|
+
} = formMethods;
|
|
2436
|
+
const translatedThreatActors = threatActorsOptions.map((threatActor) => ({
|
|
2437
|
+
value: threatActor,
|
|
2438
|
+
/* @ts-ignore Because ts can't typecheck strings against our keys */
|
|
2439
|
+
renderedValue: t(`threatActors.${threatActor}`)
|
|
2440
|
+
}));
|
|
2441
|
+
const translatedVulnerabilities = vulnerabilitiesOptions.map(
|
|
2442
|
+
(vulnerability) => ({
|
|
2443
|
+
value: vulnerability,
|
|
2444
|
+
/* @ts-ignore Because ts can't typecheck strings against our keys */
|
|
2445
|
+
renderedValue: t(`vulnerabilities.${vulnerability}`)
|
|
2446
|
+
})
|
|
2447
|
+
);
|
|
2448
|
+
return /* @__PURE__ */ React.createElement(Paper$1, { sx: section }, /* @__PURE__ */ React.createElement(Typography$1, { sx: heading3 }, t("scenarioDrawer.title")), /* @__PURE__ */ React.createElement(
|
|
2449
|
+
Input,
|
|
2343
2450
|
{
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2451
|
+
required: true,
|
|
2452
|
+
...register("title", { required: true }),
|
|
2453
|
+
error: errors.title !== void 0,
|
|
2454
|
+
label: t("dictionary.title")
|
|
2455
|
+
}
|
|
2456
|
+
), /* @__PURE__ */ React.createElement(
|
|
2457
|
+
Select,
|
|
2458
|
+
{
|
|
2459
|
+
multiple: true,
|
|
2460
|
+
control,
|
|
2461
|
+
name: "threatActors",
|
|
2462
|
+
label: t("dictionary.threatActors"),
|
|
2463
|
+
labelTranslationKey: "threatActors",
|
|
2464
|
+
options: translatedThreatActors
|
|
2465
|
+
}
|
|
2466
|
+
), /* @__PURE__ */ React.createElement(
|
|
2467
|
+
Select,
|
|
2468
|
+
{
|
|
2469
|
+
multiple: true,
|
|
2470
|
+
control,
|
|
2471
|
+
name: "vulnerabilities",
|
|
2472
|
+
label: t("dictionary.vulnerabilities"),
|
|
2473
|
+
labelTranslationKey: "vulnerabilities",
|
|
2474
|
+
options: translatedVulnerabilities
|
|
2475
|
+
}
|
|
2476
|
+
), /* @__PURE__ */ React.createElement(
|
|
2477
|
+
Input,
|
|
2478
|
+
{
|
|
2479
|
+
...register("description"),
|
|
2480
|
+
label: t("dictionary.description"),
|
|
2481
|
+
minRows: 4
|
|
2349
2482
|
}
|
|
2350
|
-
))
|
|
2483
|
+
));
|
|
2351
2484
|
};
|
|
2352
2485
|
|
|
2353
2486
|
const ScenarioDrawer = () => {
|
|
2354
2487
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2355
|
-
const
|
|
2356
|
-
const {
|
|
2357
|
-
|
|
2358
|
-
|
|
2488
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
2489
|
+
const {
|
|
2490
|
+
scenario,
|
|
2491
|
+
isDrawerOpen,
|
|
2492
|
+
openDeleteConfirmation,
|
|
2493
|
+
closeScenario,
|
|
2494
|
+
submitEditedScenarioToRiSc
|
|
2495
|
+
} = useScenario();
|
|
2496
|
+
const formMethods = useForm({ defaultValues: scenario });
|
|
2497
|
+
const onCancel = () => {
|
|
2498
|
+
formMethods.reset(scenario);
|
|
2499
|
+
setIsEditing(false);
|
|
2500
|
+
};
|
|
2501
|
+
const onClose = () => {
|
|
2502
|
+
closeScenario();
|
|
2503
|
+
setIsEditing(false);
|
|
2504
|
+
};
|
|
2505
|
+
const onSubmit = formMethods.handleSubmit((data) => {
|
|
2506
|
+
submitEditedScenarioToRiSc(data);
|
|
2507
|
+
setIsEditing(false);
|
|
2508
|
+
});
|
|
2509
|
+
useEffect(() => {
|
|
2510
|
+
formMethods.reset(scenario);
|
|
2511
|
+
}, [scenario, formMethods]);
|
|
2359
2512
|
return /* @__PURE__ */ React.createElement(
|
|
2360
2513
|
Drawer,
|
|
2361
2514
|
{
|
|
2362
|
-
|
|
2515
|
+
PaperProps: {
|
|
2516
|
+
sx: (theme) => ({
|
|
2517
|
+
padding: theme.spacing(4),
|
|
2518
|
+
width: "50%",
|
|
2519
|
+
gap: theme.spacing(3),
|
|
2520
|
+
[theme.breakpoints.down("sm")]: {
|
|
2521
|
+
width: "90%",
|
|
2522
|
+
padding: theme.spacing(2)
|
|
2523
|
+
},
|
|
2524
|
+
backgroundColor: theme.palette.mode === "dark" ? "#333333" : "#f8f8f8"
|
|
2525
|
+
})
|
|
2526
|
+
},
|
|
2363
2527
|
variant: "temporary",
|
|
2364
2528
|
anchor: "right",
|
|
2365
|
-
open:
|
|
2366
|
-
onClose
|
|
2529
|
+
open: isDrawerOpen,
|
|
2530
|
+
onClose
|
|
2367
2531
|
},
|
|
2368
2532
|
/* @__PURE__ */ React.createElement(
|
|
2369
2533
|
Box$2,
|
|
2370
2534
|
{
|
|
2371
|
-
|
|
2372
|
-
style: {
|
|
2373
|
-
marginBottom: "8px",
|
|
2374
|
-
marginTop: "8px",
|
|
2535
|
+
sx: {
|
|
2375
2536
|
display: "flex",
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
justifyContent: "flex-end"
|
|
2537
|
+
gap: "16px",
|
|
2538
|
+
marginLeft: "auto"
|
|
2379
2539
|
}
|
|
2380
2540
|
},
|
|
2381
2541
|
/* @__PURE__ */ React.createElement(
|
|
2382
|
-
Button,
|
|
2542
|
+
Button$1,
|
|
2543
|
+
{
|
|
2544
|
+
color: "primary",
|
|
2545
|
+
variant: "contained",
|
|
2546
|
+
onClick: isEditing ? onSubmit : () => setIsEditing(true),
|
|
2547
|
+
disabled: isEditing && !formMethods.formState.isDirty
|
|
2548
|
+
},
|
|
2549
|
+
t(isEditing ? "dictionary.save" : "dictionary.edit")
|
|
2550
|
+
),
|
|
2551
|
+
/* @__PURE__ */ React.createElement(
|
|
2552
|
+
Button$1,
|
|
2383
2553
|
{
|
|
2384
|
-
className: button,
|
|
2385
2554
|
variant: "outlined",
|
|
2386
2555
|
color: "primary",
|
|
2387
|
-
onClick:
|
|
2556
|
+
onClick: isEditing ? onCancel : onClose
|
|
2388
2557
|
},
|
|
2389
|
-
t("dictionary.close")
|
|
2558
|
+
t(isEditing ? "dictionary.cancel" : "dictionary.close")
|
|
2390
2559
|
)
|
|
2391
2560
|
),
|
|
2392
|
-
/* @__PURE__ */ React.createElement(ScopeSection, null),
|
|
2393
|
-
/* @__PURE__ */ React.createElement(RiskSection, null),
|
|
2394
|
-
/* @__PURE__ */ React.createElement(ActionsSection, null),
|
|
2561
|
+
isEditing ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ScenarioFormSection, { formMethods }), /* @__PURE__ */ React.createElement(ScenarioForm, { formMethods }), /* @__PURE__ */ React.createElement(ActionFormSection, { formMethods })) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ScopeSection, null), /* @__PURE__ */ React.createElement(RiskSection, null), /* @__PURE__ */ React.createElement(ActionsSection, null)),
|
|
2395
2562
|
/* @__PURE__ */ React.createElement(
|
|
2396
|
-
|
|
2563
|
+
Button$1,
|
|
2397
2564
|
{
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
justifyContent: "flex-start"
|
|
2404
|
-
}
|
|
2565
|
+
startIcon: /* @__PURE__ */ React.createElement(DeleteIcon$1, null),
|
|
2566
|
+
variant: "text",
|
|
2567
|
+
color: "primary",
|
|
2568
|
+
onClick: openDeleteConfirmation,
|
|
2569
|
+
sx: { marginRight: "auto" }
|
|
2405
2570
|
},
|
|
2406
|
-
|
|
2407
|
-
Button,
|
|
2408
|
-
{
|
|
2409
|
-
startIcon: /* @__PURE__ */ React.createElement(DeleteIcon$1, null),
|
|
2410
|
-
variant: "text",
|
|
2411
|
-
color: "primary",
|
|
2412
|
-
onClick: openDeleteConfirmation
|
|
2413
|
-
},
|
|
2414
|
-
t("scenarioDrawer.deleteScenarioButton")
|
|
2415
|
-
)
|
|
2571
|
+
t("scenarioDrawer.deleteScenarioButton")
|
|
2416
2572
|
),
|
|
2417
2573
|
/* @__PURE__ */ React.createElement(DeleteConfirmation, null)
|
|
2418
2574
|
);
|
|
@@ -2504,7 +2660,7 @@ const RiskMatrixScenarioCount = ({
|
|
|
2504
2660
|
tooltipText
|
|
2505
2661
|
} = useRiskMatrixStyles();
|
|
2506
2662
|
const [tooltipOpen, setTooltipOpen] = useState(false);
|
|
2507
|
-
const { openScenario } =
|
|
2663
|
+
const { openScenario } = useScenario();
|
|
2508
2664
|
const handleScenarioClick = (ID) => {
|
|
2509
2665
|
setTooltipOpen(false);
|
|
2510
2666
|
openScenario(ID);
|
|
@@ -2519,16 +2675,27 @@ const RiskMatrixScenarioCount = ({
|
|
|
2519
2675
|
if (scenarios.length === 0) {
|
|
2520
2676
|
return null;
|
|
2521
2677
|
}
|
|
2522
|
-
const tooltipList = /* @__PURE__ */ React.createElement(List, { dense: true }, /* @__PURE__ */ React.createElement(ListSubheader, { className: tooltipText }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: tooltipText }, t("riskMatrix.tooltip.title"))), scenarios.map((s) => /* @__PURE__ */ React.createElement(
|
|
2523
|
-
|
|
2524
|
-
} }, /* @__PURE__ */ React.createElement(CircleIcon, { className: tooltipText, style: { width: "10px" } }), /* @__PURE__ */ React.createElement(
|
|
2525
|
-
ListItemText$1,
|
|
2678
|
+
const tooltipList = /* @__PURE__ */ React.createElement(List, { dense: true }, /* @__PURE__ */ React.createElement(ListSubheader, { className: tooltipText }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: tooltipText }, t("riskMatrix.tooltip.title"))), scenarios.map((s) => /* @__PURE__ */ React.createElement(
|
|
2679
|
+
ListItem,
|
|
2526
2680
|
{
|
|
2681
|
+
key: s.ID,
|
|
2682
|
+
button: true,
|
|
2683
|
+
disableGutters: true,
|
|
2527
2684
|
className: tooltipText,
|
|
2528
|
-
|
|
2685
|
+
onClick: () => {
|
|
2686
|
+
handleScenarioClick(s.ID);
|
|
2687
|
+
}
|
|
2529
2688
|
},
|
|
2530
|
-
/* @__PURE__ */ React.createElement(
|
|
2531
|
-
|
|
2689
|
+
/* @__PURE__ */ React.createElement(CircleIcon, { className: tooltipText, style: { width: "10px" } }),
|
|
2690
|
+
/* @__PURE__ */ React.createElement(
|
|
2691
|
+
ListItemText$2,
|
|
2692
|
+
{
|
|
2693
|
+
className: tooltipText,
|
|
2694
|
+
style: { paddingLeft: "0.6rem" }
|
|
2695
|
+
},
|
|
2696
|
+
/* @__PURE__ */ React.createElement("span", null, s.title)
|
|
2697
|
+
)
|
|
2698
|
+
)));
|
|
2532
2699
|
return /* @__PURE__ */ React.createElement(ClickAwayListener, { onClickAway: () => setTooltipOpen(false) }, /* @__PURE__ */ React.createElement(
|
|
2533
2700
|
Tooltip,
|
|
2534
2701
|
{
|
|
@@ -2593,7 +2760,7 @@ const AggregatedCost = ({ riSc, initialRisk }) => {
|
|
|
2593
2760
|
const cost = riSc.scenarios.map(
|
|
2594
2761
|
(scenario) => initialRisk ? scenario.risk.probability * scenario.risk.consequence : scenario.remainingRisk.probability * scenario.remainingRisk.consequence
|
|
2595
2762
|
).reduce((a, b) => a + b, 0);
|
|
2596
|
-
return /* @__PURE__ */ React.createElement(Box$1, { className: outerBox }, /* @__PURE__ */ React.createElement(Typography, { className: label2 }, t("riskMatrix.estimatedRisk.title")), /* @__PURE__ */ React.createElement(Box$1, { className: innerBox }, /* @__PURE__ */ React.createElement(Typography, { className: body2 }, formatNumber(cost, t), " ", t("riskMatrix.estimatedRisk.unit.nokPerYear")), /* @__PURE__ */ React.createElement(IconButton, { size: "small", onClick: () => setShowDialog(true) }, /* @__PURE__ */ React.createElement(InfoIcon, null))), /* @__PURE__ */ React.createElement(
|
|
2763
|
+
return /* @__PURE__ */ React.createElement(Box$1, { className: outerBox }, /* @__PURE__ */ React.createElement(Typography, { className: label2 }, t("riskMatrix.estimatedRisk.title")), /* @__PURE__ */ React.createElement(Box$1, { className: innerBox }, /* @__PURE__ */ React.createElement(Typography, { className: body2 }, formatNumber(cost, t), " ", t("riskMatrix.estimatedRisk.unit.nokPerYear")), /* @__PURE__ */ React.createElement(IconButton$1, { size: "small", onClick: () => setShowDialog(true) }, /* @__PURE__ */ React.createElement(InfoIcon, null))), /* @__PURE__ */ React.createElement(
|
|
2597
2764
|
EstimatedRiskInfoDialog,
|
|
2598
2765
|
{
|
|
2599
2766
|
isOpen: showDialog,
|
|
@@ -2661,29 +2828,36 @@ const RiskMatrix = ({ riSc }) => {
|
|
|
2661
2828
|
centered
|
|
2662
2829
|
} = useRiskMatrixStyles();
|
|
2663
2830
|
const [tab, setTab] = useState("initialRisk" /* initialRisk */);
|
|
2664
|
-
return /* @__PURE__ */ React.createElement(
|
|
2665
|
-
|
|
2666
|
-
{
|
|
2667
|
-
riSc,
|
|
2668
|
-
initialRisk: tab === "initialRisk" /* initialRisk */
|
|
2669
|
-
}
|
|
2670
|
-
)), /* @__PURE__ */ React.createElement(Box$2, { className: gridWrapper }, /* @__PURE__ */ React.createElement(Box$2, { className: grid }, /* @__PURE__ */ React.createElement(Box$2, { className: konsekvens }, /* @__PURE__ */ React.createElement(Typography, { className: `${centered} ${label2}` }, t("dictionary.consequence"))), riskMatrix.map((row, rowIndex) => /* @__PURE__ */ React.createElement(Fragment, { key: rowIndex }, /* @__PURE__ */ React.createElement(Box$2, { className: centered }, /* @__PURE__ */ React.createElement(Typography, { className: text }, 5 - rowIndex)), row.map((col, colIndex) => /* @__PURE__ */ React.createElement(
|
|
2671
|
-
Box$2,
|
|
2831
|
+
return /* @__PURE__ */ React.createElement(
|
|
2832
|
+
InfoCard,
|
|
2672
2833
|
{
|
|
2673
|
-
|
|
2674
|
-
style: {
|
|
2675
|
-
key: colIndex
|
|
2834
|
+
title: t("riskMatrix.title"),
|
|
2835
|
+
titleTypographyProps: { style: { marginBottom: 0 } }
|
|
2676
2836
|
},
|
|
2677
|
-
/* @__PURE__ */ React.createElement(
|
|
2678
|
-
|
|
2837
|
+
/* @__PURE__ */ React.createElement(TabContext, { value: tab }, /* @__PURE__ */ React.createElement(Tabs, { setTab }), riSc.scenarios.length > 0 && /* @__PURE__ */ React.createElement(Box$2, { className: riskSummary }, /* @__PURE__ */ React.createElement(
|
|
2838
|
+
AggregatedCost,
|
|
2679
2839
|
{
|
|
2680
2840
|
riSc,
|
|
2681
|
-
probability: colIndex,
|
|
2682
|
-
consequence: 4 - rowIndex,
|
|
2683
2841
|
initialRisk: tab === "initialRisk" /* initialRisk */
|
|
2684
2842
|
}
|
|
2685
|
-
)
|
|
2686
|
-
|
|
2843
|
+
)), /* @__PURE__ */ React.createElement(Box$2, { className: gridWrapper }, /* @__PURE__ */ React.createElement(Box$2, { className: grid }, /* @__PURE__ */ React.createElement(Box$2, { className: konsekvens }, /* @__PURE__ */ React.createElement(Typography, { className: `${centered} ${label2}` }, t("dictionary.consequence"))), riskMatrix.map((row, rowIndex) => /* @__PURE__ */ React.createElement(Fragment, { key: rowIndex }, /* @__PURE__ */ React.createElement(Box$2, { className: centered }, /* @__PURE__ */ React.createElement(Typography, { className: text }, 5 - rowIndex)), row.map((col, colIndex) => /* @__PURE__ */ React.createElement(
|
|
2844
|
+
Box$2,
|
|
2845
|
+
{
|
|
2846
|
+
className: `${square} ${centered}`,
|
|
2847
|
+
style: { backgroundColor: col },
|
|
2848
|
+
key: colIndex
|
|
2849
|
+
},
|
|
2850
|
+
/* @__PURE__ */ React.createElement(
|
|
2851
|
+
RiskMatrixScenarioCount,
|
|
2852
|
+
{
|
|
2853
|
+
riSc,
|
|
2854
|
+
probability: colIndex,
|
|
2855
|
+
consequence: 4 - rowIndex,
|
|
2856
|
+
initialRisk: tab === "initialRisk" /* initialRisk */
|
|
2857
|
+
}
|
|
2858
|
+
)
|
|
2859
|
+
)))), /* @__PURE__ */ React.createElement(Box$2, { className: centered }), /* @__PURE__ */ React.createElement(Box$2, { className: centered }), riskMatrix.map((_, col) => /* @__PURE__ */ React.createElement(Box$2, { className: centered, key: col }, /* @__PURE__ */ React.createElement(Typography, { className: text }, col + 1))), /* @__PURE__ */ React.createElement(Box$2, { className: sannsynlighet }, /* @__PURE__ */ React.createElement(Typography, { className: `${centered} ${label2}` }, t("dictionary.probability"))))))
|
|
2860
|
+
);
|
|
2687
2861
|
};
|
|
2688
2862
|
|
|
2689
2863
|
const useTableStyles = makeStyles((theme) => ({
|
|
@@ -2801,9 +2975,10 @@ const ScenarioTableRow = ({
|
|
|
2801
2975
|
|
|
2802
2976
|
const ScenarioTable = ({ riSc }) => {
|
|
2803
2977
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
2978
|
+
const { label } = useFontStyles();
|
|
2804
2979
|
const { titleBox, rowBorder, tableCell, tableCellTitle } = useTableStyles();
|
|
2805
|
-
const { newScenario, openScenario } =
|
|
2806
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Paper, null, /* @__PURE__ */ React.createElement(Box$1, { className: titleBox }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5", style: { padding: "1rem" } }, t("scenarioTable.title")), riSc.scenarios.length > 0 && /* @__PURE__ */ React.createElement(
|
|
2980
|
+
const { newScenario, openScenario } = useScenario();
|
|
2981
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Paper, null, /* @__PURE__ */ React.createElement(Box$1, { className: titleBox }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5", style: { padding: "1rem", marginBottom: 0 } }, t("scenarioTable.title")), riSc.scenarios.length > 0 && /* @__PURE__ */ React.createElement(
|
|
2807
2982
|
Box$1,
|
|
2808
2983
|
{
|
|
2809
2984
|
style: {
|
|
@@ -2847,38 +3022,7 @@ const ScenarioTable = ({ riSc }) => {
|
|
|
2847
3022
|
},
|
|
2848
3023
|
t("scenarioTable.addScenarioButton")
|
|
2849
3024
|
)
|
|
2850
|
-
) : /* @__PURE__ */ React.createElement(TableContainer, { style: { overflow: "auto" }, component: Paper }, /* @__PURE__ */ React.createElement(Table, null, /* @__PURE__ */ React.createElement(TableHead,
|
|
2851
|
-
Typography,
|
|
2852
|
-
{
|
|
2853
|
-
variant: "subtitle1",
|
|
2854
|
-
style: { fontWeight: "bold", textTransform: "uppercase" }
|
|
2855
|
-
},
|
|
2856
|
-
t("dictionary.title")
|
|
2857
|
-
)), /* @__PURE__ */ React.createElement(TableCell, { className: tableCell }, /* @__PURE__ */ React.createElement(
|
|
2858
|
-
Typography,
|
|
2859
|
-
{
|
|
2860
|
-
variant: "subtitle1",
|
|
2861
|
-
style: { fontWeight: "bold", textTransform: "uppercase" }
|
|
2862
|
-
},
|
|
2863
|
-
t("dictionary.initialRisk")
|
|
2864
|
-
)), /* @__PURE__ */ React.createElement(TableCell, { className: tableCell }, /* @__PURE__ */ React.createElement(
|
|
2865
|
-
Typography,
|
|
2866
|
-
{
|
|
2867
|
-
variant: "subtitle1",
|
|
2868
|
-
style: { fontWeight: "bold", textTransform: "uppercase" }
|
|
2869
|
-
},
|
|
2870
|
-
t("scenarioTable.columns.measuresCount")
|
|
2871
|
-
)), /* @__PURE__ */ React.createElement(TableCell, { className: tableCell }, /* @__PURE__ */ React.createElement(
|
|
2872
|
-
Typography,
|
|
2873
|
-
{
|
|
2874
|
-
variant: "subtitle1",
|
|
2875
|
-
style: {
|
|
2876
|
-
fontWeight: "bold",
|
|
2877
|
-
textTransform: "uppercase"
|
|
2878
|
-
}
|
|
2879
|
-
},
|
|
2880
|
-
t("dictionary.restRisk")
|
|
2881
|
-
)))), /* @__PURE__ */ React.createElement(TableBody, null, riSc.scenarios.map((scenario, idx) => /* @__PURE__ */ React.createElement(
|
|
3025
|
+
) : /* @__PURE__ */ React.createElement(TableContainer, { style: { overflow: "auto" }, component: Paper }, /* @__PURE__ */ React.createElement(Table, null, /* @__PURE__ */ React.createElement(TableHead, { style: { whiteSpace: "nowrap" } }, /* @__PURE__ */ React.createElement(TableRow, { className: rowBorder }, /* @__PURE__ */ React.createElement(TableCell, { className: tableCellTitle }, /* @__PURE__ */ React.createElement(Typography, { className: label, style: { paddingBottom: 0 } }, t("dictionary.title"))), /* @__PURE__ */ React.createElement(TableCell, { className: tableCell }, /* @__PURE__ */ React.createElement(Typography, { className: label, style: { paddingBottom: 0 } }, t("dictionary.initialRisk"))), /* @__PURE__ */ React.createElement(TableCell, { className: tableCell }, /* @__PURE__ */ React.createElement(Typography, { className: label, style: { paddingBottom: 0 } }, t("scenarioTable.columns.measuresCount"))), /* @__PURE__ */ React.createElement(TableCell, { className: tableCell }, /* @__PURE__ */ React.createElement(Typography, { className: label, style: { paddingBottom: 0 } }, t("dictionary.restRisk"))))), /* @__PURE__ */ React.createElement(TableBody, null, riSc.scenarios.map((scenario, idx) => /* @__PURE__ */ React.createElement(
|
|
2882
3026
|
ScenarioTableRow,
|
|
2883
3027
|
{
|
|
2884
3028
|
key: scenario.ID,
|
|
@@ -2991,7 +3135,7 @@ const RiScDialog = ({
|
|
|
2991
3135
|
{
|
|
2992
3136
|
classes: { paper },
|
|
2993
3137
|
open: dialogState !== 0 /* Closed */,
|
|
2994
|
-
onClose:
|
|
3138
|
+
onClose: handleCancel,
|
|
2995
3139
|
...props
|
|
2996
3140
|
},
|
|
2997
3141
|
/* @__PURE__ */ React.createElement(DialogContent, null, /* @__PURE__ */ React.createElement(Typography, { className: h1 }, header), /* @__PURE__ */ React.createElement(Box$1, { className: content }, /* @__PURE__ */ React.createElement(
|
|
@@ -3031,116 +3175,6 @@ const RiScDialog = ({
|
|
|
3031
3175
|
);
|
|
3032
3176
|
};
|
|
3033
3177
|
|
|
3034
|
-
const useStatusChipStyles = makeStyles(() => ({
|
|
3035
|
-
statusChip: {
|
|
3036
|
-
borderRadius: "7px",
|
|
3037
|
-
maxHeight: "fit-content",
|
|
3038
|
-
height: "fit-content",
|
|
3039
|
-
margin: "0px"
|
|
3040
|
-
},
|
|
3041
|
-
statusChipText: {
|
|
3042
|
-
whiteSpace: "normal"
|
|
3043
|
-
},
|
|
3044
|
-
statusIcon: {
|
|
3045
|
-
maxHeight: "10px"
|
|
3046
|
-
},
|
|
3047
|
-
riScPublished: {
|
|
3048
|
-
borderColor: "#88e763",
|
|
3049
|
-
color: "#88e763"
|
|
3050
|
-
},
|
|
3051
|
-
riScSentForApproval: {
|
|
3052
|
-
borderColor: "#E7A563FF",
|
|
3053
|
-
color: "#E7A563FF"
|
|
3054
|
-
},
|
|
3055
|
-
riScDraft: {
|
|
3056
|
-
borderColor: "#FBE36A",
|
|
3057
|
-
color: "#FBE36A"
|
|
3058
|
-
}
|
|
3059
|
-
}));
|
|
3060
|
-
const useStatusTextStyles = makeStyles(() => ({
|
|
3061
|
-
prStatus: {
|
|
3062
|
-
fontSize: "14px",
|
|
3063
|
-
wrap: "wrap"
|
|
3064
|
-
},
|
|
3065
|
-
prIcon: {
|
|
3066
|
-
margin: "0px",
|
|
3067
|
-
padding: "0px",
|
|
3068
|
-
marginBottom: "-1px",
|
|
3069
|
-
marginRight: "2px",
|
|
3070
|
-
marginLeft: "2px"
|
|
3071
|
-
}
|
|
3072
|
-
}));
|
|
3073
|
-
|
|
3074
|
-
const getChipColor = (status, classes) => {
|
|
3075
|
-
switch (status) {
|
|
3076
|
-
case RiScStatus.Draft:
|
|
3077
|
-
return classes.riScDraft;
|
|
3078
|
-
case RiScStatus.SentForApproval:
|
|
3079
|
-
case RiScStatus.Published:
|
|
3080
|
-
return classes.riScPublished;
|
|
3081
|
-
default:
|
|
3082
|
-
return classes.riScDraft;
|
|
3083
|
-
}
|
|
3084
|
-
};
|
|
3085
|
-
const useChipText = (status) => {
|
|
3086
|
-
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
3087
|
-
switch (status) {
|
|
3088
|
-
case RiScStatus.Draft:
|
|
3089
|
-
return t("rosStatus.statusBadge.missing");
|
|
3090
|
-
case RiScStatus.SentForApproval:
|
|
3091
|
-
case RiScStatus.Published:
|
|
3092
|
-
return t("rosStatus.statusBadge.approved");
|
|
3093
|
-
default:
|
|
3094
|
-
return t("rosStatus.statusBadge.error");
|
|
3095
|
-
}
|
|
3096
|
-
};
|
|
3097
|
-
function ChipTextStatus({ status }) {
|
|
3098
|
-
const { statusChipText } = useStatusChipStyles();
|
|
3099
|
-
const chipText = useChipText(status);
|
|
3100
|
-
return /* @__PURE__ */ React.createElement("span", { className: statusChipText }, chipText);
|
|
3101
|
-
}
|
|
3102
|
-
function PRStatus({ status, classes }) {
|
|
3103
|
-
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
3104
|
-
switch (status) {
|
|
3105
|
-
case RiScStatus.SentForApproval:
|
|
3106
|
-
return /* @__PURE__ */ React.createElement(Typography, { className: classes.prStatus }, /* @__PURE__ */ React.createElement(GitHubIcon, { fontSize: "inherit", className: classes.prIcon }), t("rosStatus.prStatus"));
|
|
3107
|
-
case RiScStatus.Draft:
|
|
3108
|
-
case RiScStatus.Published:
|
|
3109
|
-
default:
|
|
3110
|
-
return null;
|
|
3111
|
-
}
|
|
3112
|
-
}
|
|
3113
|
-
const StatusChip = ({ currentRiScStatus }) => {
|
|
3114
|
-
const chipClasses = useStatusChipStyles();
|
|
3115
|
-
const textClasses = useStatusTextStyles();
|
|
3116
|
-
const [chipColorClass, setChipColorClass] = useState(null);
|
|
3117
|
-
useEffect(() => {
|
|
3118
|
-
const chipColor = getChipColor(currentRiScStatus, chipClasses);
|
|
3119
|
-
setChipColorClass(chipColor);
|
|
3120
|
-
}, [currentRiScStatus, chipClasses]);
|
|
3121
|
-
return /* @__PURE__ */ React.createElement(
|
|
3122
|
-
Grid,
|
|
3123
|
-
{
|
|
3124
|
-
container: true,
|
|
3125
|
-
direction: "column",
|
|
3126
|
-
spacing: 0,
|
|
3127
|
-
style: { alignItems: "end" }
|
|
3128
|
-
},
|
|
3129
|
-
/* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(
|
|
3130
|
-
Chip,
|
|
3131
|
-
{
|
|
3132
|
-
color: "primary",
|
|
3133
|
-
size: "medium",
|
|
3134
|
-
variant: "outlined",
|
|
3135
|
-
label: /* @__PURE__ */ React.createElement(ChipTextStatus, { status: currentRiScStatus }),
|
|
3136
|
-
icon: /* @__PURE__ */ React.createElement(CircleIcon$1, { className: chipClasses.statusIcon }),
|
|
3137
|
-
className: [chipColorClass, chipClasses.statusChip].join(" ")
|
|
3138
|
-
}
|
|
3139
|
-
)),
|
|
3140
|
-
/* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(PRStatus, { status: currentRiScStatus, classes: textClasses }))
|
|
3141
|
-
);
|
|
3142
|
-
};
|
|
3143
|
-
|
|
3144
3178
|
const useButtonStyles = makeStyles(() => ({
|
|
3145
3179
|
approveButton: {
|
|
3146
3180
|
borderRadius: "2px",
|
|
@@ -3190,6 +3224,49 @@ const RiScPublishDialog = ({
|
|
|
3190
3224
|
))
|
|
3191
3225
|
));
|
|
3192
3226
|
};
|
|
3227
|
+
function PullRequestSvg() {
|
|
3228
|
+
const theme = useTheme();
|
|
3229
|
+
return /* @__PURE__ */ React.createElement(
|
|
3230
|
+
"svg",
|
|
3231
|
+
{
|
|
3232
|
+
width: "18",
|
|
3233
|
+
height: "16",
|
|
3234
|
+
viewBox: "0 0 16 16",
|
|
3235
|
+
fill: "none",
|
|
3236
|
+
style: {
|
|
3237
|
+
transform: "translateY(2px)"
|
|
3238
|
+
},
|
|
3239
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
3240
|
+
},
|
|
3241
|
+
/* @__PURE__ */ React.createElement(
|
|
3242
|
+
"path",
|
|
3243
|
+
{
|
|
3244
|
+
d: "M9.55625 0.065625C9.825 0.184375 10 0.453125 10 0.75V2.25H10.5C12.5719 2.25 14.25 3.92812 14.25 6V11.1156C15.2656 11.4344 16 12.3813 16 13.5C16 14.8813 14.8813 16 13.5 16C12.1187 16 11 14.8813 11 13.5C11 12.3813 11.7344 11.4344 12.75 11.1156V6C12.75 4.75625 11.7437 3.75 10.5 3.75H10V5.25C10 5.54688 9.825 5.81562 9.55625 5.93437C9.2875 6.05312 8.96875 6.00625 8.75 5.80625L6.25 3.55625C6.09062 3.4125 6.00313 3.2125 6.00313 3C6.00313 2.7875 6.09375 2.58437 6.25 2.44375L8.75 0.19375C8.96875 -0.00312501 9.2875 -0.053125 9.55625 0.065625ZM3.5 2.5C3.5 2.23478 3.39464 1.98043 3.20711 1.79289C3.01957 1.60536 2.76522 1.5 2.5 1.5C2.23478 1.5 1.98043 1.60536 1.79289 1.79289C1.60536 1.98043 1.5 2.23478 1.5 2.5C1.5 2.76522 1.60536 3.01957 1.79289 3.20711C1.98043 3.39464 2.23478 3.5 2.5 3.5C2.76522 3.5 3.01957 3.39464 3.20711 3.20711C3.39464 3.01957 3.5 2.76522 3.5 2.5ZM3.25 4.88438V11.1156C4.26562 11.4344 5 12.3813 5 13.5C5 14.8813 3.88125 16 2.5 16C1.11875 16 0 14.8813 0 13.5C0 12.3813 0.734375 11.4344 1.75 11.1156V4.88438C0.734375 4.56563 0 3.61875 0 2.5C0 1.11875 1.11875 0 2.5 0C3.88125 0 5 1.11875 5 2.5C5 3.61875 4.26562 4.56563 3.25 4.88438ZM3.5 13.5C3.5 13.2348 3.39464 12.9804 3.20711 12.7929C3.01957 12.6054 2.76522 12.5 2.5 12.5C2.23478 12.5 1.98043 12.6054 1.79289 12.7929C1.60536 12.9804 1.5 13.2348 1.5 13.5C1.5 13.7652 1.60536 14.0196 1.79289 14.2071C1.98043 14.3946 2.23478 14.5 2.5 14.5C2.76522 14.5 3.01957 14.3946 3.20711 14.2071C3.39464 14.0196 3.5 13.7652 3.5 13.5ZM13.5 14.5C13.7652 14.5 14.0196 14.3946 14.2071 14.2071C14.3946 14.0196 14.5 13.7652 14.5 13.5C14.5 13.2348 14.3946 12.9804 14.2071 12.7929C14.0196 12.6054 13.7652 12.5 13.5 12.5C13.2348 12.5 12.9804 12.6054 12.7929 12.7929C12.6054 12.9804 12.5 13.2348 12.5 13.5C12.5 13.7652 12.6054 14.0196 12.7929 14.2071C12.9804 14.3946 13.2348 14.5 13.5 14.5Z",
|
|
3245
|
+
fill: theme.palette.type === "dark" ? "white" : "rgba(0, 0, 0, 0.87)"
|
|
3246
|
+
}
|
|
3247
|
+
)
|
|
3248
|
+
);
|
|
3249
|
+
}
|
|
3250
|
+
const RosAcceptance = ({
|
|
3251
|
+
status
|
|
3252
|
+
}) => {
|
|
3253
|
+
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
3254
|
+
switch (status) {
|
|
3255
|
+
case RiScStatus.Draft:
|
|
3256
|
+
return /* @__PURE__ */ React.createElement(Typography, { paragraph: true, style: { fontWeight: 700 }, variant: "subtitle1" }, t("rosStatus.statusBadge.missing"));
|
|
3257
|
+
case RiScStatus.SentForApproval:
|
|
3258
|
+
case RiScStatus.Published:
|
|
3259
|
+
return /* @__PURE__ */ React.createElement(Typography, { paragraph: true, style: { fontWeight: 700 }, variant: "subtitle1" }, /* @__PURE__ */ React.createElement(
|
|
3260
|
+
CheckIcon,
|
|
3261
|
+
{
|
|
3262
|
+
fontSize: "medium",
|
|
3263
|
+
style: { transform: "translateY(5px)" }
|
|
3264
|
+
}
|
|
3265
|
+
), " ", t("rosStatus.statusBadge.approved"));
|
|
3266
|
+
default:
|
|
3267
|
+
return /* @__PURE__ */ React.createElement(Typography, { paragraph: true, variant: "subtitle1" }, t("rosStatus.statusBadge.error"));
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3193
3270
|
const RiScStatusComponent = ({
|
|
3194
3271
|
selectedRiSc,
|
|
3195
3272
|
publishRiScFn
|
|
@@ -3201,50 +3278,66 @@ const RiScStatusComponent = ({
|
|
|
3201
3278
|
publishRiScFn();
|
|
3202
3279
|
setPublishRiScDialogIsOpen(false);
|
|
3203
3280
|
};
|
|
3204
|
-
return /* @__PURE__ */ React.createElement(
|
|
3205
|
-
|
|
3281
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, "Status"), /* @__PURE__ */ React.createElement(RosAcceptance, { status: selectedRiSc.status }), selectedRiSc.status === RiScStatus.SentForApproval && /* @__PURE__ */ React.createElement(Typography, { style: { fontWeight: 700 }, paragraph: true, variant: "subtitle1" }, /* @__PURE__ */ React.createElement(PullRequestSvg, null), t("rosStatus.prStatus"), /* @__PURE__ */ React.createElement(Link$1, { target: "_blank", href: selectedRiSc.pullRequestUrl }, "Github")), /* @__PURE__ */ React.createElement(
|
|
3282
|
+
Grid,
|
|
3206
3283
|
{
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3284
|
+
item: true,
|
|
3285
|
+
container: true,
|
|
3286
|
+
xs: true,
|
|
3287
|
+
direction: "row",
|
|
3288
|
+
alignItems: "flex-end",
|
|
3289
|
+
justifyContent: "space-between"
|
|
3213
3290
|
},
|
|
3214
|
-
/* @__PURE__ */ React.createElement(
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3291
|
+
/* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" })),
|
|
3292
|
+
/* @__PURE__ */ React.createElement(Grid, { item: true }, selectedRiSc.status === RiScStatus.Draft && /* @__PURE__ */ React.createElement(
|
|
3293
|
+
Button,
|
|
3294
|
+
{
|
|
3295
|
+
color: "primary",
|
|
3296
|
+
variant: "contained",
|
|
3297
|
+
onClick: () => setPublishRiScDialogIsOpen(!publishRiScDialogIsOpen),
|
|
3298
|
+
className: approveButton,
|
|
3299
|
+
fullWidth: true,
|
|
3300
|
+
disabled: selectedRiSc.status !== RiScStatus.Draft
|
|
3301
|
+
},
|
|
3302
|
+
/* @__PURE__ */ React.createElement(Typography, { variant: "button" }, t("rosStatus.approveButton"))
|
|
3303
|
+
)),
|
|
3304
|
+
/* @__PURE__ */ React.createElement(
|
|
3305
|
+
RiScPublishDialog,
|
|
3306
|
+
{
|
|
3307
|
+
openDialog: publishRiScDialogIsOpen,
|
|
3308
|
+
handlePublish: handleApproveAndPublish,
|
|
3309
|
+
handleCancel: () => setPublishRiScDialogIsOpen(false)
|
|
3310
|
+
}
|
|
3311
|
+
)
|
|
3222
3312
|
));
|
|
3223
3313
|
};
|
|
3224
3314
|
|
|
3225
|
-
const
|
|
3226
|
-
|
|
3227
|
-
|
|
3315
|
+
const useEditButtonStyle = makeStyles((theme) => ({
|
|
3316
|
+
icon: {
|
|
3317
|
+
color: theme.palette.type === "dark" ? "#fff" : "rgba(0, 0, 0, 0.54)"
|
|
3228
3318
|
}
|
|
3229
3319
|
}));
|
|
3320
|
+
const EditButton = (props) => {
|
|
3321
|
+
const { icon } = useEditButtonStyle();
|
|
3322
|
+
return /* @__PURE__ */ React.createElement(IconButton$1, { size: "small", ...props }, /* @__PURE__ */ React.createElement(EditIcon, { className: icon, "aria-label": "Edit" }));
|
|
3323
|
+
};
|
|
3230
3324
|
|
|
3231
3325
|
const RiScInfo = ({ riSc, approveRiSc, edit }) => {
|
|
3232
3326
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
3233
3327
|
const { label, body2 } = useFontStyles();
|
|
3234
|
-
const { infoCard } = useRiScInfoStyles();
|
|
3235
3328
|
return /* @__PURE__ */ React.createElement(Grid, { container: true }, /* @__PURE__ */ React.createElement(
|
|
3236
3329
|
Grid,
|
|
3237
3330
|
{
|
|
3238
3331
|
item: true,
|
|
3239
3332
|
xs: 12,
|
|
3240
3333
|
sm: 6,
|
|
3241
|
-
md:
|
|
3334
|
+
md: 6,
|
|
3242
3335
|
style: {
|
|
3243
3336
|
display: "flex",
|
|
3244
3337
|
flexDirection: "column"
|
|
3245
3338
|
}
|
|
3246
3339
|
},
|
|
3247
|
-
/* @__PURE__ */ React.createElement(InfoCard,
|
|
3340
|
+
/* @__PURE__ */ React.createElement(InfoCard, null, /* @__PURE__ */ React.createElement(
|
|
3248
3341
|
Box$1,
|
|
3249
3342
|
{
|
|
3250
3343
|
style: {
|
|
@@ -3254,9 +3347,15 @@ const RiScInfo = ({ riSc, approveRiSc, edit }) => {
|
|
|
3254
3347
|
}
|
|
3255
3348
|
},
|
|
3256
3349
|
/* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, riSc.content.title),
|
|
3257
|
-
/* @__PURE__ */ React.createElement(
|
|
3350
|
+
/* @__PURE__ */ React.createElement(EditButton, { onClick: edit })
|
|
3258
3351
|
), /* @__PURE__ */ React.createElement(Typography, { className: label }, t("dictionary.scope")), /* @__PURE__ */ React.createElement(Typography, { className: body2 }, riSc.content.scope))
|
|
3259
|
-
), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, sm: 6, md:
|
|
3352
|
+
), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, sm: 6, md: 6 }, /* @__PURE__ */ React.createElement(InfoCard, null, /* @__PURE__ */ React.createElement(
|
|
3353
|
+
RiScStatusComponent,
|
|
3354
|
+
{
|
|
3355
|
+
selectedRiSc: riSc,
|
|
3356
|
+
publishRiScFn: approveRiSc
|
|
3357
|
+
}
|
|
3358
|
+
))));
|
|
3260
3359
|
};
|
|
3261
3360
|
|
|
3262
3361
|
const useLinearProgressStyle = makeStyles((theme) => ({
|
|
@@ -3267,8 +3366,16 @@ const useLinearProgressStyle = makeStyles((theme) => ({
|
|
|
3267
3366
|
}
|
|
3268
3367
|
}));
|
|
3269
3368
|
|
|
3369
|
+
var _a;
|
|
3370
|
+
const emotionInsertionPoint = document.createElement("meta");
|
|
3371
|
+
emotionInsertionPoint.setAttribute("name", "emotion-insertion-point");
|
|
3372
|
+
(_a = document.querySelector("head")) == null ? void 0 : _a.appendChild(emotionInsertionPoint);
|
|
3373
|
+
const cache = createCache({
|
|
3374
|
+
key: "css",
|
|
3375
|
+
insertionPoint: emotionInsertionPoint
|
|
3376
|
+
});
|
|
3270
3377
|
const Plugin = () => {
|
|
3271
|
-
var
|
|
3378
|
+
var _a2, _b;
|
|
3272
3379
|
const params = useParams();
|
|
3273
3380
|
const { t } = useTranslationRef(pluginRiScTranslationRef);
|
|
3274
3381
|
const { linearProgress } = useLinearProgressStyle();
|
|
@@ -3291,77 +3398,84 @@ const Plugin = () => {
|
|
|
3291
3398
|
response,
|
|
3292
3399
|
isRequesting
|
|
3293
3400
|
} = useFetchRiScs(params.riScId);
|
|
3294
|
-
const scenario = useScenarioDrawer(
|
|
3295
|
-
selectedRiSc != null ? selectedRiSc : null,
|
|
3296
|
-
updateRiSc,
|
|
3297
|
-
params.scenarioId
|
|
3298
|
-
);
|
|
3299
3401
|
const [searchParams] = useSearchParams();
|
|
3300
3402
|
const scenarioWizardStep = searchParams.get("step") || null;
|
|
3301
3403
|
useEffect(() => {
|
|
3302
3404
|
if (scenarioWizardStep !== null)
|
|
3303
3405
|
resetRiScStatus();
|
|
3304
3406
|
}, [resetRiScStatus, scenarioWizardStep]);
|
|
3305
|
-
return /* @__PURE__ */ React.createElement(
|
|
3306
|
-
|
|
3307
|
-
{
|
|
3308
|
-
step: scenarioWizardStep,
|
|
3309
|
-
isFetching,
|
|
3310
|
-
updateStatus: updateRiScStatus
|
|
3311
|
-
}
|
|
3312
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ContentHeader, { title: t("contentHeader.title") }, /* @__PURE__ */ React.createElement(SupportButton, null)), isFetching && /* @__PURE__ */ React.createElement(Spinner, { size: 80 }), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 4 }, riScs !== null && riScs.length !== 0 && /* @__PURE__ */ React.createElement(
|
|
3313
|
-
Grid,
|
|
3407
|
+
return /* @__PURE__ */ React.createElement(CacheProvider, { value: cache }, /* @__PURE__ */ React.createElement(
|
|
3408
|
+
ScenarioProvider,
|
|
3314
3409
|
{
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
style: {
|
|
3319
|
-
maxWidth: "600px",
|
|
3320
|
-
minWidth: "300px"
|
|
3321
|
-
}
|
|
3410
|
+
riSc: selectedRiSc != null ? selectedRiSc : null,
|
|
3411
|
+
updateRiSc,
|
|
3412
|
+
scenarioIdFromParams: params.scenarioId
|
|
3322
3413
|
},
|
|
3323
|
-
/* @__PURE__ */ React.createElement(
|
|
3324
|
-
|
|
3414
|
+
response && /* @__PURE__ */ React.createElement(Alert, { severity: getAlertSeverity(response.status) }, /* @__PURE__ */ React.createElement(Typography, null, response.statusMessage)),
|
|
3415
|
+
isRequesting && /* @__PURE__ */ React.createElement(LinearProgress, { className: linearProgress }),
|
|
3416
|
+
scenarioWizardStep !== null ? /* @__PURE__ */ React.createElement(
|
|
3417
|
+
ScenarioWizard,
|
|
3325
3418
|
{
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
variant: "standard"
|
|
3419
|
+
step: scenarioWizardStep,
|
|
3420
|
+
isFetching,
|
|
3421
|
+
updateStatus: updateRiScStatus
|
|
3330
3422
|
}
|
|
3331
|
-
)
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3423
|
+
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ContentHeader, { title: t("contentHeader.title") }, /* @__PURE__ */ React.createElement(SupportButton, null)), isFetching && /* @__PURE__ */ React.createElement(Spinner, { size: 80 }), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 4 }, riScs !== null && riScs.length !== 0 && /* @__PURE__ */ React.createElement(
|
|
3424
|
+
Grid,
|
|
3425
|
+
{
|
|
3426
|
+
item: true,
|
|
3427
|
+
xs: 12,
|
|
3428
|
+
sm: 6,
|
|
3429
|
+
style: {
|
|
3430
|
+
maxWidth: "600px",
|
|
3431
|
+
minWidth: "300px"
|
|
3432
|
+
}
|
|
3433
|
+
},
|
|
3434
|
+
/* @__PURE__ */ React.createElement(
|
|
3435
|
+
Dropdown,
|
|
3436
|
+
{
|
|
3437
|
+
options: (_a2 = riScs.map((riSc) => riSc.content.title)) != null ? _a2 : [],
|
|
3438
|
+
selectedValues: (_b = selectedRiSc == null ? void 0 : selectedRiSc.content.title) != null ? _b : "",
|
|
3439
|
+
handleChange: (title) => selectRiSc(title),
|
|
3440
|
+
variant: "standard"
|
|
3441
|
+
}
|
|
3442
|
+
)
|
|
3443
|
+
), !isFetching && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React.createElement(
|
|
3444
|
+
Button,
|
|
3445
|
+
{
|
|
3446
|
+
startIcon: /* @__PURE__ */ React.createElement(AddCircle, null),
|
|
3447
|
+
variant: "text",
|
|
3448
|
+
color: "primary",
|
|
3449
|
+
onClick: openCreateRiScDialog,
|
|
3450
|
+
style: {
|
|
3451
|
+
minWidth: "205px"
|
|
3452
|
+
}
|
|
3453
|
+
},
|
|
3454
|
+
t("contentHeader.createNewButton")
|
|
3455
|
+
)), selectedRiSc && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
|
|
3456
|
+
RiScInfo,
|
|
3457
|
+
{
|
|
3458
|
+
riSc: selectedRiSc,
|
|
3459
|
+
approveRiSc,
|
|
3460
|
+
edit: openEditRiScDialog
|
|
3341
3461
|
}
|
|
3342
|
-
},
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
createNewRiSc,
|
|
3356
|
-
updateRiSc,
|
|
3357
|
-
riSc: selectedRiSc,
|
|
3358
|
-
dialogState: RiScDialogState
|
|
3359
|
-
}
|
|
3360
|
-
), !scenarioWizardStep && /* @__PURE__ */ React.createElement(ScenarioDrawer, null)));
|
|
3462
|
+
)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true, md: 7, lg: 8 }, /* @__PURE__ */ React.createElement(ScenarioTable, { riSc: selectedRiSc.content })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: true, md: 5, lg: 4 }, /* @__PURE__ */ React.createElement(RiskMatrix, { riSc: selectedRiSc.content }))))),
|
|
3463
|
+
RiScDialogState !== RiScDialogStates.Closed && /* @__PURE__ */ React.createElement(
|
|
3464
|
+
RiScDialog,
|
|
3465
|
+
{
|
|
3466
|
+
onClose: closeRiScDialog,
|
|
3467
|
+
createNewRiSc,
|
|
3468
|
+
updateRiSc,
|
|
3469
|
+
riSc: selectedRiSc,
|
|
3470
|
+
dialogState: RiScDialogState
|
|
3471
|
+
}
|
|
3472
|
+
),
|
|
3473
|
+
!scenarioWizardStep && /* @__PURE__ */ React.createElement(ScenarioDrawer, null)
|
|
3474
|
+
));
|
|
3361
3475
|
};
|
|
3362
3476
|
const RiScPlugin = () => {
|
|
3363
3477
|
return /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, { path: "/", element: /* @__PURE__ */ React.createElement(Plugin, null) }), /* @__PURE__ */ React.createElement(Route, { path: riScRouteRef.path, element: /* @__PURE__ */ React.createElement(Plugin, null) }), /* @__PURE__ */ React.createElement(Route, { path: scenarioRouteRef.path, element: /* @__PURE__ */ React.createElement(Plugin, null) }));
|
|
3364
3478
|
};
|
|
3365
3479
|
|
|
3366
3480
|
export { RiScPlugin };
|
|
3367
|
-
//# sourceMappingURL=index-
|
|
3481
|
+
//# sourceMappingURL=index-99d0fef8.esm.js.map
|