@kopexa/grc 0.0.2 → 0.0.4
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/chunk-5TBN3JQA.mjs +66 -0
- package/dist/{chunk-TW3S4OE2.mjs → chunk-AGASJJ7X.mjs} +106 -82
- package/dist/chunk-DC44K745.mjs +46 -0
- package/dist/chunk-HI7F2CF4.mjs +1 -0
- package/dist/chunk-HJUSN7FD.mjs +1 -0
- package/dist/chunk-QDYL5ABK.mjs +118 -0
- package/dist/chunk-QS5S6V26.mjs +22 -0
- package/dist/chunk-VFX3DASQ.mjs +57 -0
- package/dist/common/control/index.d.mts +3 -0
- package/dist/common/control/index.d.ts +3 -0
- package/dist/common/control/index.js +160 -0
- package/dist/common/control/index.mjs +11 -0
- package/dist/common/control/mapped-controls.d.mts +33 -0
- package/dist/common/control/mapped-controls.d.ts +33 -0
- package/dist/common/control/mapped-controls.js +159 -0
- package/dist/common/control/mapped-controls.mjs +11 -0
- package/dist/common/control/messages.d.mts +16 -0
- package/dist/common/control/messages.d.ts +16 -0
- package/dist/common/control/messages.js +45 -0
- package/dist/common/control/messages.mjs +7 -0
- package/dist/common/impact/impact-card.d.mts +7 -1
- package/dist/common/impact/impact-card.d.ts +7 -1
- package/dist/common/impact/impact-card.js +105 -81
- package/dist/common/impact/impact-card.mjs +1 -1
- package/dist/common/impact/index.js +105 -81
- package/dist/common/impact/index.mjs +1 -1
- package/dist/common/index.d.mts +5 -0
- package/dist/common/index.d.ts +5 -0
- package/dist/common/index.js +458 -145
- package/dist/common/index.mjs +27 -2
- package/dist/common/risk/index.d.mts +4 -0
- package/dist/common/risk/index.d.ts +4 -0
- package/dist/common/risk/index.js +185 -0
- package/dist/common/risk/index.mjs +20 -0
- package/dist/common/risk/messages.d.mts +40 -0
- package/dist/common/risk/messages.d.ts +40 -0
- package/dist/common/risk/messages.js +69 -0
- package/dist/common/risk/messages.mjs +7 -0
- package/dist/common/risk/risk-rating-display.d.mts +21 -0
- package/dist/common/risk/risk-rating-display.d.ts +21 -0
- package/dist/common/risk/risk-rating-display.js +139 -0
- package/dist/common/risk/risk-rating-display.mjs +10 -0
- package/dist/common/risk/types.d.mts +37 -0
- package/dist/common/risk/types.d.ts +37 -0
- package/dist/common/risk/types.js +82 -0
- package/dist/common/risk/types.mjs +11 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +458 -145
- package/dist/index.mjs +27 -2
- package/package.json +8 -7
- package/src/common/control/index.ts +6 -0
- package/src/common/control/mapped-controls.tsx +192 -0
- package/src/common/control/messages.ts +16 -0
- package/src/common/impact/impact-card.tsx +132 -79
- package/src/common/index.ts +2 -0
- package/src/common/risk/index.ts +12 -0
- package/src/common/risk/messages.ts +40 -0
- package/src/common/risk/risk-rating-display.tsx +86 -0
- package/src/common/risk/types.ts +91 -0
- /package/dist/{chunk-BFZPRJQT.mjs → chunk-CND77GVC.mjs} +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
messages
|
|
4
|
+
} from "./chunk-DC44K745.mjs";
|
|
5
|
+
import {
|
|
6
|
+
getRiskLevelFromRating,
|
|
7
|
+
isRatingUnrated
|
|
8
|
+
} from "./chunk-VFX3DASQ.mjs";
|
|
9
|
+
|
|
10
|
+
// src/common/risk/risk-rating-display.tsx
|
|
11
|
+
import { useSafeIntl } from "@kopexa/i18n";
|
|
12
|
+
import { Tooltip } from "@kopexa/sight";
|
|
13
|
+
import { riskRating } from "@kopexa/theme";
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
function RiskRatingDisplay({
|
|
16
|
+
rating,
|
|
17
|
+
showBadge = true,
|
|
18
|
+
showLabel = true,
|
|
19
|
+
size = "md"
|
|
20
|
+
}) {
|
|
21
|
+
const intl = useSafeIntl();
|
|
22
|
+
if (isRatingUnrated(rating)) {
|
|
23
|
+
const styles2 = riskRating({ size, level: "unrated" });
|
|
24
|
+
const levelLabel2 = intl.formatMessage(messages.level_unrated);
|
|
25
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: intl.formatMessage(messages.not_rated_hint), children: /* @__PURE__ */ jsxs("div", { className: styles2.base(), children: [
|
|
26
|
+
showBadge && /* @__PURE__ */ jsx("div", { className: styles2.badge(), children: "\u2014" }),
|
|
27
|
+
showLabel && /* @__PURE__ */ jsx("span", { className: styles2.label(), children: levelLabel2 })
|
|
28
|
+
] }) });
|
|
29
|
+
}
|
|
30
|
+
const ratedValue = rating;
|
|
31
|
+
const level = getRiskLevelFromRating(ratedValue.rating);
|
|
32
|
+
const styles = riskRating({
|
|
33
|
+
size,
|
|
34
|
+
level
|
|
35
|
+
});
|
|
36
|
+
const levelLabelKey = `level_${level}`;
|
|
37
|
+
const levelLabel = intl.formatMessage(messages[levelLabelKey]);
|
|
38
|
+
return /* @__PURE__ */ jsx(
|
|
39
|
+
Tooltip,
|
|
40
|
+
{
|
|
41
|
+
content: /* @__PURE__ */ jsxs("div", { className: "text-xs space-y-1", children: [
|
|
42
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
43
|
+
intl.formatMessage(messages.likelihood),
|
|
44
|
+
": ",
|
|
45
|
+
ratedValue.likelihood,
|
|
46
|
+
"/5"
|
|
47
|
+
] }),
|
|
48
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
49
|
+
intl.formatMessage(messages.consequence),
|
|
50
|
+
": ",
|
|
51
|
+
ratedValue.consequence,
|
|
52
|
+
"/5"
|
|
53
|
+
] }),
|
|
54
|
+
ratedValue.comment && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: ratedValue.comment })
|
|
55
|
+
] }),
|
|
56
|
+
children: /* @__PURE__ */ jsxs("div", { className: styles.base(), children: [
|
|
57
|
+
showBadge && /* @__PURE__ */ jsx("div", { className: styles.badge(), children: ratedValue.rating }),
|
|
58
|
+
showLabel && /* @__PURE__ */ jsx("span", { className: styles.label(), children: levelLabel })
|
|
59
|
+
] })
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export {
|
|
65
|
+
RiskRatingDisplay
|
|
66
|
+
};
|
|
@@ -13,7 +13,7 @@ import { EditIcon } from "@kopexa/icons";
|
|
|
13
13
|
import { Button, Card, Chip, Heading, Select, Textarea } from "@kopexa/sight";
|
|
14
14
|
import { impactCard } from "@kopexa/theme";
|
|
15
15
|
import { useState } from "react";
|
|
16
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
17
17
|
function ImpactItemRow({
|
|
18
18
|
label,
|
|
19
19
|
shortLabel,
|
|
@@ -82,15 +82,18 @@ function ImpactCard({
|
|
|
82
82
|
showAuthenticity = false,
|
|
83
83
|
readOnly = false,
|
|
84
84
|
scale = "risk",
|
|
85
|
-
title
|
|
85
|
+
title,
|
|
86
|
+
variant = "card"
|
|
86
87
|
}) {
|
|
87
88
|
var _a, _b;
|
|
88
89
|
const intl = useSafeIntl();
|
|
90
|
+
const isInline = variant === "inline";
|
|
89
91
|
const [isEditing, setIsEditing] = useState(false);
|
|
90
92
|
const [editValues, setEditValues] = useState(
|
|
91
93
|
value || defaultImpact
|
|
92
94
|
);
|
|
93
|
-
const
|
|
95
|
+
const effectiveIsEditing = isInline ? !readOnly : isEditing;
|
|
96
|
+
const styles = impactCard({ editing: !isInline && isEditing });
|
|
94
97
|
const scaleConfig = typeof scale === "string" ? getScale(scale) : scale;
|
|
95
98
|
const formatLabel = (level) => {
|
|
96
99
|
const config = scaleConfig[level];
|
|
@@ -126,18 +129,28 @@ function ImpactCard({
|
|
|
126
129
|
setEditValues(value || defaultImpact);
|
|
127
130
|
setIsEditing(true);
|
|
128
131
|
};
|
|
129
|
-
const currentImpact = isEditing ? editValues : value || defaultImpact;
|
|
132
|
+
const currentImpact = isInline ? value || defaultImpact : isEditing ? editValues : value || defaultImpact;
|
|
130
133
|
const handleLevelChange = (key) => (level) => {
|
|
131
|
-
|
|
132
|
-
...
|
|
134
|
+
const newValues = {
|
|
135
|
+
...isInline ? value || defaultImpact : editValues,
|
|
133
136
|
[key]: level
|
|
134
|
-
}
|
|
137
|
+
};
|
|
138
|
+
if (isInline) {
|
|
139
|
+
onChange == null ? void 0 : onChange(newValues);
|
|
140
|
+
} else {
|
|
141
|
+
setEditValues(newValues);
|
|
142
|
+
}
|
|
135
143
|
};
|
|
136
144
|
const handleJustificationChange = (justification) => {
|
|
137
|
-
|
|
138
|
-
...
|
|
145
|
+
const newValues = {
|
|
146
|
+
...isInline ? value || defaultImpact : editValues,
|
|
139
147
|
impactJustification: justification || void 0
|
|
140
|
-
}
|
|
148
|
+
};
|
|
149
|
+
if (isInline) {
|
|
150
|
+
onChange == null ? void 0 : onChange(newValues);
|
|
151
|
+
} else {
|
|
152
|
+
setEditValues(newValues);
|
|
153
|
+
}
|
|
141
154
|
};
|
|
142
155
|
const highestImpact = Math.max(
|
|
143
156
|
currentImpact.impactConfidentiality,
|
|
@@ -149,6 +162,87 @@ function ImpactCard({
|
|
|
149
162
|
const justificationHint = intl.formatMessage(messages.justification_hint, {
|
|
150
163
|
level: highestLabel
|
|
151
164
|
});
|
|
165
|
+
const impactRows = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
166
|
+
/* @__PURE__ */ jsx(
|
|
167
|
+
ImpactItemRow,
|
|
168
|
+
{
|
|
169
|
+
label: t.confidentiality,
|
|
170
|
+
shortLabel: "C",
|
|
171
|
+
value: currentImpact.impactConfidentiality,
|
|
172
|
+
isEditing: effectiveIsEditing,
|
|
173
|
+
scale: scaleConfig,
|
|
174
|
+
formatLabel,
|
|
175
|
+
onLevelChange: handleLevelChange("impactConfidentiality")
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
/* @__PURE__ */ jsx(
|
|
179
|
+
ImpactItemRow,
|
|
180
|
+
{
|
|
181
|
+
label: t.integrity,
|
|
182
|
+
shortLabel: "I",
|
|
183
|
+
value: currentImpact.impactIntegrity,
|
|
184
|
+
isEditing: effectiveIsEditing,
|
|
185
|
+
scale: scaleConfig,
|
|
186
|
+
formatLabel,
|
|
187
|
+
onLevelChange: handleLevelChange("impactIntegrity")
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ jsx(
|
|
191
|
+
ImpactItemRow,
|
|
192
|
+
{
|
|
193
|
+
label: t.availability,
|
|
194
|
+
shortLabel: "A",
|
|
195
|
+
value: currentImpact.impactAvailability,
|
|
196
|
+
isEditing: effectiveIsEditing,
|
|
197
|
+
scale: scaleConfig,
|
|
198
|
+
formatLabel,
|
|
199
|
+
onLevelChange: handleLevelChange("impactAvailability")
|
|
200
|
+
}
|
|
201
|
+
),
|
|
202
|
+
showAuthenticity && /* @__PURE__ */ jsx(
|
|
203
|
+
ImpactItemRow,
|
|
204
|
+
{
|
|
205
|
+
label: t.authenticity,
|
|
206
|
+
shortLabel: "Au",
|
|
207
|
+
value: (_b = currentImpact.impactAuthenticity) != null ? _b : 0,
|
|
208
|
+
isEditing: effectiveIsEditing,
|
|
209
|
+
scale: scaleConfig,
|
|
210
|
+
formatLabel,
|
|
211
|
+
onLevelChange: handleLevelChange("impactAuthenticity")
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
] });
|
|
215
|
+
const justificationContent = showJustification && /* @__PURE__ */ jsxs("div", { className: styles.justificationSection(), children: [
|
|
216
|
+
/* @__PURE__ */ jsxs(
|
|
217
|
+
"label",
|
|
218
|
+
{
|
|
219
|
+
htmlFor: "impact-justification",
|
|
220
|
+
className: styles.justificationLabel(),
|
|
221
|
+
children: [
|
|
222
|
+
t.justification,
|
|
223
|
+
highestImpact > 0 && /* @__PURE__ */ jsx("span", { className: styles.justificationHint(), children: justificationHint })
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
),
|
|
227
|
+
effectiveIsEditing ? /* @__PURE__ */ jsx(
|
|
228
|
+
Textarea,
|
|
229
|
+
{
|
|
230
|
+
id: "impact-justification",
|
|
231
|
+
value: currentImpact.impactJustification || "",
|
|
232
|
+
onChange: (e) => handleJustificationChange(e.target.value),
|
|
233
|
+
placeholder: t.justificationPlaceholder,
|
|
234
|
+
rows: 3,
|
|
235
|
+
className: "text-sm"
|
|
236
|
+
}
|
|
237
|
+
) : currentImpact.impactJustification ? /* @__PURE__ */ jsx("p", { className: styles.justificationText(), children: currentImpact.impactJustification }) : /* @__PURE__ */ jsx("p", { className: styles.justificationEmpty(), children: t.noJustification })
|
|
238
|
+
] });
|
|
239
|
+
if (isInline) {
|
|
240
|
+
return /* @__PURE__ */ jsxs("div", { className: styles.wrapper(), children: [
|
|
241
|
+
title && /* @__PURE__ */ jsx("div", { className: styles.inlineHeader(), children: /* @__PURE__ */ jsx(Heading, { level: "h4", className: "text-sm font-medium", children: title }) }),
|
|
242
|
+
impactRows,
|
|
243
|
+
justificationContent
|
|
244
|
+
] });
|
|
245
|
+
}
|
|
152
246
|
return /* @__PURE__ */ jsxs(Card.Root, { className: styles.root(), children: [
|
|
153
247
|
/* @__PURE__ */ jsxs(Card.Header, { className: "flex flex-row items-center justify-between", children: [
|
|
154
248
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -170,78 +264,8 @@ function ImpactCard({
|
|
|
170
264
|
] }))
|
|
171
265
|
] }),
|
|
172
266
|
/* @__PURE__ */ jsxs(Card.Body, { className: "space-y-3", children: [
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
{
|
|
176
|
-
label: t.confidentiality,
|
|
177
|
-
shortLabel: "C",
|
|
178
|
-
value: currentImpact.impactConfidentiality,
|
|
179
|
-
isEditing,
|
|
180
|
-
scale: scaleConfig,
|
|
181
|
-
formatLabel,
|
|
182
|
-
onLevelChange: handleLevelChange("impactConfidentiality")
|
|
183
|
-
}
|
|
184
|
-
),
|
|
185
|
-
/* @__PURE__ */ jsx(
|
|
186
|
-
ImpactItemRow,
|
|
187
|
-
{
|
|
188
|
-
label: t.integrity,
|
|
189
|
-
shortLabel: "I",
|
|
190
|
-
value: currentImpact.impactIntegrity,
|
|
191
|
-
isEditing,
|
|
192
|
-
scale: scaleConfig,
|
|
193
|
-
formatLabel,
|
|
194
|
-
onLevelChange: handleLevelChange("impactIntegrity")
|
|
195
|
-
}
|
|
196
|
-
),
|
|
197
|
-
/* @__PURE__ */ jsx(
|
|
198
|
-
ImpactItemRow,
|
|
199
|
-
{
|
|
200
|
-
label: t.availability,
|
|
201
|
-
shortLabel: "A",
|
|
202
|
-
value: currentImpact.impactAvailability,
|
|
203
|
-
isEditing,
|
|
204
|
-
scale: scaleConfig,
|
|
205
|
-
formatLabel,
|
|
206
|
-
onLevelChange: handleLevelChange("impactAvailability")
|
|
207
|
-
}
|
|
208
|
-
),
|
|
209
|
-
showAuthenticity && /* @__PURE__ */ jsx(
|
|
210
|
-
ImpactItemRow,
|
|
211
|
-
{
|
|
212
|
-
label: t.authenticity,
|
|
213
|
-
shortLabel: "Au",
|
|
214
|
-
value: (_b = currentImpact.impactAuthenticity) != null ? _b : 0,
|
|
215
|
-
isEditing,
|
|
216
|
-
scale: scaleConfig,
|
|
217
|
-
formatLabel,
|
|
218
|
-
onLevelChange: handleLevelChange("impactAuthenticity")
|
|
219
|
-
}
|
|
220
|
-
),
|
|
221
|
-
showJustification && /* @__PURE__ */ jsxs("div", { className: styles.justificationSection(), children: [
|
|
222
|
-
/* @__PURE__ */ jsxs(
|
|
223
|
-
"label",
|
|
224
|
-
{
|
|
225
|
-
htmlFor: "impact-justification",
|
|
226
|
-
className: styles.justificationLabel(),
|
|
227
|
-
children: [
|
|
228
|
-
t.justification,
|
|
229
|
-
highestImpact > 0 && /* @__PURE__ */ jsx("span", { className: styles.justificationHint(), children: justificationHint })
|
|
230
|
-
]
|
|
231
|
-
}
|
|
232
|
-
),
|
|
233
|
-
isEditing ? /* @__PURE__ */ jsx(
|
|
234
|
-
Textarea,
|
|
235
|
-
{
|
|
236
|
-
id: "impact-justification",
|
|
237
|
-
value: currentImpact.impactJustification || "",
|
|
238
|
-
onChange: (e) => handleJustificationChange(e.target.value),
|
|
239
|
-
placeholder: t.justificationPlaceholder,
|
|
240
|
-
rows: 3,
|
|
241
|
-
className: "text-sm"
|
|
242
|
-
}
|
|
243
|
-
) : currentImpact.impactJustification ? /* @__PURE__ */ jsx("p", { className: styles.justificationText(), children: currentImpact.impactJustification }) : /* @__PURE__ */ jsx("p", { className: styles.justificationEmpty(), children: t.noJustification })
|
|
244
|
-
] })
|
|
267
|
+
impactRows,
|
|
268
|
+
justificationContent
|
|
245
269
|
] })
|
|
246
270
|
] });
|
|
247
271
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/common/risk/messages.ts
|
|
4
|
+
import { defineMessages } from "@kopexa/i18n";
|
|
5
|
+
var messages = defineMessages({
|
|
6
|
+
level_unrated: {
|
|
7
|
+
id: "grc.risk.level.unrated",
|
|
8
|
+
defaultMessage: "Not rated"
|
|
9
|
+
},
|
|
10
|
+
level_low: {
|
|
11
|
+
id: "grc.risk.level.low",
|
|
12
|
+
defaultMessage: "Low"
|
|
13
|
+
},
|
|
14
|
+
level_medium: {
|
|
15
|
+
id: "grc.risk.level.medium",
|
|
16
|
+
defaultMessage: "Medium"
|
|
17
|
+
},
|
|
18
|
+
level_high: {
|
|
19
|
+
id: "grc.risk.level.high",
|
|
20
|
+
defaultMessage: "High"
|
|
21
|
+
},
|
|
22
|
+
level_critical: {
|
|
23
|
+
id: "grc.risk.level.critical",
|
|
24
|
+
defaultMessage: "Critical"
|
|
25
|
+
},
|
|
26
|
+
likelihood: {
|
|
27
|
+
id: "grc.risk.likelihood",
|
|
28
|
+
defaultMessage: "Likelihood"
|
|
29
|
+
},
|
|
30
|
+
consequence: {
|
|
31
|
+
id: "grc.risk.consequence",
|
|
32
|
+
defaultMessage: "Consequence"
|
|
33
|
+
},
|
|
34
|
+
rating: {
|
|
35
|
+
id: "grc.risk.rating",
|
|
36
|
+
defaultMessage: "Rating"
|
|
37
|
+
},
|
|
38
|
+
not_rated_hint: {
|
|
39
|
+
id: "grc.risk.not_rated_hint",
|
|
40
|
+
defaultMessage: "Risk has not been assessed yet"
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
messages
|
|
46
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
messages
|
|
4
|
+
} from "./chunk-QS5S6V26.mjs";
|
|
5
|
+
|
|
6
|
+
// src/common/control/mapped-controls.tsx
|
|
7
|
+
import { useSafeIntl } from "@kopexa/i18n";
|
|
8
|
+
import { KRN } from "@kopexa/krn";
|
|
9
|
+
import { Popover, Tooltip } from "@kopexa/sight";
|
|
10
|
+
import { relatedControlChip } from "@kopexa/theme";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
function formatControlKrn(krnString) {
|
|
13
|
+
const parsed = KRN.tryParse(krnString);
|
|
14
|
+
if (!parsed) {
|
|
15
|
+
return { framework: null, controlId: krnString, full: krnString };
|
|
16
|
+
}
|
|
17
|
+
const framework = parsed.tryResourceId("frameworks");
|
|
18
|
+
const control = parsed.tryResourceId("controls");
|
|
19
|
+
if (framework && control) {
|
|
20
|
+
return {
|
|
21
|
+
framework,
|
|
22
|
+
controlId: control,
|
|
23
|
+
full: `${framework}:${control}`
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const basename = parsed.basename();
|
|
27
|
+
return {
|
|
28
|
+
framework: null,
|
|
29
|
+
controlId: basename || krnString,
|
|
30
|
+
full: basename || krnString
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function ControlChip({
|
|
34
|
+
krn,
|
|
35
|
+
size = "md",
|
|
36
|
+
interactive = false,
|
|
37
|
+
onClick,
|
|
38
|
+
className
|
|
39
|
+
}) {
|
|
40
|
+
const styles = relatedControlChip({ size, interactive });
|
|
41
|
+
const { controlId, full } = formatControlKrn(krn);
|
|
42
|
+
const displayId = controlId.toUpperCase();
|
|
43
|
+
const content = /* @__PURE__ */ jsx("span", { className: styles.chipId(), children: displayId });
|
|
44
|
+
const chip = interactive && onClick ? /* @__PURE__ */ jsx(
|
|
45
|
+
"button",
|
|
46
|
+
{
|
|
47
|
+
type: "button",
|
|
48
|
+
className: styles.chip({ className }),
|
|
49
|
+
onClick,
|
|
50
|
+
children: content
|
|
51
|
+
}
|
|
52
|
+
) : /* @__PURE__ */ jsx("span", { className: styles.chip({ className }), children: content });
|
|
53
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: full, children: chip });
|
|
54
|
+
}
|
|
55
|
+
function MappedControls({
|
|
56
|
+
controls,
|
|
57
|
+
maxVisible = 2,
|
|
58
|
+
size = "md",
|
|
59
|
+
interactive = false,
|
|
60
|
+
onControlClick,
|
|
61
|
+
showEmpty = false,
|
|
62
|
+
className,
|
|
63
|
+
...rest
|
|
64
|
+
}) {
|
|
65
|
+
const intl = useSafeIntl();
|
|
66
|
+
const styles = relatedControlChip({ size, interactive });
|
|
67
|
+
if (controls.length === 0) {
|
|
68
|
+
if (!showEmpty) return null;
|
|
69
|
+
return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: intl.formatMessage(messages.no_controls) });
|
|
70
|
+
}
|
|
71
|
+
const visibleControls = controls.slice(0, maxVisible);
|
|
72
|
+
const hiddenCount = controls.length - maxVisible;
|
|
73
|
+
return /* @__PURE__ */ jsxs("div", { className: styles.root({ className }), ...rest, children: [
|
|
74
|
+
visibleControls.map((krn) => /* @__PURE__ */ jsx(
|
|
75
|
+
ControlChip,
|
|
76
|
+
{
|
|
77
|
+
krn,
|
|
78
|
+
size,
|
|
79
|
+
interactive,
|
|
80
|
+
onClick: onControlClick ? () => onControlClick(krn) : void 0
|
|
81
|
+
},
|
|
82
|
+
krn
|
|
83
|
+
)),
|
|
84
|
+
hiddenCount > 0 && /* @__PURE__ */ jsxs(Popover.Root, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { className: styles.overflow(), children: intl.formatMessage(messages.more_controls, {
|
|
86
|
+
count: hiddenCount
|
|
87
|
+
}) }),
|
|
88
|
+
/* @__PURE__ */ jsxs(
|
|
89
|
+
Popover.Content,
|
|
90
|
+
{
|
|
91
|
+
align: "start",
|
|
92
|
+
className: "p-2 max-w-xs",
|
|
93
|
+
showArrow: false,
|
|
94
|
+
children: [
|
|
95
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground mb-2", children: intl.formatMessage(messages.view_all, {
|
|
96
|
+
count: controls.length
|
|
97
|
+
}) }),
|
|
98
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: controls.map((krn) => /* @__PURE__ */ jsx(
|
|
99
|
+
ControlChip,
|
|
100
|
+
{
|
|
101
|
+
krn,
|
|
102
|
+
size,
|
|
103
|
+
interactive,
|
|
104
|
+
onClick: onControlClick ? () => onControlClick(krn) : void 0
|
|
105
|
+
},
|
|
106
|
+
krn
|
|
107
|
+
)) })
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
] })
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export {
|
|
116
|
+
ControlChip,
|
|
117
|
+
MappedControls
|
|
118
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/common/control/messages.ts
|
|
4
|
+
import { defineMessages } from "@kopexa/i18n";
|
|
5
|
+
var messages = defineMessages({
|
|
6
|
+
more_controls: {
|
|
7
|
+
id: "grc.control.mapped.more",
|
|
8
|
+
defaultMessage: "+{count} more"
|
|
9
|
+
},
|
|
10
|
+
view_all: {
|
|
11
|
+
id: "grc.control.mapped.view_all",
|
|
12
|
+
defaultMessage: "View all {count} controls"
|
|
13
|
+
},
|
|
14
|
+
no_controls: {
|
|
15
|
+
id: "grc.control.mapped.no_controls",
|
|
16
|
+
defaultMessage: "No mapped controls"
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
messages
|
|
22
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/common/risk/types.ts
|
|
4
|
+
function getRiskLevelFromRating(rating) {
|
|
5
|
+
if (rating === 0) return "unrated";
|
|
6
|
+
if (rating <= 4) return "low";
|
|
7
|
+
if (rating <= 9) return "medium";
|
|
8
|
+
if (rating <= 16) return "high";
|
|
9
|
+
return "critical";
|
|
10
|
+
}
|
|
11
|
+
function isRatingUnrated(rating) {
|
|
12
|
+
if (!rating) return true;
|
|
13
|
+
return rating.rating === 0 || rating.likelihood === 0 || rating.consequence === 0;
|
|
14
|
+
}
|
|
15
|
+
var riskLevelConfig = {
|
|
16
|
+
unrated: {
|
|
17
|
+
label: "Nicht bewertet",
|
|
18
|
+
bgColor: "bg-muted",
|
|
19
|
+
textColor: "text-muted-foreground",
|
|
20
|
+
iconBgColor: "bg-muted/50",
|
|
21
|
+
iconTextColor: "text-muted-foreground"
|
|
22
|
+
},
|
|
23
|
+
low: {
|
|
24
|
+
label: "Niedrig",
|
|
25
|
+
bgColor: "bg-success",
|
|
26
|
+
textColor: "text-success",
|
|
27
|
+
iconBgColor: "bg-success/10",
|
|
28
|
+
iconTextColor: "text-success"
|
|
29
|
+
},
|
|
30
|
+
medium: {
|
|
31
|
+
label: "Mittel",
|
|
32
|
+
bgColor: "bg-warning",
|
|
33
|
+
textColor: "text-warning",
|
|
34
|
+
iconBgColor: "bg-warning/10",
|
|
35
|
+
iconTextColor: "text-warning"
|
|
36
|
+
},
|
|
37
|
+
high: {
|
|
38
|
+
label: "Hoch",
|
|
39
|
+
bgColor: "bg-orange-500",
|
|
40
|
+
textColor: "text-orange-500",
|
|
41
|
+
iconBgColor: "bg-orange-500/10",
|
|
42
|
+
iconTextColor: "text-orange-500"
|
|
43
|
+
},
|
|
44
|
+
critical: {
|
|
45
|
+
label: "Kritisch",
|
|
46
|
+
bgColor: "bg-destructive",
|
|
47
|
+
textColor: "text-destructive",
|
|
48
|
+
iconBgColor: "bg-destructive/10",
|
|
49
|
+
iconTextColor: "text-destructive"
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
getRiskLevelFromRating,
|
|
55
|
+
isRatingUnrated,
|
|
56
|
+
riskLevelConfig
|
|
57
|
+
};
|