@kartverket/backstage-plugin-risk-scorecard 6.9.7 → 6.10.1

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.
Files changed (37) hide show
  1. package/dist/PluginRoot.esm.js +5 -1
  2. package/dist/PluginRoot.esm.js.map +1 -1
  3. package/dist/components/riScDialog/AppliesToField.esm.js +189 -0
  4. package/dist/components/riScDialog/AppliesToField.esm.js.map +1 -0
  5. package/dist/components/riScDialog/ConfigRiscInfo.esm.js +4 -0
  6. package/dist/components/riScDialog/ConfigRiscInfo.esm.js.map +1 -1
  7. package/dist/components/riScDialog/RiScDialog.esm.js +6 -3
  8. package/dist/components/riScDialog/RiScDialog.esm.js.map +1 -1
  9. package/dist/components/riScDialog/entityRefOptions.esm.js +25 -0
  10. package/dist/components/riScDialog/entityRefOptions.esm.js.map +1 -0
  11. package/dist/components/riScInfo/RiScSelectionCard.esm.js +20 -4
  12. package/dist/components/riScInfo/RiScSelectionCard.esm.js.map +1 -1
  13. package/dist/components/riScInfo/RiScSelectionCard.module.css.esm.js +2 -2
  14. package/dist/components/riScInfo/changeset/RiScAppliesToChange.esm.js +31 -0
  15. package/dist/components/riScInfo/changeset/RiScAppliesToChange.esm.js.map +1 -0
  16. package/dist/components/riScInfo/changeset/RiScChangeSet.esm.js +4 -1
  17. package/dist/components/riScInfo/changeset/RiScChangeSet.esm.js.map +1 -1
  18. package/dist/components/riScPlugin/RiScPlugin.esm.js +22 -3
  19. package/dist/components/riScPlugin/RiScPlugin.esm.js.map +1 -1
  20. package/dist/contexts/RiScContext.esm.js +36 -10
  21. package/dist/contexts/RiScContext.esm.js.map +1 -1
  22. package/dist/plugin.esm.js +7 -0
  23. package/dist/plugin.esm.js.map +1 -1
  24. package/dist/utils/DTOs.esm.js +5 -1
  25. package/dist/utils/DTOs.esm.js.map +1 -1
  26. package/dist/utils/constants.esm.js +1 -1
  27. package/dist/utils/constants.esm.js.map +1 -1
  28. package/dist/utils/featureFlags.esm.js +10 -0
  29. package/dist/utils/featureFlags.esm.js.map +1 -0
  30. package/dist/utils/hooks.esm.js +75 -2
  31. package/dist/utils/hooks.esm.js.map +1 -1
  32. package/dist/utils/translations.esm.js +33 -1
  33. package/dist/utils/translations.esm.js.map +1 -1
  34. package/dist/utils/types.esm.js.map +1 -1
  35. package/dist/utils/utilityfunctions.esm.js +4 -0
  36. package/dist/utils/utilityfunctions.esm.js.map +1 -1
  37. package/package.json +4 -2
@@ -3,6 +3,8 @@ import { Routes, Route } from 'react-router-dom';
3
3
  import { CacheProvider } from '@emotion/react';
4
4
  import createCache from '@emotion/cache';
5
5
  import { useMemo } from 'react';
6
+ import { stringifyEntityRef } from '@backstage/catalog-model';
7
+ import { useEntity } from '@backstage/plugin-catalog-react';
6
8
  import { createTheme, ThemeProvider } from '@mui/material/styles';
7
9
  import { RiScPlugin } from './components/riScPlugin/RiScPlugin.esm.js';
8
10
  import { ScenarioProvider } from './contexts/ScenarioContext.esm.js';
@@ -26,7 +28,9 @@ function MuiThemeBridge({ children }) {
26
28
  return /* @__PURE__ */ jsx(ThemeProvider, { theme, children });
27
29
  }
28
30
  function ProvidedPlugin() {
29
- return /* @__PURE__ */ jsx(CacheProvider, { value: cache, children: /* @__PURE__ */ jsx(MuiThemeBridge, { children: /* @__PURE__ */ jsx(BackstageContextProvider, { children: /* @__PURE__ */ jsx(RiScProvider, { children: /* @__PURE__ */ jsx(DefaultRiScTypesProvider, { children: /* @__PURE__ */ jsx(ScenarioProvider, { children: /* @__PURE__ */ jsx(RiScPlugin, {}) }) }) }) }) }) });
31
+ const { entity } = useEntity();
32
+ const entityKey = stringifyEntityRef(entity);
33
+ return /* @__PURE__ */ jsx(CacheProvider, { value: cache, children: /* @__PURE__ */ jsx(MuiThemeBridge, { children: /* @__PURE__ */ jsx(BackstageContextProvider, { children: /* @__PURE__ */ jsx(RiScProvider, { children: /* @__PURE__ */ jsx(DefaultRiScTypesProvider, { children: /* @__PURE__ */ jsx(ScenarioProvider, { children: /* @__PURE__ */ jsx(RiScPlugin, {}) }) }) }, entityKey) }) }) });
30
34
  }
31
35
  function PluginRoot() {
32
36
  return /* @__PURE__ */ jsxs(Routes, { children: [
@@ -1 +1 @@
1
- {"version":3,"file":"PluginRoot.esm.js","sources":["../src/PluginRoot.tsx"],"sourcesContent":["import { Route, Routes } from 'react-router-dom';\nimport { CacheProvider } from '@emotion/react';\nimport createCache from '@emotion/cache';\nimport { useMemo } from 'react';\nimport { createTheme, ThemeProvider } from '@mui/material/styles';\nimport { RiScPlugin } from './components/riScPlugin/RiScPlugin';\nimport { ScenarioProvider } from './contexts/ScenarioContext';\nimport { riScRouteRef, scenarioRouteRef } from './routes';\nimport { RiScProvider } from './contexts/RiScContext';\nimport 'remixicon/fonts/remixicon.css';\nimport { DefaultRiScTypesProvider } from './contexts/DefaultRiScTypesContext.tsx';\nimport { BackstageContextProvider } from './contexts/BackstageContext.tsx';\nimport { useBackstageThemeMode } from './hooks/useBackstageThemeMode.ts';\n\nconst emotionInsertionPoint = document.createElement('meta');\nemotionInsertionPoint.setAttribute('name', 'emotion-insertion-point');\ndocument.querySelector('head')?.appendChild(emotionInsertionPoint);\n\nconst cache = createCache({\n key: 'css',\n insertionPoint: emotionInsertionPoint,\n});\n\nfunction MuiThemeBridge({ children }: { children: React.ReactNode }) {\n const mode = useBackstageThemeMode();\n const theme = useMemo(() => createTheme({ palette: { mode } }), [mode]);\n return <ThemeProvider theme={theme}>{children}</ThemeProvider>;\n}\n\nfunction ProvidedPlugin() {\n return (\n <CacheProvider value={cache}>\n <MuiThemeBridge>\n <BackstageContextProvider>\n <RiScProvider>\n <DefaultRiScTypesProvider>\n <ScenarioProvider>\n <RiScPlugin />\n </ScenarioProvider>\n </DefaultRiScTypesProvider>\n </RiScProvider>\n </BackstageContextProvider>\n </MuiThemeBridge>\n </CacheProvider>\n );\n}\n\nexport function PluginRoot() {\n return (\n <Routes>\n <Route path=\"/\" element={<ProvidedPlugin />} />\n <Route path={riScRouteRef.path} element={<ProvidedPlugin />} />\n <Route path={scenarioRouteRef.path} element={<ProvidedPlugin />} />\n </Routes>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAcA,MAAM,qBAAA,GAAwB,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC3D,qBAAA,CAAsB,YAAA,CAAa,QAAQ,yBAAyB,CAAA;AACpE,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA,EAAG,WAAA,CAAY,qBAAqB,CAAA;AAEjE,MAAM,QAAQ,WAAA,CAAY;AAAA,EACxB,GAAA,EAAK,KAAA;AAAA,EACL,cAAA,EAAgB;AAClB,CAAC,CAAA;AAED,SAAS,cAAA,CAAe,EAAE,QAAA,EAAS,EAAkC;AACnE,EAAA,MAAM,OAAO,qBAAA,EAAsB;AACnC,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAM,WAAA,CAAY,EAAE,OAAA,EAAS,EAAE,IAAA,EAAK,EAAG,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AACtE,EAAA,uBAAO,GAAA,CAAC,aAAA,EAAA,EAAc,KAAA,EAAe,QAAA,EAAS,CAAA;AAChD;AAEA,SAAS,cAAA,GAAiB;AACxB,EAAA,uBACE,GAAA,CAAC,iBAAc,KAAA,EAAO,KAAA,EACpB,8BAAC,cAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,4BACC,QAAA,kBAAA,GAAA,CAAC,YAAA,EAAA,EACC,8BAAC,wBAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,oBACC,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,GACd,CAAA,EACF,CAAA,EACF,CAAA,EACF,CAAA,EACF,CAAA,EACF,CAAA;AAEJ;AAEO,SAAS,UAAA,GAAa;AAC3B,EAAA,4BACG,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAM,IAAA,EAAK,GAAA,EAAI,OAAA,kBAAS,GAAA,CAAC,kBAAe,CAAA,EAAI,CAAA;AAAA,oBAC7C,GAAA,CAAC,SAAM,IAAA,EAAM,YAAA,CAAa,MAAM,OAAA,kBAAS,GAAA,CAAC,kBAAe,CAAA,EAAI,CAAA;AAAA,oBAC7D,GAAA,CAAC,SAAM,IAAA,EAAM,gBAAA,CAAiB,MAAM,OAAA,kBAAS,GAAA,CAAC,kBAAe,CAAA,EAAI;AAAA,GAAA,EACnE,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"PluginRoot.esm.js","sources":["../src/PluginRoot.tsx"],"sourcesContent":["import { Route, Routes } from 'react-router-dom';\nimport { CacheProvider } from '@emotion/react';\nimport createCache from '@emotion/cache';\nimport { useMemo } from 'react';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { createTheme, ThemeProvider } from '@mui/material/styles';\nimport { RiScPlugin } from './components/riScPlugin/RiScPlugin';\nimport { ScenarioProvider } from './contexts/ScenarioContext';\nimport { riScRouteRef, scenarioRouteRef } from './routes';\nimport { RiScProvider } from './contexts/RiScContext';\nimport 'remixicon/fonts/remixicon.css';\nimport { DefaultRiScTypesProvider } from './contexts/DefaultRiScTypesContext.tsx';\nimport { BackstageContextProvider } from './contexts/BackstageContext.tsx';\nimport { useBackstageThemeMode } from './hooks/useBackstageThemeMode.ts';\n\nconst emotionInsertionPoint = document.createElement('meta');\nemotionInsertionPoint.setAttribute('name', 'emotion-insertion-point');\ndocument.querySelector('head')?.appendChild(emotionInsertionPoint);\n\nconst cache = createCache({\n key: 'css',\n insertionPoint: emotionInsertionPoint,\n});\n\nfunction MuiThemeBridge({ children }: { children: React.ReactNode }) {\n const mode = useBackstageThemeMode();\n const theme = useMemo(() => createTheme({ palette: { mode } }), [mode]);\n return <ThemeProvider theme={theme}>{children}</ThemeProvider>;\n}\n\nfunction ProvidedPlugin() {\n const { entity } = useEntity();\n const entityKey = stringifyEntityRef(entity);\n\n return (\n <CacheProvider value={cache}>\n <MuiThemeBridge>\n <BackstageContextProvider>\n <RiScProvider key={entityKey}>\n <DefaultRiScTypesProvider>\n <ScenarioProvider>\n <RiScPlugin />\n </ScenarioProvider>\n </DefaultRiScTypesProvider>\n </RiScProvider>\n </BackstageContextProvider>\n </MuiThemeBridge>\n </CacheProvider>\n );\n}\n\nexport function PluginRoot() {\n return (\n <Routes>\n <Route path=\"/\" element={<ProvidedPlugin />} />\n <Route path={riScRouteRef.path} element={<ProvidedPlugin />} />\n <Route path={scenarioRouteRef.path} element={<ProvidedPlugin />} />\n </Routes>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAgBA,MAAM,qBAAA,GAAwB,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC3D,qBAAA,CAAsB,YAAA,CAAa,QAAQ,yBAAyB,CAAA;AACpE,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA,EAAG,WAAA,CAAY,qBAAqB,CAAA;AAEjE,MAAM,QAAQ,WAAA,CAAY;AAAA,EACxB,GAAA,EAAK,KAAA;AAAA,EACL,cAAA,EAAgB;AAClB,CAAC,CAAA;AAED,SAAS,cAAA,CAAe,EAAE,QAAA,EAAS,EAAkC;AACnE,EAAA,MAAM,OAAO,qBAAA,EAAsB;AACnC,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAM,WAAA,CAAY,EAAE,OAAA,EAAS,EAAE,IAAA,EAAK,EAAG,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AACtE,EAAA,uBAAO,GAAA,CAAC,aAAA,EAAA,EAAc,KAAA,EAAe,QAAA,EAAS,CAAA;AAChD;AAEA,SAAS,cAAA,GAAiB;AACxB,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,SAAA,GAAY,mBAAmB,MAAM,CAAA;AAE3C,EAAA,uBACE,GAAA,CAAC,iBAAc,KAAA,EAAO,KAAA,EACpB,8BAAC,cAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,wBAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,YAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,4BACC,QAAA,kBAAA,GAAA,CAAC,gBAAA,EAAA,EACC,8BAAC,UAAA,EAAA,EAAW,CAAA,EACd,GACF,CAAA,EAAA,EALiB,SAMnB,CAAA,EACF,CAAA,EACF,CAAA,EACF,CAAA;AAEJ;AAEO,SAAS,UAAA,GAAa;AAC3B,EAAA,4BACG,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAM,IAAA,EAAK,GAAA,EAAI,OAAA,kBAAS,GAAA,CAAC,kBAAe,CAAA,EAAI,CAAA;AAAA,oBAC7C,GAAA,CAAC,SAAM,IAAA,EAAM,YAAA,CAAa,MAAM,OAAA,kBAAS,GAAA,CAAC,kBAAe,CAAA,EAAI,CAAA;AAAA,oBAC7D,GAAA,CAAC,SAAM,IAAA,EAAM,gBAAA,CAAiB,MAAM,OAAA,kBAAS,GAAA,CAAC,kBAAe,CAAA,EAAI;AAAA,GAAA,EACnE,CAAA;AAEJ;;;;"}
@@ -0,0 +1,189 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useApi, configApiRef } from '@backstage/core-plugin-api';
3
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
4
+ import { stringifyEntityRef, RELATION_PART_OF } from '@backstage/catalog-model';
5
+ import { catalogApiRef, useEntity } from '@backstage/plugin-catalog-react';
6
+ import { Alert } from '@backstage/ui';
7
+ import Autocomplete from '@mui/material/Autocomplete';
8
+ import Chip from '@mui/material/Chip';
9
+ import FormControl from '@mui/material/FormControl';
10
+ import FormHelperText from '@mui/material/FormHelperText';
11
+ import FormLabel from '@mui/material/FormLabel';
12
+ import TextField from '@mui/material/TextField';
13
+ import { useState, useEffect } from 'react';
14
+ import { useController } from 'react-hook-form';
15
+ import { pluginRiScTranslationRef } from '../../utils/translations.esm.js';
16
+ import formStyles from '../common/formStyles.module.css.esm.js';
17
+ import { getCurrentSystemRef, entityRefOptionFields } from './entityRefOptions.esm.js';
18
+
19
+ const backstageAppliesToPrefix = "backstage:";
20
+ function AppliesToField({ control }) {
21
+ const { t } = useTranslationRef(pluginRiScTranslationRef);
22
+ const catalogApi = useApi(catalogApiRef);
23
+ const configApi = useApi(configApiRef);
24
+ const includeAllEntities = configApi.getOptionalBoolean(
25
+ "riskScorecard.appliesTo.includeAllEntities"
26
+ ) ?? false;
27
+ const [catalogEntityRefs, setCatalogEntityRefs] = useState([]);
28
+ const [isLoadingOptions, setIsLoadingOptions] = useState(false);
29
+ const { field, fieldState } = useController({
30
+ control,
31
+ name: "content.unencryptedMetadata.appliesTo"
32
+ });
33
+ const { entity } = useEntity();
34
+ const currentEntityRef = stringifyEntityRef(entity);
35
+ const currentPrefixedEntityRef = backstageAppliesToPrefix + currentEntityRef;
36
+ const selectedEntityRefs = field.value ?? [currentPrefixedEntityRef];
37
+ const isMissingCurrentEntityRef = getIsMissingCurrentEntityRef(
38
+ selectedEntityRefs,
39
+ currentPrefixedEntityRef
40
+ );
41
+ const missingEntityRefs = catalogEntityRefs.length > 0 ? getMissingEntityRefs(
42
+ selectedEntityRefs.filter((ref) => ref !== currentPrefixedEntityRef),
43
+ catalogEntityRefs
44
+ ) : [];
45
+ useEffect(() => {
46
+ let cancelled = false;
47
+ const currentSystemRef = getCurrentSystemRef(entity);
48
+ setIsLoadingOptions(true);
49
+ setCatalogEntityRefs([]);
50
+ const sameSystemEntitiesPromise = currentSystemRef ? catalogApi.getEntities({
51
+ fields: entityRefOptionFields,
52
+ filter: {
53
+ [`relations.${RELATION_PART_OF}`]: currentSystemRef
54
+ }
55
+ }).catch(() => ({ items: [] })) : Promise.resolve({ items: [] });
56
+ Promise.all([
57
+ sameSystemEntitiesPromise,
58
+ includeAllEntities ? catalogApi.getEntities({
59
+ fields: entityRefOptionFields
60
+ }) : Promise.resolve({ items: [] })
61
+ ]).then(([sameSystemEntitiesResponse, allEntitiesResponse]) => {
62
+ if (cancelled) {
63
+ return;
64
+ }
65
+ setCatalogEntityRefs(
66
+ Array.from(
67
+ new Set(
68
+ [
69
+ ...sameSystemEntitiesResponse.items,
70
+ ...allEntitiesResponse.items
71
+ ].map(
72
+ (optionEntity) => backstageAppliesToPrefix + stringifyEntityRef(optionEntity)
73
+ )
74
+ )
75
+ )
76
+ );
77
+ }).catch(() => {
78
+ if (!cancelled) {
79
+ setCatalogEntityRefs([]);
80
+ }
81
+ }).finally(() => {
82
+ if (!cancelled) {
83
+ setIsLoadingOptions(false);
84
+ }
85
+ });
86
+ return () => {
87
+ cancelled = true;
88
+ };
89
+ }, [catalogApi, entity, includeAllEntities]);
90
+ function handleChange(_, value) {
91
+ field.onChange(
92
+ ensureNullOrCurrentEntityRefAsHead(value, currentPrefixedEntityRef)
93
+ );
94
+ }
95
+ return /* @__PURE__ */ jsxs(FormControl, { className: formStyles.formControl, children: [
96
+ /* @__PURE__ */ jsx(FormLabel, { className: formStyles.formLabel, children: t("rosDialog.appliesTo") }),
97
+ /* @__PURE__ */ jsx(FormHelperText, { className: formStyles.formHelperText, children: t("rosDialog.appliesToDescription") }),
98
+ /* @__PURE__ */ jsx(
99
+ Autocomplete,
100
+ {
101
+ multiple: true,
102
+ disablePortal: true,
103
+ filterSelectedOptions: true,
104
+ loading: isLoadingOptions,
105
+ options: catalogEntityRefs,
106
+ value: selectedEntityRefs,
107
+ getOptionLabel: formatBackstageAppliesTo,
108
+ isOptionEqualToValue: (option, value) => option === value,
109
+ onChange: handleChange,
110
+ renderValue: (value, getItemProps) => value.map((prefixedEntityRef, index) => {
111
+ const tagProps = getItemProps({ index });
112
+ const { key, onDelete, ...restTagProps } = tagProps;
113
+ const isCurrentEntity = prefixedEntityRef === currentPrefixedEntityRef;
114
+ return /* @__PURE__ */ jsx(
115
+ Chip,
116
+ {
117
+ label: formatBackstageAppliesTo(prefixedEntityRef),
118
+ color: isCurrentEntity ? "primary" : "default",
119
+ variant: isCurrentEntity ? "filled" : "outlined",
120
+ onDelete: isCurrentEntity ? void 0 : onDelete,
121
+ ...restTagProps
122
+ },
123
+ key
124
+ );
125
+ }),
126
+ renderInput: (params) => /* @__PURE__ */ jsx(
127
+ TextField,
128
+ {
129
+ ...params,
130
+ placeholder: t("rosDialog.appliesToPlaceholder")
131
+ }
132
+ ),
133
+ loadingText: t("rosDialog.appliesToLoading"),
134
+ noOptionsText: t("rosDialog.appliesToNoOptions")
135
+ }
136
+ ),
137
+ selectedEntityRefs.length > 1 && /* @__PURE__ */ jsx(FormHelperText, { children: t("rosDialog.appliesToSystemRosHint") }),
138
+ fieldState.isDirty && /* @__PURE__ */ jsx(
139
+ Alert,
140
+ {
141
+ status: "info",
142
+ icon: true,
143
+ description: t("rosDialog.appliesToNightlyRefreshHint")
144
+ }
145
+ ),
146
+ isMissingCurrentEntityRef && /* @__PURE__ */ jsx(
147
+ Alert,
148
+ {
149
+ status: "warning",
150
+ icon: true,
151
+ description: t("rosDialog.appliesToMissingCurrentEntity", {
152
+ entityRef: currentEntityRef
153
+ })
154
+ }
155
+ ),
156
+ missingEntityRefs.length > 0 && /* @__PURE__ */ jsx(
157
+ Alert,
158
+ {
159
+ status: "warning",
160
+ icon: true,
161
+ description: t("rosDialog.appliesToMissingEntities", {
162
+ entityRefs: missingEntityRefs.map(formatBackstageAppliesTo).join(", ")
163
+ })
164
+ }
165
+ )
166
+ ] });
167
+ }
168
+ function ensureNullOrCurrentEntityRefAsHead(entityRefs, currentEntityRef) {
169
+ const currentValue = [
170
+ currentEntityRef,
171
+ ...new Set(entityRefs.filter((it) => it !== currentEntityRef))
172
+ ];
173
+ if (currentValue.length === 1) {
174
+ return null;
175
+ }
176
+ return currentValue;
177
+ }
178
+ function formatBackstageAppliesTo(appliesTo) {
179
+ return appliesTo.startsWith(backstageAppliesToPrefix) ? appliesTo.slice(backstageAppliesToPrefix.length) : appliesTo;
180
+ }
181
+ function getIsMissingCurrentEntityRef(entityRefs, currentEntityRef) {
182
+ return entityRefs.length > 0 && !entityRefs.includes(currentEntityRef);
183
+ }
184
+ function getMissingEntityRefs(entityRefs, catalogEntityRefs) {
185
+ return entityRefs.filter((entityRef) => !catalogEntityRefs.includes(entityRef));
186
+ }
187
+
188
+ export { AppliesToField };
189
+ //# sourceMappingURL=AppliesToField.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppliesToField.esm.js","sources":["../../../src/components/riScDialog/AppliesToField.tsx"],"sourcesContent":["import { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { RELATION_PART_OF, stringifyEntityRef } from '@backstage/catalog-model';\nimport { catalogApiRef, useEntity } from '@backstage/plugin-catalog-react';\nimport { Alert } from '@backstage/ui';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Chip from '@mui/material/Chip';\nimport FormControl from '@mui/material/FormControl';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport FormLabel from '@mui/material/FormLabel';\nimport TextField from '@mui/material/TextField';\nimport { useEffect, useState } from 'react';\nimport { Control, useController } from 'react-hook-form';\nimport { pluginRiScTranslationRef } from '../../utils/translations';\nimport { RiScWithMetadata } from '../../utils/types';\nimport formStyles from '../common/formStyles.module.css';\nimport { entityRefOptionFields, getCurrentSystemRef } from './entityRefOptions';\n\nconst backstageAppliesToPrefix = 'backstage:';\n\ntype AppliesToFieldProps = {\n control: Control<RiScWithMetadata>;\n};\n\nexport function AppliesToField({ control }: AppliesToFieldProps) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n const catalogApi = useApi(catalogApiRef);\n const configApi = useApi(configApiRef);\n const includeAllEntities =\n configApi.getOptionalBoolean(\n 'riskScorecard.appliesTo.includeAllEntities',\n ) ?? false;\n const [catalogEntityRefs, setCatalogEntityRefs] = useState<string[]>([]);\n const [isLoadingOptions, setIsLoadingOptions] = useState(false);\n const { field, fieldState } = useController({\n control,\n name: 'content.unencryptedMetadata.appliesTo',\n });\n const { entity } = useEntity();\n const currentEntityRef = stringifyEntityRef(entity);\n const currentPrefixedEntityRef = backstageAppliesToPrefix + currentEntityRef;\n // Ensure that it always looks as if currentRef is saved, but we only save it if at least two refs are selected\n const selectedEntityRefs = field.value ?? [currentPrefixedEntityRef];\n const isMissingCurrentEntityRef = getIsMissingCurrentEntityRef(\n selectedEntityRefs,\n currentPrefixedEntityRef,\n );\n // Avoid missing-entity warnings until catalog refs have loaded. On an entity\n // page, a successful fetch should at least contain the current entity.\n const missingEntityRefs =\n catalogEntityRefs.length > 0\n ? getMissingEntityRefs(\n selectedEntityRefs.filter(ref => ref !== currentPrefixedEntityRef),\n catalogEntityRefs,\n )\n : [];\n\n useEffect(() => {\n let cancelled = false;\n const currentSystemRef = getCurrentSystemRef(entity);\n setIsLoadingOptions(true);\n setCatalogEntityRefs([]);\n\n const sameSystemEntitiesPromise = currentSystemRef\n ? catalogApi\n .getEntities({\n fields: entityRefOptionFields,\n filter: {\n [`relations.${RELATION_PART_OF}`]: currentSystemRef,\n },\n })\n .catch(() => ({ items: [] }))\n : Promise.resolve({ items: [] });\n\n Promise.all([\n sameSystemEntitiesPromise,\n includeAllEntities\n ? catalogApi.getEntities({\n fields: entityRefOptionFields,\n })\n : Promise.resolve({ items: [] }),\n ])\n .then(([sameSystemEntitiesResponse, allEntitiesResponse]) => {\n if (cancelled) {\n return;\n }\n\n setCatalogEntityRefs(\n Array.from(\n new Set(\n [\n ...sameSystemEntitiesResponse.items,\n ...allEntitiesResponse.items,\n ].map(\n optionEntity =>\n backstageAppliesToPrefix + stringifyEntityRef(optionEntity),\n ),\n ),\n ),\n );\n })\n .catch(() => {\n if (!cancelled) {\n setCatalogEntityRefs([]);\n }\n })\n .finally(() => {\n if (!cancelled) {\n setIsLoadingOptions(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [catalogApi, entity, includeAllEntities]);\n\n function handleChange(_: unknown, value: string[]) {\n field.onChange(\n ensureNullOrCurrentEntityRefAsHead(value, currentPrefixedEntityRef),\n );\n }\n\n return (\n <FormControl className={formStyles.formControl}>\n <FormLabel className={formStyles.formLabel}>\n {t('rosDialog.appliesTo')}\n </FormLabel>\n <FormHelperText className={formStyles.formHelperText}>\n {t('rosDialog.appliesToDescription')}\n </FormHelperText>\n <Autocomplete<string, true, false, false>\n multiple\n disablePortal\n filterSelectedOptions\n loading={isLoadingOptions}\n options={catalogEntityRefs}\n value={selectedEntityRefs}\n getOptionLabel={formatBackstageAppliesTo}\n isOptionEqualToValue={(option, value) => option === value}\n onChange={handleChange}\n renderValue={(value, getItemProps) =>\n value.map((prefixedEntityRef, index) => {\n const tagProps = getItemProps({ index });\n const { key, onDelete, ...restTagProps } = tagProps;\n const isCurrentEntity =\n prefixedEntityRef === currentPrefixedEntityRef;\n\n return (\n <Chip\n key={key}\n label={formatBackstageAppliesTo(prefixedEntityRef)}\n color={isCurrentEntity ? 'primary' : 'default'}\n variant={isCurrentEntity ? 'filled' : 'outlined'}\n onDelete={isCurrentEntity ? undefined : onDelete}\n {...restTagProps}\n />\n );\n })\n }\n renderInput={params => (\n <TextField\n {...params}\n placeholder={t('rosDialog.appliesToPlaceholder')}\n />\n )}\n loadingText={t('rosDialog.appliesToLoading')}\n noOptionsText={t('rosDialog.appliesToNoOptions')}\n />\n {selectedEntityRefs.length > 1 && (\n <FormHelperText>{t('rosDialog.appliesToSystemRosHint')}</FormHelperText>\n )}\n {fieldState.isDirty && (\n <Alert\n status=\"info\"\n icon\n description={t('rosDialog.appliesToNightlyRefreshHint')}\n />\n )}\n {isMissingCurrentEntityRef && (\n <Alert\n status=\"warning\"\n icon\n description={t('rosDialog.appliesToMissingCurrentEntity', {\n entityRef: currentEntityRef,\n })}\n />\n )}\n {missingEntityRefs.length > 0 && (\n <Alert\n status=\"warning\"\n icon\n description={t('rosDialog.appliesToMissingEntities', {\n entityRefs: missingEntityRefs\n .map(formatBackstageAppliesTo)\n .join(', '),\n })}\n />\n )}\n </FormControl>\n );\n}\n\nfunction ensureNullOrCurrentEntityRefAsHead(\n entityRefs: string[],\n currentEntityRef: string,\n): string[] | null {\n const currentValue = [\n currentEntityRef,\n ...new Set(entityRefs.filter(it => it !== currentEntityRef)),\n ];\n if (currentValue.length === 1) {\n // React Hook Form does not support undefined field values; DTO serialization normalizes null by omitting appliesTo.\n return null;\n }\n\n return currentValue;\n}\n\nfunction formatBackstageAppliesTo(appliesTo: string): string {\n return appliesTo.startsWith(backstageAppliesToPrefix)\n ? appliesTo.slice(backstageAppliesToPrefix.length)\n : appliesTo;\n}\n\nfunction getIsMissingCurrentEntityRef(\n entityRefs: string[],\n currentEntityRef: string,\n): boolean {\n return entityRefs.length > 0 && !entityRefs.includes(currentEntityRef);\n}\n\nfunction getMissingEntityRefs(\n entityRefs: string[],\n catalogEntityRefs: string[],\n): string[] {\n return entityRefs.filter(entityRef => !catalogEntityRefs.includes(entityRef));\n}\n"],"names":[],"mappings":"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"}
@@ -4,9 +4,12 @@ import { Input } from '../common/Input.esm.js';
4
4
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
5
5
  import { pluginRiScTranslationRef } from '../../utils/translations.esm.js';
6
6
  import { Flex } from '@backstage/ui';
7
+ import { AppliesToField } from './AppliesToField.esm.js';
8
+ import { useSystemRiScsFeatureFlag } from '../../utils/featureFlags.esm.js';
7
9
 
8
10
  function ConfigRiscInfo(props) {
9
11
  const { t } = useTranslationRef(pluginRiScTranslationRef);
12
+ const isSystemRiScsEnabled = useSystemRiScsFeatureFlag();
10
13
  const currentScope = props.watch("content.scope");
11
14
  return /* @__PURE__ */ jsxs(Flex, { gap: "16px", direction: "column", px: "1px", children: [
12
15
  /* @__PURE__ */ jsx(
@@ -19,6 +22,7 @@ function ConfigRiscInfo(props) {
19
22
  helperText: props.errors?.content?.title && t("rosDialog.titleError")
20
23
  }
21
24
  ),
25
+ isSystemRiScsEnabled && /* @__PURE__ */ jsx(AppliesToField, { control: props.control }),
22
26
  /* @__PURE__ */ jsx(
23
27
  MarkdownInput,
24
28
  {
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigRiscInfo.esm.js","sources":["../../../src/components/riScDialog/ConfigRiscInfo.tsx"],"sourcesContent":["import { MarkdownInput } from '../common/MarkdownInput';\nimport { Input } from '../common/Input';\nimport {\n UseFormRegister,\n UseFormSetValue,\n UseFormWatch,\n} from 'react-hook-form';\nimport { RiScWithMetadata } from '../../utils/types';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { pluginRiScTranslationRef } from '../../utils/translations';\nimport { FieldErrors } from 'react-hook-form';\nimport { Flex } from '@backstage/ui';\n\ninterface ConfigRiscInfoProps {\n register: UseFormRegister<RiScWithMetadata>;\n errors: FieldErrors<RiScWithMetadata>;\n setValue: UseFormSetValue<RiScWithMetadata>;\n watch: UseFormWatch<RiScWithMetadata>;\n}\n\nfunction ConfigRiscInfo(props: ConfigRiscInfoProps) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n const currentScope = props.watch('content.scope');\n return (\n <Flex gap=\"16px\" direction=\"column\" px=\"1px\">\n <Input\n required\n {...props.register('content.title', { required: true })}\n error={props.errors?.content?.title !== undefined}\n label={t('dictionary.title')}\n helperText={props.errors?.content?.title && t('rosDialog.titleError')}\n />\n <MarkdownInput\n {...props.register('content.scope')}\n value={currentScope}\n label={t('dictionary.scope')}\n sublabel={t('rosDialog.scopeDescription')}\n error={props.errors?.content?.scope !== undefined}\n minRows={8}\n onMarkdownChange={value => props.setValue('content.scope', value)}\n />\n </Flex>\n );\n}\n\nexport default ConfigRiscInfo;\n"],"names":[],"mappings":";;;;;;;AAoBA,SAAS,eAAe,KAAA,EAA4B;AAClD,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,wBAAwB,CAAA;AACxD,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,eAAe,CAAA;AAChD,EAAA,4BACG,IAAA,EAAA,EAAK,GAAA,EAAI,QAAO,SAAA,EAAU,QAAA,EAAS,IAAG,KAAA,EACrC,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,QAAA,EAAQ,IAAA;AAAA,QACP,GAAG,KAAA,CAAM,QAAA,CAAS,iBAAiB,EAAE,QAAA,EAAU,MAAM,CAAA;AAAA,QACtD,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,KAAA,KAAU,MAAA;AAAA,QACxC,KAAA,EAAO,EAAE,kBAAkB,CAAA;AAAA,QAC3B,YAAY,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,KAAA,IAAS,EAAE,sBAAsB;AAAA;AAAA,KACtE;AAAA,oBACA,GAAA;AAAA,MAAC,aAAA;AAAA,MAAA;AAAA,QACE,GAAG,KAAA,CAAM,QAAA,CAAS,eAAe,CAAA;AAAA,QAClC,KAAA,EAAO,YAAA;AAAA,QACP,KAAA,EAAO,EAAE,kBAAkB,CAAA;AAAA,QAC3B,QAAA,EAAU,EAAE,4BAA4B,CAAA;AAAA,QACxC,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,KAAA,KAAU,MAAA;AAAA,QACxC,OAAA,EAAS,CAAA;AAAA,QACT,gBAAA,EAAkB,CAAA,KAAA,KAAS,KAAA,CAAM,QAAA,CAAS,iBAAiB,KAAK;AAAA;AAAA;AAClE,GAAA,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"ConfigRiscInfo.esm.js","sources":["../../../src/components/riScDialog/ConfigRiscInfo.tsx"],"sourcesContent":["import { MarkdownInput } from '../common/MarkdownInput';\nimport { Input } from '../common/Input';\nimport {\n Control,\n UseFormRegister,\n UseFormSetValue,\n UseFormWatch,\n} from 'react-hook-form';\nimport { RiScWithMetadata } from '../../utils/types';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { pluginRiScTranslationRef } from '../../utils/translations';\nimport { FieldErrors } from 'react-hook-form';\nimport { Flex } from '@backstage/ui';\nimport { AppliesToField } from './AppliesToField';\nimport { useSystemRiScsFeatureFlag } from '../../utils/featureFlags';\n\ninterface ConfigRiscInfoProps {\n register: UseFormRegister<RiScWithMetadata>;\n errors: FieldErrors<RiScWithMetadata>;\n setValue: UseFormSetValue<RiScWithMetadata>;\n watch: UseFormWatch<RiScWithMetadata>;\n control: Control<RiScWithMetadata>;\n}\n\nfunction ConfigRiscInfo(props: ConfigRiscInfoProps) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n const isSystemRiScsEnabled = useSystemRiScsFeatureFlag();\n const currentScope = props.watch('content.scope');\n\n return (\n <Flex gap=\"16px\" direction=\"column\" px=\"1px\">\n <Input\n required\n {...props.register('content.title', { required: true })}\n error={props.errors?.content?.title !== undefined}\n label={t('dictionary.title')}\n helperText={props.errors?.content?.title && t('rosDialog.titleError')}\n />\n {isSystemRiScsEnabled && <AppliesToField control={props.control} />}\n <MarkdownInput\n {...props.register('content.scope')}\n value={currentScope}\n label={t('dictionary.scope')}\n sublabel={t('rosDialog.scopeDescription')}\n error={props.errors?.content?.scope !== undefined}\n minRows={8}\n onMarkdownChange={value => props.setValue('content.scope', value)}\n />\n </Flex>\n );\n}\n\nexport default ConfigRiscInfo;\n"],"names":[],"mappings":";;;;;;;;;AAwBA,SAAS,eAAe,KAAA,EAA4B;AAClD,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,wBAAwB,CAAA;AACxD,EAAA,MAAM,uBAAuB,yBAAA,EAA0B;AACvD,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,eAAe,CAAA;AAEhD,EAAA,4BACG,IAAA,EAAA,EAAK,GAAA,EAAI,QAAO,SAAA,EAAU,QAAA,EAAS,IAAG,KAAA,EACrC,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,QAAA,EAAQ,IAAA;AAAA,QACP,GAAG,KAAA,CAAM,QAAA,CAAS,iBAAiB,EAAE,QAAA,EAAU,MAAM,CAAA;AAAA,QACtD,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,KAAA,KAAU,MAAA;AAAA,QACxC,KAAA,EAAO,EAAE,kBAAkB,CAAA;AAAA,QAC3B,YAAY,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,KAAA,IAAS,EAAE,sBAAsB;AAAA;AAAA,KACtE;AAAA,IACC,oBAAA,oBAAwB,GAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAS,MAAM,OAAA,EAAS,CAAA;AAAA,oBACjE,GAAA;AAAA,MAAC,aAAA;AAAA,MAAA;AAAA,QACE,GAAG,KAAA,CAAM,QAAA,CAAS,eAAe,CAAA;AAAA,QAClC,KAAA,EAAO,YAAA;AAAA,QACP,KAAA,EAAO,EAAE,kBAAkB,CAAA;AAAA,QAC3B,QAAA,EAAU,EAAE,4BAA4B,CAAA;AAAA,QACxC,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,KAAA,KAAU,MAAA;AAAA,QACxC,OAAA,EAAS,CAAA;AAAA,QACT,gBAAA,EAAkB,CAAA,KAAA,KAAS,KAAA,CAAM,QAAA,CAAS,iBAAiB,KAAK;AAAA;AAAA;AAClE,GAAA,EACF,CAAA;AAEJ;;;;"}
@@ -52,7 +52,8 @@ function RiScDialog({
52
52
  handleSubmit,
53
53
  watch,
54
54
  formState: { errors },
55
- setValue
55
+ setValue,
56
+ control
56
57
  } = useForm({
57
58
  defaultValues: dialogState === 2 /* EditRiscInfo */ || dialogState === 4 /* EditEncryption */ ? selectedRiSc : {
58
59
  content: emptyRiSc(),
@@ -164,7 +165,8 @@ function RiScDialog({
164
165
  register,
165
166
  errors,
166
167
  setValue,
167
- watch
168
+ watch,
169
+ control
168
170
  }
169
171
  ),
170
172
  activeStep === 2 && /* @__PURE__ */ jsx(
@@ -230,7 +232,8 @@ function RiScDialog({
230
232
  register,
231
233
  errors,
232
234
  setValue,
233
- watch
235
+ watch,
236
+ control
234
237
  }
235
238
  ),
236
239
  /* @__PURE__ */ jsxs(Flex, { justify: "between", pt: "16px", children: [
@@ -1 +1 @@
1
- {"version":3,"file":"RiScDialog.esm.js","sources":["../../../src/components/riScDialog/RiScDialog.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { RiScWithMetadata } from '../../utils/types';\nimport { emptyRiSc, isDeeplyEqual } from '../../utils/utilityfunctions';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { pluginRiScTranslationRef } from '../../utils/translations';\nimport { useRiScs } from '../../contexts/RiScContext';\nimport { useForm } from 'react-hook-form';\nimport { Step, StepLabel, Stepper } from '@mui/material';\nimport ConfigEncryptionDialog from './ConfigEncryptionDialog';\nimport ConfigRiscInfo from './ConfigRiscInfo';\nimport ConfigInitialRisc from './ConfigInitialRisc';\nimport { Flex, Button, Text } from '@backstage/ui';\nimport styles from './RiScDialog.module.css';\nimport { useDefaultRiScTypeDescriptors } from '../../contexts/DefaultRiScTypesContext.tsx';\nimport DialogComponent from '../dialog/DialogComponent.tsx';\n\nexport enum RiScDialogStates {\n Closed = 0,\n Create = 1,\n EditRiscInfo = 2,\n SelectInitialRisc = 3,\n EditEncryption = 4,\n Delete = 5,\n}\n\ninterface RiScDialogProps {\n onClose: () => void;\n dialogState: RiScDialogStates;\n onDelete: () => void;\n}\n\nfunction RiScStepper({ activeStep }: { activeStep: number }) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n\n const steps = [\n t('rosDialog.initialRiscTitle'),\n t('rosDialog.stepRiscDetails'),\n t('rosDialog.stepEncryption'),\n ];\n return (\n <Stepper activeStep={activeStep} alternativeLabel>\n {steps.map(label => (\n <Step key={label}>\n <StepLabel>\n <Text>{label}</Text>\n </StepLabel>\n </Step>\n ))}\n </Stepper>\n );\n}\n\nexport function RiScDialog({\n onClose,\n dialogState,\n onDelete,\n}: RiScDialogProps) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n\n const {\n selectedRiSc,\n riScs,\n selectRiSc,\n createNewRiSc,\n deleteRiSc,\n updateRiSc,\n gcpCryptoKeys,\n } = useRiScs();\n const {\n register,\n handleSubmit,\n watch,\n formState: { errors },\n setValue,\n } = useForm<RiScWithMetadata>({\n defaultValues:\n dialogState === RiScDialogStates.EditRiscInfo ||\n dialogState === RiScDialogStates.EditEncryption\n ? selectedRiSc!\n : {\n content: emptyRiSc(),\n sopsConfig: {\n shamir_threshold: 2,\n },\n },\n mode: 'onBlur',\n });\n\n const [activeStep, setActiveStep] = useState(0);\n\n const [switchOn, setSwitchOn] = useState(false);\n\n const { riScSelectedByDefault } = useDefaultRiScTypeDescriptors();\n const [selectedRiScId, setSelectedRiScId] = useState<string | undefined>(\n riScSelectedByDefault?.id,\n );\n useEffect(() => {\n setSelectedRiScId(riScSelectedByDefault?.id);\n }, [riScSelectedByDefault]);\n\n const handleNext = handleSubmit(\n () => {\n if (activeStep === 0) {\n setActiveStep(1);\n }\n if (activeStep === 1) {\n setActiveStep(2);\n }\n },\n // Continue to step 1 even if there are errors, as long as there are no errors in step 0 (the content)\n validationErrors => {\n if (validationErrors.content === undefined) {\n if (activeStep === 0) setActiveStep(1);\n if (activeStep === 1) setActiveStep(2);\n }\n },\n );\n\n function handleBack() {\n if (activeStep === 1) setActiveStep(0);\n if (activeStep === 2) setActiveStep(1);\n }\n\n const handleFinish = handleSubmit((data: RiScWithMetadata) => {\n if (dialogState === RiScDialogStates.Create) {\n createNewRiSc(data, switchOn, selectedRiScId);\n } else if (dialogState === RiScDialogStates.Delete) {\n deleteRiSc(() =>\n selectRiSc(riScs && riScs.length > 0 ? riScs[0].id : ''),\n );\n } else {\n // Do manual comparison of contents, as the sopsConfig field contains many values from the backend that are not\n // used or set by the frontend.\n // Check if the additional Age keys are equal, using the single important field, `recipient`\n const areAgeKeysEqual = isDeeplyEqual(\n data.sopsConfig.age?.map(age => age.recipient).sort(),\n selectedRiSc?.sopsConfig.age?.map(age => age.recipient).sort(),\n );\n\n // Check if the GCP keys are equal, using the two important fields, `resource_id` and `created_at`.\n // Comparison uses dictionaries, where resource ids are keys and created at dates are values\n const areGCPKeysEqual = isDeeplyEqual(\n Object.fromEntries(\n data.sopsConfig.gcp_kms?.map(key => [\n key.resource_id,\n key.created_at,\n ]) ?? [],\n ),\n Object.fromEntries(\n selectedRiSc?.sopsConfig.gcp_kms?.map(key => [\n key.resource_id,\n key.created_at,\n ]) ?? [],\n ),\n );\n\n // Only update the risc if it has changed\n if (\n !isDeeplyEqual(data, selectedRiSc, ['sopsConfig']) ||\n !areGCPKeysEqual ||\n !areAgeKeysEqual\n ) {\n updateRiSc(data);\n }\n }\n onClose();\n });\n\n if (dialogState === RiScDialogStates.Create) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('rosDialog.titleNew')}\n className={styles.createRiscDialog}\n >\n <RiScStepper activeStep={activeStep} />\n <Text\n as=\"h2\"\n variant=\"title-x-small\"\n weight=\"bold\"\n className={styles.subtitle}\n >\n {activeStep === 0 && t('rosDialog.initialRiscTitle')}\n {activeStep === 1 && t('rosDialog.titleAndScope')}\n {activeStep === 2 && t('rosDialog.stepEncryption')}\n </Text>\n {activeStep === 0 && (\n <ConfigInitialRisc\n switchOn={switchOn}\n setSwitchOn={setSwitchOn}\n setValue={setValue}\n selectedRiScId={selectedRiScId}\n setSelectedRiScId={setSelectedRiScId}\n />\n )}\n {activeStep === 1 && (\n <ConfigRiscInfo\n register={register}\n errors={errors}\n setValue={setValue}\n watch={watch}\n />\n )}\n {activeStep === 2 && (\n <ConfigEncryptionDialog\n gcpCryptoKeys={gcpCryptoKeys}\n setValue={setValue}\n state={dialogState}\n register={register}\n errors={errors}\n />\n )}\n <Flex pt=\"16px\" justify=\"between\">\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Flex>\n <Button\n size=\"medium\"\n variant=\"secondary\"\n isDisabled={activeStep === 0}\n onClick={handleBack}\n >\n {t('dictionary.previous')}\n </Button>\n {activeStep < 2 ? (\n <Button size=\"medium\" variant=\"primary\" onClick={handleNext}>\n {t('dictionary.next')}\n </Button>\n ) : (\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.save')}\n </Button>\n )}\n </Flex>\n </Flex>\n </DialogComponent>\n );\n }\n\n if (dialogState === RiScDialogStates.Delete) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('deleteDialog.title')}\n className={styles.createRiscDialog}\n >\n <Flex direction=\"column\">\n {t('deleteDialog.confirmationMessage')}\n <Flex justify=\"between\" pt=\"16px\">\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.delete')}\n </Button>\n </Flex>\n </Flex>\n </DialogComponent>\n );\n }\n\n if (dialogState === RiScDialogStates.EditRiscInfo) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('rosDialog.titleEdit')}\n className={styles.createRiscDialog}\n >\n <ConfigRiscInfo\n register={register}\n errors={errors}\n setValue={setValue}\n watch={watch}\n />\n <Flex justify=\"between\" pt=\"16px\">\n <Button\n size=\"medium\"\n variant=\"tertiary\"\n onClick={onDelete}\n className={styles.deleteButton}\n >\n <i className={`ri-delete-bin-line ${styles.deleteButtonIcon}`} />\n {t('contentHeader.deleteButton')}\n </Button>\n <Flex>\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.save')}\n </Button>\n </Flex>\n </Flex>\n </DialogComponent>\n );\n }\n\n if (dialogState === RiScDialogStates.EditEncryption) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('rosDialog.editEncryption')}\n className={styles.createRiscDialog}\n >\n <ConfigEncryptionDialog\n gcpCryptoKeys={gcpCryptoKeys}\n sopsData={selectedRiSc?.sopsConfig}\n setValue={setValue}\n state={dialogState}\n register={register}\n errors={errors}\n />\n <Flex justify=\"between\" pt=\"16px\">\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.save')}\n </Button>\n </Flex>\n </DialogComponent>\n );\n }\n\n return null;\n}\n"],"names":["RiScDialogStates","styles"],"mappings":"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"}
1
+ {"version":3,"file":"RiScDialog.esm.js","sources":["../../../src/components/riScDialog/RiScDialog.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { RiScWithMetadata } from '../../utils/types';\nimport { emptyRiSc, isDeeplyEqual } from '../../utils/utilityfunctions';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { pluginRiScTranslationRef } from '../../utils/translations';\nimport { useRiScs } from '../../contexts/RiScContext';\nimport { useForm } from 'react-hook-form';\nimport { Step, StepLabel, Stepper } from '@mui/material';\nimport ConfigEncryptionDialog from './ConfigEncryptionDialog';\nimport ConfigRiscInfo from './ConfigRiscInfo';\nimport ConfigInitialRisc from './ConfigInitialRisc';\nimport { Flex, Button, Text } from '@backstage/ui';\nimport styles from './RiScDialog.module.css';\nimport { useDefaultRiScTypeDescriptors } from '../../contexts/DefaultRiScTypesContext.tsx';\nimport DialogComponent from '../dialog/DialogComponent.tsx';\n\nexport enum RiScDialogStates {\n Closed = 0,\n Create = 1,\n EditRiscInfo = 2,\n SelectInitialRisc = 3,\n EditEncryption = 4,\n Delete = 5,\n}\n\ninterface RiScDialogProps {\n onClose: () => void;\n dialogState: RiScDialogStates;\n onDelete: () => void;\n}\n\nfunction RiScStepper({ activeStep }: { activeStep: number }) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n\n const steps = [\n t('rosDialog.initialRiscTitle'),\n t('rosDialog.stepRiscDetails'),\n t('rosDialog.stepEncryption'),\n ];\n return (\n <Stepper activeStep={activeStep} alternativeLabel>\n {steps.map(label => (\n <Step key={label}>\n <StepLabel>\n <Text>{label}</Text>\n </StepLabel>\n </Step>\n ))}\n </Stepper>\n );\n}\n\nexport function RiScDialog({\n onClose,\n dialogState,\n onDelete,\n}: RiScDialogProps) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n\n const {\n selectedRiSc,\n riScs,\n selectRiSc,\n createNewRiSc,\n deleteRiSc,\n updateRiSc,\n gcpCryptoKeys,\n } = useRiScs();\n const {\n register,\n handleSubmit,\n watch,\n formState: { errors },\n setValue,\n control,\n } = useForm<RiScWithMetadata>({\n defaultValues:\n dialogState === RiScDialogStates.EditRiscInfo ||\n dialogState === RiScDialogStates.EditEncryption\n ? selectedRiSc!\n : {\n content: emptyRiSc(),\n sopsConfig: {\n shamir_threshold: 2,\n },\n },\n mode: 'onBlur',\n });\n\n const [activeStep, setActiveStep] = useState(0);\n\n const [switchOn, setSwitchOn] = useState(false);\n\n const { riScSelectedByDefault } = useDefaultRiScTypeDescriptors();\n const [selectedRiScId, setSelectedRiScId] = useState<string | undefined>(\n riScSelectedByDefault?.id,\n );\n useEffect(() => {\n setSelectedRiScId(riScSelectedByDefault?.id);\n }, [riScSelectedByDefault]);\n\n const handleNext = handleSubmit(\n () => {\n if (activeStep === 0) {\n setActiveStep(1);\n }\n if (activeStep === 1) {\n setActiveStep(2);\n }\n },\n // Continue to step 1 even if there are errors, as long as there are no errors in step 0 (the content)\n validationErrors => {\n if (validationErrors.content === undefined) {\n if (activeStep === 0) setActiveStep(1);\n if (activeStep === 1) setActiveStep(2);\n }\n },\n );\n\n function handleBack() {\n if (activeStep === 1) setActiveStep(0);\n if (activeStep === 2) setActiveStep(1);\n }\n\n const handleFinish = handleSubmit((data: RiScWithMetadata) => {\n if (dialogState === RiScDialogStates.Create) {\n createNewRiSc(data, switchOn, selectedRiScId);\n } else if (dialogState === RiScDialogStates.Delete) {\n deleteRiSc(() =>\n selectRiSc(riScs && riScs.length > 0 ? riScs[0].id : ''),\n );\n } else {\n // Do manual comparison of contents, as the sopsConfig field contains many values from the backend that are not\n // used or set by the frontend.\n // Check if the additional Age keys are equal, using the single important field, `recipient`\n const areAgeKeysEqual = isDeeplyEqual(\n data.sopsConfig.age?.map(age => age.recipient).sort(),\n selectedRiSc?.sopsConfig.age?.map(age => age.recipient).sort(),\n );\n\n // Check if the GCP keys are equal, using the two important fields, `resource_id` and `created_at`.\n // Comparison uses dictionaries, where resource ids are keys and created at dates are values\n const areGCPKeysEqual = isDeeplyEqual(\n Object.fromEntries(\n data.sopsConfig.gcp_kms?.map(key => [\n key.resource_id,\n key.created_at,\n ]) ?? [],\n ),\n Object.fromEntries(\n selectedRiSc?.sopsConfig.gcp_kms?.map(key => [\n key.resource_id,\n key.created_at,\n ]) ?? [],\n ),\n );\n\n // Only update the risc if it has changed\n if (\n !isDeeplyEqual(data, selectedRiSc, ['sopsConfig']) ||\n !areGCPKeysEqual ||\n !areAgeKeysEqual\n ) {\n updateRiSc(data);\n }\n }\n onClose();\n });\n\n if (dialogState === RiScDialogStates.Create) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('rosDialog.titleNew')}\n className={styles.createRiscDialog}\n >\n <RiScStepper activeStep={activeStep} />\n <Text\n as=\"h2\"\n variant=\"title-x-small\"\n weight=\"bold\"\n className={styles.subtitle}\n >\n {activeStep === 0 && t('rosDialog.initialRiscTitle')}\n {activeStep === 1 && t('rosDialog.titleAndScope')}\n {activeStep === 2 && t('rosDialog.stepEncryption')}\n </Text>\n {activeStep === 0 && (\n <ConfigInitialRisc\n switchOn={switchOn}\n setSwitchOn={setSwitchOn}\n setValue={setValue}\n selectedRiScId={selectedRiScId}\n setSelectedRiScId={setSelectedRiScId}\n />\n )}\n {activeStep === 1 && (\n <ConfigRiscInfo\n register={register}\n errors={errors}\n setValue={setValue}\n watch={watch}\n control={control}\n />\n )}\n {activeStep === 2 && (\n <ConfigEncryptionDialog\n gcpCryptoKeys={gcpCryptoKeys}\n setValue={setValue}\n state={dialogState}\n register={register}\n errors={errors}\n />\n )}\n <Flex pt=\"16px\" justify=\"between\">\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Flex>\n <Button\n size=\"medium\"\n variant=\"secondary\"\n isDisabled={activeStep === 0}\n onClick={handleBack}\n >\n {t('dictionary.previous')}\n </Button>\n {activeStep < 2 ? (\n <Button size=\"medium\" variant=\"primary\" onClick={handleNext}>\n {t('dictionary.next')}\n </Button>\n ) : (\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.save')}\n </Button>\n )}\n </Flex>\n </Flex>\n </DialogComponent>\n );\n }\n\n if (dialogState === RiScDialogStates.Delete) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('deleteDialog.title')}\n className={styles.createRiscDialog}\n >\n <Flex direction=\"column\">\n {t('deleteDialog.confirmationMessage')}\n <Flex justify=\"between\" pt=\"16px\">\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.delete')}\n </Button>\n </Flex>\n </Flex>\n </DialogComponent>\n );\n }\n\n if (dialogState === RiScDialogStates.EditRiscInfo) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('rosDialog.titleEdit')}\n className={styles.createRiscDialog}\n >\n <ConfigRiscInfo\n register={register}\n errors={errors}\n setValue={setValue}\n watch={watch}\n control={control}\n />\n <Flex justify=\"between\" pt=\"16px\">\n <Button\n size=\"medium\"\n variant=\"tertiary\"\n onClick={onDelete}\n className={styles.deleteButton}\n >\n <i className={`ri-delete-bin-line ${styles.deleteButtonIcon}`} />\n {t('contentHeader.deleteButton')}\n </Button>\n <Flex>\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.save')}\n </Button>\n </Flex>\n </Flex>\n </DialogComponent>\n );\n }\n\n if (dialogState === RiScDialogStates.EditEncryption) {\n return (\n <DialogComponent\n isOpen={true}\n onClick={onClose}\n header={t('rosDialog.editEncryption')}\n className={styles.createRiscDialog}\n >\n <ConfigEncryptionDialog\n gcpCryptoKeys={gcpCryptoKeys}\n sopsData={selectedRiSc?.sopsConfig}\n setValue={setValue}\n state={dialogState}\n register={register}\n errors={errors}\n />\n <Flex justify=\"between\" pt=\"16px\">\n <Button size=\"medium\" variant=\"secondary\" onClick={onClose}>\n {t('dictionary.cancel')}\n </Button>\n <Button size=\"medium\" variant=\"primary\" onClick={handleFinish}>\n {t('dictionary.save')}\n </Button>\n </Flex>\n </DialogComponent>\n );\n }\n\n return null;\n}\n"],"names":["RiScDialogStates","styles"],"mappings":";;;;;;;;;;;;;;;;AAgBO,IAAK,gBAAA,qBAAAA,iBAAAA,KAAL;AACL,EAAAA,iBAAAA,CAAAA,iBAAAA,CAAA,YAAS,CAAA,CAAA,GAAT,QAAA;AACA,EAAAA,iBAAAA,CAAAA,iBAAAA,CAAA,YAAS,CAAA,CAAA,GAAT,QAAA;AACA,EAAAA,iBAAAA,CAAAA,iBAAAA,CAAA,kBAAe,CAAA,CAAA,GAAf,cAAA;AACA,EAAAA,iBAAAA,CAAAA,iBAAAA,CAAA,uBAAoB,CAAA,CAAA,GAApB,mBAAA;AACA,EAAAA,iBAAAA,CAAAA,iBAAAA,CAAA,oBAAiB,CAAA,CAAA,GAAjB,gBAAA;AACA,EAAAA,iBAAAA,CAAAA,iBAAAA,CAAA,YAAS,CAAA,CAAA,GAAT,QAAA;AANU,EAAA,OAAAA,iBAAAA;AAAA,CAAA,EAAA,gBAAA,IAAA,EAAA;AAeZ,SAAS,WAAA,CAAY,EAAE,UAAA,EAAW,EAA2B;AAC3D,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,wBAAwB,CAAA;AAExD,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,EAAE,4BAA4B,CAAA;AAAA,IAC9B,EAAE,2BAA2B,CAAA;AAAA,IAC7B,EAAE,0BAA0B;AAAA,GAC9B;AACA,EAAA,2BACG,OAAA,EAAA,EAAQ,UAAA,EAAwB,kBAAgB,IAAA,EAC9C,QAAA,EAAA,KAAA,CAAM,IAAI,CAAA,KAAA,qBACT,GAAA,CAAC,QACC,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EACC,8BAAC,IAAA,EAAA,EAAM,QAAA,EAAA,KAAA,EAAM,GACf,CAAA,EAAA,EAHS,KAIX,CACD,CAAA,EACH,CAAA;AAEJ;AAEO,SAAS,UAAA,CAAW;AAAA,EACzB,OAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAAoB;AAClB,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,wBAAwB,CAAA;AAExD,EAAA,MAAM;AAAA,IACJ,YAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,MACE,QAAA,EAAS;AACb,EAAA,MAAM;AAAA,IACJ,QAAA;AAAA,IACA,YAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA,EAAW,EAAE,MAAA,EAAO;AAAA,IACpB,QAAA;AAAA,IACA;AAAA,MACE,OAAA,CAA0B;AAAA,IAC5B,aAAA,EACE,WAAA,KAAgB,CAAA,uBAChB,WAAA,KAAgB,yBACZ,YAAA,GACA;AAAA,MACE,SAAS,SAAA,EAAU;AAAA,MACnB,UAAA,EAAY;AAAA,QACV,gBAAA,EAAkB;AAAA;AACpB,KACF;AAAA,IACN,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAAS,CAAC,CAAA;AAE9C,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,KAAK,CAAA;AAE9C,EAAA,MAAM,EAAE,qBAAA,EAAsB,GAAI,6BAAA,EAA8B;AAChE,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,QAAA;AAAA,IAC1C,qBAAA,EAAuB;AAAA,GACzB;AACA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,iBAAA,CAAkB,uBAAuB,EAAE,CAAA;AAAA,EAC7C,CAAA,EAAG,CAAC,qBAAqB,CAAC,CAAA;AAE1B,EAAA,MAAM,UAAA,GAAa,YAAA;AAAA,IACjB,MAAM;AACJ,MAAA,IAAI,eAAe,CAAA,EAAG;AACpB,QAAA,aAAA,CAAc,CAAC,CAAA;AAAA,MACjB;AACA,MAAA,IAAI,eAAe,CAAA,EAAG;AACpB,QAAA,aAAA,CAAc,CAAC,CAAA;AAAA,MACjB;AAAA,IACF,CAAA;AAAA;AAAA,IAEA,CAAA,gBAAA,KAAoB;AAClB,MAAA,IAAI,gBAAA,CAAiB,YAAY,MAAA,EAAW;AAC1C,QAAA,IAAI,UAAA,KAAe,CAAA,EAAG,aAAA,CAAc,CAAC,CAAA;AACrC,QAAA,IAAI,UAAA,KAAe,CAAA,EAAG,aAAA,CAAc,CAAC,CAAA;AAAA,MACvC;AAAA,IACF;AAAA,GACF;AAEA,EAAA,SAAS,UAAA,GAAa;AACpB,IAAA,IAAI,UAAA,KAAe,CAAA,EAAG,aAAA,CAAc,CAAC,CAAA;AACrC,IAAA,IAAI,UAAA,KAAe,CAAA,EAAG,aAAA,CAAc,CAAC,CAAA;AAAA,EACvC;AAEA,EAAA,MAAM,YAAA,GAAe,YAAA,CAAa,CAAC,IAAA,KAA2B;AAC5D,IAAA,IAAI,gBAAgB,CAAA,eAAyB;AAC3C,MAAA,aAAA,CAAc,IAAA,EAAM,UAAU,cAAc,CAAA;AAAA,IAC9C,CAAA,MAAA,IAAW,gBAAgB,CAAA,eAAyB;AAClD,MAAA,UAAA;AAAA,QAAW,MACT,UAAA,CAAW,KAAA,IAAS,KAAA,CAAM,MAAA,GAAS,IAAI,KAAA,CAAM,CAAC,CAAA,CAAE,EAAA,GAAK,EAAE;AAAA,OACzD;AAAA,IACF,CAAA,MAAO;AAIL,MAAA,MAAM,eAAA,GAAkB,aAAA;AAAA,QACtB,IAAA,CAAK,WAAW,GAAA,EAAK,GAAA,CAAI,SAAO,GAAA,CAAI,SAAS,EAAE,IAAA,EAAK;AAAA,QACpD,YAAA,EAAc,WAAW,GAAA,EAAK,GAAA,CAAI,SAAO,GAAA,CAAI,SAAS,EAAE,IAAA;AAAK,OAC/D;AAIA,MAAA,MAAM,eAAA,GAAkB,aAAA;AAAA,QACtB,MAAA,CAAO,WAAA;AAAA,UACL,IAAA,CAAK,UAAA,CAAW,OAAA,EAAS,GAAA,CAAI,CAAA,GAAA,KAAO;AAAA,YAClC,GAAA,CAAI,WAAA;AAAA,YACJ,GAAA,CAAI;AAAA,WACL,KAAK;AAAC,SACT;AAAA,QACA,MAAA,CAAO,WAAA;AAAA,UACL,YAAA,EAAc,UAAA,CAAW,OAAA,EAAS,GAAA,CAAI,CAAA,GAAA,KAAO;AAAA,YAC3C,GAAA,CAAI,WAAA;AAAA,YACJ,GAAA,CAAI;AAAA,WACL,KAAK;AAAC;AACT,OACF;AAGA,MAAA,IACE,CAAC,aAAA,CAAc,IAAA,EAAM,YAAA,EAAc,CAAC,YAAY,CAAC,CAAA,IACjD,CAAC,eAAA,IACD,CAAC,eAAA,EACD;AACA,QAAA,UAAA,CAAW,IAAI,CAAA;AAAA,MACjB;AAAA,IACF;AACA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAC,CAAA;AAED,EAAA,IAAI,gBAAgB,CAAA,eAAyB;AAC3C,IAAA,uBACE,IAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAQ,IAAA;AAAA,QACR,OAAA,EAAS,OAAA;AAAA,QACT,MAAA,EAAQ,EAAE,oBAAoB,CAAA;AAAA,QAC9B,WAAWC,YAAA,CAAO,gBAAA;AAAA,QAElB,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,eAAY,UAAA,EAAwB,CAAA;AAAA,0BACrC,IAAA;AAAA,YAAC,IAAA;AAAA,YAAA;AAAA,cACC,EAAA,EAAG,IAAA;AAAA,cACH,OAAA,EAAQ,eAAA;AAAA,cACR,MAAA,EAAO,MAAA;AAAA,cACP,WAAWA,YAAA,CAAO,QAAA;AAAA,cAEjB,QAAA,EAAA;AAAA,gBAAA,UAAA,KAAe,CAAA,IAAK,EAAE,4BAA4B,CAAA;AAAA,gBAClD,UAAA,KAAe,CAAA,IAAK,CAAA,CAAE,yBAAyB,CAAA;AAAA,gBAC/C,UAAA,KAAe,CAAA,IAAK,CAAA,CAAE,0BAA0B;AAAA;AAAA;AAAA,WACnD;AAAA,UACC,eAAe,CAAA,oBACd,GAAA;AAAA,YAAC,iBAAA;AAAA,YAAA;AAAA,cACC,QAAA;AAAA,cACA,WAAA;AAAA,cACA,QAAA;AAAA,cACA,cAAA;AAAA,cACA;AAAA;AAAA,WACF;AAAA,UAED,eAAe,CAAA,oBACd,GAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAA;AAAA,cACA,MAAA;AAAA,cACA,QAAA;AAAA,cACA,KAAA;AAAA,cACA;AAAA;AAAA,WACF;AAAA,UAED,eAAe,CAAA,oBACd,GAAA;AAAA,YAAC,sBAAA;AAAA,YAAA;AAAA,cACC,aAAA;AAAA,cACA,QAAA;AAAA,cACA,KAAA,EAAO,WAAA;AAAA,cACP,QAAA;AAAA,cACA;AAAA;AAAA,WACF;AAAA,0BAEF,IAAA,CAAC,IAAA,EAAA,EAAK,EAAA,EAAG,MAAA,EAAO,SAAQ,SAAA,EACtB,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,MAAK,QAAA,EAAS,OAAA,EAAQ,aAAY,OAAA,EAAS,OAAA,EAChD,QAAA,EAAA,CAAA,CAAE,mBAAmB,CAAA,EACxB,CAAA;AAAA,iCACC,IAAA,EAAA,EACC,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,IAAA,EAAK,QAAA;AAAA,kBACL,OAAA,EAAQ,WAAA;AAAA,kBACR,YAAY,UAAA,KAAe,CAAA;AAAA,kBAC3B,OAAA,EAAS,UAAA;AAAA,kBAER,YAAE,qBAAqB;AAAA;AAAA,eAC1B;AAAA,cACC,UAAA,GAAa,CAAA,mBACZ,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,UAAS,OAAA,EAAQ,SAAA,EAAU,OAAA,EAAS,UAAA,EAC9C,QAAA,EAAA,CAAA,CAAE,iBAAiB,GACtB,CAAA,mBAEA,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAQ,WAAU,OAAA,EAAS,YAAA,EAC9C,QAAA,EAAA,CAAA,CAAE,iBAAiB,CAAA,EACtB;AAAA,aAAA,EAEJ;AAAA,WAAA,EACF;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,IAAI,gBAAgB,CAAA,eAAyB;AAC3C,IAAA,uBACE,GAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAQ,IAAA;AAAA,QACR,OAAA,EAAS,OAAA;AAAA,QACT,MAAA,EAAQ,EAAE,oBAAoB,CAAA;AAAA,QAC9B,WAAWA,YAAA,CAAO,gBAAA;AAAA,QAElB,QAAA,kBAAA,IAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EACb,QAAA,EAAA;AAAA,UAAA,CAAA,CAAE,kCAAkC,CAAA;AAAA,0BACrC,IAAA,CAAC,IAAA,EAAA,EAAK,OAAA,EAAQ,SAAA,EAAU,IAAG,MAAA,EACzB,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,MAAK,QAAA,EAAS,OAAA,EAAQ,aAAY,OAAA,EAAS,OAAA,EAChD,QAAA,EAAA,CAAA,CAAE,mBAAmB,CAAA,EACxB,CAAA;AAAA,4BACA,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAQ,WAAU,OAAA,EAAS,YAAA,EAC9C,QAAA,EAAA,CAAA,CAAE,mBAAmB,CAAA,EACxB;AAAA,WAAA,EACF;AAAA,SAAA,EACF;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,IAAI,gBAAgB,CAAA,qBAA+B;AACjD,IAAA,uBACE,IAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAQ,IAAA;AAAA,QACR,OAAA,EAAS,OAAA;AAAA,QACT,MAAA,EAAQ,EAAE,qBAAqB,CAAA;AAAA,QAC/B,WAAWA,YAAA,CAAO,gBAAA;AAAA,QAElB,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAA;AAAA,cACA,MAAA;AAAA,cACA,QAAA;AAAA,cACA,KAAA;AAAA,cACA;AAAA;AAAA,WACF;AAAA,0BACA,IAAA,CAAC,IAAA,EAAA,EAAK,OAAA,EAAQ,SAAA,EAAU,IAAG,MAAA,EACzB,QAAA,EAAA;AAAA,4BAAA,IAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAQ,UAAA;AAAA,gBACR,OAAA,EAAS,QAAA;AAAA,gBACT,WAAWA,YAAA,CAAO,YAAA;AAAA,gBAElB,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAW,CAAA,mBAAA,EAAsBA,YAAA,CAAO,gBAAgB,CAAA,CAAA,EAAI,CAAA;AAAA,kBAC9D,EAAE,4BAA4B;AAAA;AAAA;AAAA,aACjC;AAAA,iCACC,IAAA,EAAA,EACC,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,MAAK,QAAA,EAAS,OAAA,EAAQ,aAAY,OAAA,EAAS,OAAA,EAChD,QAAA,EAAA,CAAA,CAAE,mBAAmB,CAAA,EACxB,CAAA;AAAA,8BACA,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAQ,WAAU,OAAA,EAAS,YAAA,EAC9C,QAAA,EAAA,CAAA,CAAE,iBAAiB,CAAA,EACtB;AAAA,aAAA,EACF;AAAA,WAAA,EACF;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,IAAI,gBAAgB,CAAA,uBAAiC;AACnD,IAAA,uBACE,IAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAQ,IAAA;AAAA,QACR,OAAA,EAAS,OAAA;AAAA,QACT,MAAA,EAAQ,EAAE,0BAA0B,CAAA;AAAA,QACpC,WAAWA,YAAA,CAAO,gBAAA;AAAA,QAElB,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,sBAAA;AAAA,YAAA;AAAA,cACC,aAAA;AAAA,cACA,UAAU,YAAA,EAAc,UAAA;AAAA,cACxB,QAAA;AAAA,cACA,KAAA,EAAO,WAAA;AAAA,cACP,QAAA;AAAA,cACA;AAAA;AAAA,WACF;AAAA,0BACA,IAAA,CAAC,IAAA,EAAA,EAAK,OAAA,EAAQ,SAAA,EAAU,IAAG,MAAA,EACzB,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,MAAK,QAAA,EAAS,OAAA,EAAQ,aAAY,OAAA,EAAS,OAAA,EAChD,QAAA,EAAA,CAAA,CAAE,mBAAmB,CAAA,EACxB,CAAA;AAAA,4BACA,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAQ,WAAU,OAAA,EAAS,YAAA,EAC9C,QAAA,EAAA,CAAA,CAAE,iBAAiB,CAAA,EACtB;AAAA,WAAA,EACF;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,OAAO,IAAA;AACT;;;;"}
@@ -0,0 +1,25 @@
1
+ import { stringifyEntityRef, parseEntityRef } from '@backstage/catalog-model';
2
+
3
+ const entityRefOptionFields = [
4
+ "kind",
5
+ "metadata.name",
6
+ "metadata.namespace"
7
+ ];
8
+ function getCurrentSystemRef(entity) {
9
+ if (entity.kind === "System") {
10
+ return stringifyEntityRef(entity);
11
+ }
12
+ const specSystem = entity.spec?.system;
13
+ if (typeof specSystem !== "string" || specSystem.trim() === "") {
14
+ return void 0;
15
+ }
16
+ return stringifyEntityRef(
17
+ parseEntityRef(specSystem, {
18
+ defaultKind: "System",
19
+ defaultNamespace: entity.metadata.namespace ?? "default"
20
+ })
21
+ );
22
+ }
23
+
24
+ export { entityRefOptionFields, getCurrentSystemRef };
25
+ //# sourceMappingURL=entityRefOptions.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityRefOptions.esm.js","sources":["../../../src/components/riScDialog/entityRefOptions.ts"],"sourcesContent":["import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport type { Entity } from '@backstage/catalog-model';\n\nexport const entityRefOptionFields = [\n 'kind',\n 'metadata.name',\n 'metadata.namespace',\n];\n\nexport function getCurrentSystemRef(entity: Entity): string | undefined {\n if (entity.kind === 'System') {\n return stringifyEntityRef(entity);\n }\n\n const specSystem = entity.spec?.system;\n if (typeof specSystem !== 'string' || specSystem.trim() === '') {\n return undefined;\n }\n\n return stringifyEntityRef(\n parseEntityRef(specSystem, {\n defaultKind: 'System',\n defaultNamespace: entity.metadata.namespace ?? 'default',\n }),\n );\n}\n"],"names":[],"mappings":";;AAGO,MAAM,qBAAA,GAAwB;AAAA,EACnC,MAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF;AAEO,SAAS,oBAAoB,MAAA,EAAoC;AACtE,EAAA,IAAI,MAAA,CAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,OAAO,mBAAmB,MAAM,CAAA;AAAA,EAClC;AAEA,EAAA,MAAM,UAAA,GAAa,OAAO,IAAA,EAAM,MAAA;AAChC,EAAA,IAAI,OAAO,UAAA,KAAe,QAAA,IAAY,UAAA,CAAW,IAAA,OAAW,EAAA,EAAI;AAC9D,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,kBAAA;AAAA,IACL,eAAe,UAAA,EAAY;AAAA,MACzB,WAAA,EAAa,QAAA;AAAA,MACb,gBAAA,EAAkB,MAAA,CAAO,QAAA,CAAS,SAAA,IAAa;AAAA,KAChD;AAAA,GACH;AACF;;;;"}
@@ -10,22 +10,38 @@ import MUISelect from '@mui/material/Select';
10
10
  import riscStyles from './RiScSelectionCard.module.css.esm.js';
11
11
 
12
12
  function RiScSelectionCard() {
13
- const { riScs, lockedRiScs, selectedRiSc, selectedLockedRiSc, selectRiSc } = useRiScs();
13
+ const {
14
+ riScs,
15
+ lockedRiScs,
16
+ systemRiScs,
17
+ selectedRiSc,
18
+ selectedLockedRiSc,
19
+ selectedSystemRiSc,
20
+ selectRiSc
21
+ } = useRiScs();
14
22
  const { t } = useTranslationRef(pluginRiScTranslationRef);
15
- const hasOptions = riScs !== null && riScs.length !== 0 || lockedRiScs.length !== 0;
23
+ const hasOptions = riScs !== null && riScs.length !== 0 || systemRiScs.length !== 0 || lockedRiScs.length !== 0;
16
24
  return /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "24px", children: hasOptions && /* @__PURE__ */ jsx(FormControl, { fullWidth: true, size: "small", children: /* @__PURE__ */ jsxs(
17
25
  MUISelect,
18
26
  {
19
- value: selectedRiSc?.id ?? selectedLockedRiSc?.id ?? "",
27
+ value: selectedRiSc?.id ?? selectedSystemRiSc?.riScId ?? selectedLockedRiSc?.id ?? "",
20
28
  onChange: (e) => selectRiSc(e.target.value),
21
29
  inputProps: { "aria-label": t("contentHeader.multipleRiScs") },
22
30
  MenuProps: { disablePortal: true },
23
31
  children: [
24
32
  (riScs ?? []).map((riSc) => /* @__PURE__ */ jsx(MenuItem, { value: riSc.id, children: riSc.content.title }, riSc.id)),
33
+ systemRiScs.length > 0 && /* @__PURE__ */ jsx(
34
+ ListSubheader,
35
+ {
36
+ className: `${riscStyles.sectionHeader} ${riScs && riScs.length > 0 ? riscStyles.sectionHeaderWithDivider : ""}`,
37
+ children: t("contentHeader.systemRiScsSection")
38
+ }
39
+ ),
40
+ systemRiScs.map((riSc) => /* @__PURE__ */ jsx(MenuItem, { value: riSc.riScId, children: riSc.riScId }, riSc.riScId)),
25
41
  lockedRiScs.length > 0 && /* @__PURE__ */ jsx(
26
42
  ListSubheader,
27
43
  {
28
- className: `${riscStyles.lockedSectionHeader} ${riScs && riScs.length > 0 ? riscStyles.lockedSectionHeaderWithDivider : ""}`,
44
+ className: `${riscStyles.sectionHeader} ${riScs && riScs.length > 0 || systemRiScs.length > 0 ? riscStyles.sectionHeaderWithDivider : ""}`,
29
45
  children: t("contentHeader.lockedRiScsSection")
30
46
  }
31
47
  ),
@@ -1 +1 @@
1
- {"version":3,"file":"RiScSelectionCard.esm.js","sources":["../../../src/components/riScInfo/RiScSelectionCard.tsx"],"sourcesContent":["import { useRiScs } from '../../contexts/RiScContext.tsx';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { pluginRiScTranslationRef } from '../../utils/translations.ts';\nimport { Flex } from '@backstage/ui';\nimport FormControl from '@mui/material/FormControl';\nimport ListSubheader from '@mui/material/ListSubheader';\nimport MenuItem from '@mui/material/MenuItem';\nimport MUISelect from '@mui/material/Select';\nimport styles from './RiScSelectionCard.module.css';\n\nexport function RiScSelectionCard() {\n const { riScs, lockedRiScs, selectedRiSc, selectedLockedRiSc, selectRiSc } =\n useRiScs();\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n\n const hasOptions =\n (riScs !== null && riScs.length !== 0) || lockedRiScs.length !== 0;\n\n return (\n <Flex direction=\"column\" gap=\"24px\">\n {hasOptions && (\n <FormControl fullWidth size=\"small\">\n <MUISelect\n value={selectedRiSc?.id ?? selectedLockedRiSc?.id ?? ''}\n onChange={e => selectRiSc(e.target.value)}\n inputProps={{ 'aria-label': t('contentHeader.multipleRiScs') }}\n MenuProps={{ disablePortal: true }}\n >\n {(riScs ?? []).map(riSc => (\n <MenuItem key={riSc.id} value={riSc.id}>\n {riSc.content.title}\n </MenuItem>\n ))}\n {lockedRiScs.length > 0 && (\n <ListSubheader\n className={`${styles.lockedSectionHeader} ${riScs && riScs.length > 0 ? styles.lockedSectionHeaderWithDivider : ''}`}\n >\n {t('contentHeader.lockedRiScsSection')}\n </ListSubheader>\n )}\n {lockedRiScs.map(riSc => (\n <MenuItem key={riSc.id} value={riSc.id}>\n 🔒 {riSc.id}\n </MenuItem>\n ))}\n </MUISelect>\n </FormControl>\n )}\n </Flex>\n );\n}\n"],"names":["styles"],"mappings":";;;;;;;;;;;AAUO,SAAS,iBAAA,GAAoB;AAClC,EAAA,MAAM,EAAE,KAAA,EAAO,WAAA,EAAa,cAAc,kBAAA,EAAoB,UAAA,KAC5D,QAAA,EAAS;AACX,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,wBAAwB,CAAA;AAExD,EAAA,MAAM,aACH,KAAA,KAAU,IAAA,IAAQ,MAAM,MAAA,KAAW,CAAA,IAAM,YAAY,MAAA,KAAW,CAAA;AAEnE,EAAA,uBACE,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,GAAA,EAAI,MAAA,EAC1B,QAAA,EAAA,UAAA,oBACC,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAS,IAAA,EAAC,IAAA,EAAK,OAAA,EAC1B,QAAA,kBAAA,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,YAAA,EAAc,EAAA,IAAM,kBAAA,EAAoB,EAAA,IAAM,EAAA;AAAA,MACrD,QAAA,EAAU,CAAA,CAAA,KAAK,UAAA,CAAW,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,MACxC,UAAA,EAAY,EAAE,YAAA,EAAc,CAAA,CAAE,6BAA6B,CAAA,EAAE;AAAA,MAC7D,SAAA,EAAW,EAAE,aAAA,EAAe,IAAA,EAAK;AAAA,MAE/B,QAAA,EAAA;AAAA,QAAA,CAAA,KAAA,IAAS,EAAC,EAAG,GAAA,CAAI,CAAA,IAAA,yBAChB,QAAA,EAAA,EAAuB,KAAA,EAAO,IAAA,CAAK,EAAA,EACjC,QAAA,EAAA,IAAA,CAAK,OAAA,CAAQ,KAAA,EAAA,EADD,IAAA,CAAK,EAEpB,CACD,CAAA;AAAA,QACA,WAAA,CAAY,SAAS,CAAA,oBACpB,GAAA;AAAA,UAAC,aAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,CAAA,EAAGA,UAAA,CAAO,mBAAmB,CAAA,CAAA,EAAI,KAAA,IAAS,KAAA,CAAM,MAAA,GAAS,CAAA,GAAIA,UAAA,CAAO,8BAAA,GAAiC,EAAE,CAAA,CAAA;AAAA,YAEjH,YAAE,kCAAkC;AAAA;AAAA,SACvC;AAAA,QAED,YAAY,GAAA,CAAI,CAAA,IAAA,0BACd,QAAA,EAAA,EAAuB,KAAA,EAAO,KAAK,EAAA,EAAI,QAAA,EAAA;AAAA,UAAA,YAAA;AAAA,UAClC,IAAA,CAAK;AAAA,SAAA,EAAA,EADI,IAAA,CAAK,EAEpB,CACD;AAAA;AAAA;AAAA,KAEL,CAAA,EAEJ,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"RiScSelectionCard.esm.js","sources":["../../../src/components/riScInfo/RiScSelectionCard.tsx"],"sourcesContent":["import { useRiScs } from '../../contexts/RiScContext.tsx';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { pluginRiScTranslationRef } from '../../utils/translations.ts';\nimport { Flex } from '@backstage/ui';\nimport FormControl from '@mui/material/FormControl';\nimport ListSubheader from '@mui/material/ListSubheader';\nimport MenuItem from '@mui/material/MenuItem';\nimport MUISelect from '@mui/material/Select';\nimport styles from './RiScSelectionCard.module.css';\n\nexport function RiScSelectionCard() {\n const {\n riScs,\n lockedRiScs,\n systemRiScs,\n selectedRiSc,\n selectedLockedRiSc,\n selectedSystemRiSc,\n selectRiSc,\n } = useRiScs();\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n\n const hasOptions =\n (riScs !== null && riScs.length !== 0) ||\n systemRiScs.length !== 0 ||\n lockedRiScs.length !== 0;\n\n return (\n <Flex direction=\"column\" gap=\"24px\">\n {hasOptions && (\n <FormControl fullWidth size=\"small\">\n <MUISelect\n value={\n selectedRiSc?.id ??\n selectedSystemRiSc?.riScId ??\n selectedLockedRiSc?.id ??\n ''\n }\n onChange={e => selectRiSc(e.target.value)}\n inputProps={{ 'aria-label': t('contentHeader.multipleRiScs') }}\n MenuProps={{ disablePortal: true }}\n >\n {(riScs ?? []).map(riSc => (\n <MenuItem key={riSc.id} value={riSc.id}>\n {riSc.content.title}\n </MenuItem>\n ))}\n {systemRiScs.length > 0 && (\n <ListSubheader\n className={`${styles.sectionHeader} ${riScs && riScs.length > 0 ? styles.sectionHeaderWithDivider : ''}`}\n >\n {t('contentHeader.systemRiScsSection')}\n </ListSubheader>\n )}\n {systemRiScs.map(riSc => (\n <MenuItem key={riSc.riScId} value={riSc.riScId}>\n {riSc.riScId}\n </MenuItem>\n ))}\n {lockedRiScs.length > 0 && (\n <ListSubheader\n className={`${styles.sectionHeader} ${\n (riScs && riScs.length > 0) || systemRiScs.length > 0\n ? styles.sectionHeaderWithDivider\n : ''\n }`}\n >\n {t('contentHeader.lockedRiScsSection')}\n </ListSubheader>\n )}\n {lockedRiScs.map(riSc => (\n <MenuItem key={riSc.id} value={riSc.id}>\n 🔒 {riSc.id}\n </MenuItem>\n ))}\n </MUISelect>\n </FormControl>\n )}\n </Flex>\n );\n}\n"],"names":["styles"],"mappings":";;;;;;;;;;;AAUO,SAAS,iBAAA,GAAoB;AAClC,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,kBAAA;AAAA,IACA,kBAAA;AAAA,IACA;AAAA,MACE,QAAA,EAAS;AACb,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,wBAAwB,CAAA;AAExD,EAAA,MAAM,UAAA,GACH,KAAA,KAAU,IAAA,IAAQ,KAAA,CAAM,MAAA,KAAW,KACpC,WAAA,CAAY,MAAA,KAAW,CAAA,IACvB,WAAA,CAAY,MAAA,KAAW,CAAA;AAEzB,EAAA,uBACE,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,GAAA,EAAI,MAAA,EAC1B,QAAA,EAAA,UAAA,oBACC,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAS,IAAA,EAAC,IAAA,EAAK,OAAA,EAC1B,QAAA,kBAAA,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,OACE,YAAA,EAAc,EAAA,IACd,kBAAA,EAAoB,MAAA,IACpB,oBAAoB,EAAA,IACpB,EAAA;AAAA,MAEF,QAAA,EAAU,CAAA,CAAA,KAAK,UAAA,CAAW,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,MACxC,UAAA,EAAY,EAAE,YAAA,EAAc,CAAA,CAAE,6BAA6B,CAAA,EAAE;AAAA,MAC7D,SAAA,EAAW,EAAE,aAAA,EAAe,IAAA,EAAK;AAAA,MAE/B,QAAA,EAAA;AAAA,QAAA,CAAA,KAAA,IAAS,EAAC,EAAG,GAAA,CAAI,CAAA,IAAA,yBAChB,QAAA,EAAA,EAAuB,KAAA,EAAO,IAAA,CAAK,EAAA,EACjC,QAAA,EAAA,IAAA,CAAK,OAAA,CAAQ,KAAA,EAAA,EADD,IAAA,CAAK,EAEpB,CACD,CAAA;AAAA,QACA,WAAA,CAAY,SAAS,CAAA,oBACpB,GAAA;AAAA,UAAC,aAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,CAAA,EAAGA,UAAA,CAAO,aAAa,CAAA,CAAA,EAAI,KAAA,IAAS,KAAA,CAAM,MAAA,GAAS,CAAA,GAAIA,UAAA,CAAO,wBAAA,GAA2B,EAAE,CAAA,CAAA;AAAA,YAErG,YAAE,kCAAkC;AAAA;AAAA,SACvC;AAAA,QAED,WAAA,CAAY,GAAA,CAAI,CAAA,IAAA,qBACf,GAAA,CAAC,QAAA,EAAA,EAA2B,KAAA,EAAO,IAAA,CAAK,MAAA,EACrC,QAAA,EAAA,IAAA,CAAK,MAAA,EAAA,EADO,IAAA,CAAK,MAEpB,CACD,CAAA;AAAA,QACA,WAAA,CAAY,SAAS,CAAA,oBACpB,GAAA;AAAA,UAAC,aAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,CAAA,EAAGA,UAAA,CAAO,aAAa,IAC/B,KAAA,IAAS,KAAA,CAAM,MAAA,GAAS,CAAA,IAAM,WAAA,CAAY,MAAA,GAAS,CAAA,GAChDA,UAAA,CAAO,2BACP,EACN,CAAA,CAAA;AAAA,YAEC,YAAE,kCAAkC;AAAA;AAAA,SACvC;AAAA,QAED,YAAY,GAAA,CAAI,CAAA,IAAA,0BACd,QAAA,EAAA,EAAuB,KAAA,EAAO,KAAK,EAAA,EAAI,QAAA,EAAA;AAAA,UAAA,YAAA;AAAA,UAClC,IAAA,CAAK;AAAA,SAAA,EAAA,EADI,IAAA,CAAK,EAEpB,CACD;AAAA;AAAA;AAAA,KAEL,CAAA,EAEJ,CAAA;AAEJ;;;;"}
@@ -1,7 +1,7 @@
1
1
  import styleInject from '../../node_modules_dist/style-inject/dist/style-inject.es.esm.js';
2
2
 
3
- var css_248z = ".RiScSelectionCard_lockedSectionHeader__8c09a22d25 {\n font-weight: 700;\n font-size: 0.7rem;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n background-color: inherit !important;\n}\n\n.RiScSelectionCard_lockedSectionHeaderWithDivider__8c09a22d25 {\n border-top: 1px solid var(--ros-gray-200);\n margin-top: 4px;\n padding-top: 8px;\n}\n\n[role='listbox'] {\n max-height: 400px;\n overflow-y: auto;\n}\n\n.RiScSelectionCard_riScInfoDialog__8c09a22d25 {\n padding: 24px;\n border-radius: 4px;\n width: 800px;\n}\n\n.RiScSelectionCard_riscSelectionDialogHeader__8c09a22d25 {\n padding: 0 0 16px 0;\n}\n\n.RiScSelectionCard_riscSelectionDialogBody__8c09a22d25 {\n gap: 16px;\n padding: 16px 0 0 0;\n}\n\n.RiScSelectionCard_riscDescriptionComponent__8c09a22d25 {\n padding-bottom: 10px;\n}\n.RiScSelectionCard_componentLayout__8c09a22d25 {\n height: 60%;\n}\n\n.RiScSelectionCard_riscDescriptionContainer__8c09a22d25 {\n margin-bottom: 16px;\n}\n\n.RiScSelectionCard_riScInfoDialog__8c09a22d25 {\n background-color: var(--bui-bg-app);\n}\n";
4
- var riscStyles = {"lockedSectionHeader":"RiScSelectionCard_lockedSectionHeader__8c09a22d25","lockedSectionHeaderWithDivider":"RiScSelectionCard_lockedSectionHeaderWithDivider__8c09a22d25","riScInfoDialog":"RiScSelectionCard_riScInfoDialog__8c09a22d25","riscDescriptionComponent":"RiScSelectionCard_riscDescriptionComponent__8c09a22d25","componentLayout":"RiScSelectionCard_componentLayout__8c09a22d25","riscDescriptionContainer":"RiScSelectionCard_riscDescriptionContainer__8c09a22d25"};
3
+ var css_248z = ".RiScSelectionCard_sectionHeader__2c941d3e94 {\n font-weight: 700;\n font-size: 0.7rem;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n background-color: inherit !important;\n}\n\n.RiScSelectionCard_sectionHeaderWithDivider__2c941d3e94 {\n border-top: 1px solid var(--ros-gray-200);\n margin-top: 4px;\n padding-top: 8px;\n}\n\n[role='listbox'] {\n max-height: 400px;\n overflow-y: auto;\n}\n\n.RiScSelectionCard_riScInfoDialog__2c941d3e94 {\n padding: 24px;\n border-radius: 4px;\n width: 800px;\n}\n\n.RiScSelectionCard_riscSelectionDialogHeader__2c941d3e94 {\n padding: 0 0 16px 0;\n}\n\n.RiScSelectionCard_riscSelectionDialogBody__2c941d3e94 {\n gap: 16px;\n padding: 16px 0 0 0;\n}\n\n.RiScSelectionCard_riscDescriptionComponent__2c941d3e94 {\n padding-bottom: 10px;\n}\n.RiScSelectionCard_componentLayout__2c941d3e94 {\n height: 60%;\n}\n\n.RiScSelectionCard_riscDescriptionContainer__2c941d3e94 {\n margin-bottom: 16px;\n}\n\n.RiScSelectionCard_riScInfoDialog__2c941d3e94 {\n background-color: var(--bui-bg-app);\n}\n";
4
+ var riscStyles = {"sectionHeader":"RiScSelectionCard_sectionHeader__2c941d3e94","sectionHeaderWithDivider":"RiScSelectionCard_sectionHeaderWithDivider__2c941d3e94","riScInfoDialog":"RiScSelectionCard_riScInfoDialog__2c941d3e94","riscDescriptionComponent":"RiScSelectionCard_riscDescriptionComponent__2c941d3e94","componentLayout":"RiScSelectionCard_componentLayout__2c941d3e94","riscDescriptionContainer":"RiScSelectionCard_riscDescriptionContainer__2c941d3e94"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { riscStyles as default };
@@ -0,0 +1,31 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { ChangeSetBox } from './components/ChangeSetBox.esm.js';
3
+ import { ChangeSetBoxTitle } from './components/ChangeSetBoxTitle.esm.js';
4
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
5
+ import { pluginRiScTranslationRef } from '../../../utils/translations.esm.js';
6
+ import { ChangeSetAddedValue } from './components/ChangeSetAddedValue.esm.js';
7
+ import { ChangeSetRemovedValue } from './components/ChangeSetRemovedValue.esm.js';
8
+ import { ChangeSetSimpleBox } from './components/ChangeSetSimpleBox.esm.js';
9
+
10
+ function RiScAppliesToChange({
11
+ appliesToChanges
12
+ }) {
13
+ const { t } = useTranslationRef(pluginRiScTranslationRef);
14
+ return /* @__PURE__ */ jsxs(ChangeSetBox, { type: "primary", children: [
15
+ /* @__PURE__ */ jsx(ChangeSetBoxTitle, { title: t("dictionary.appliesTo") }),
16
+ appliesToChanges.map((entityChange) => /* @__PURE__ */ jsxs("div", { children: [
17
+ entityChange.type === "ADDED" && /* @__PURE__ */ jsx(ChangeSetAddedValue, { newValue: entityChange.newValue }),
18
+ entityChange.type === "DELETED" && /* @__PURE__ */ jsx(ChangeSetRemovedValue, { oldValue: entityChange.oldValue }),
19
+ entityChange.type === "CONTENT_CHANGED" && /* @__PURE__ */ jsx(
20
+ ChangeSetSimpleBox,
21
+ {
22
+ prop: entityChange,
23
+ title: t("dictionary.appliesTo")
24
+ }
25
+ )
26
+ ] }, JSON.stringify(entityChange)))
27
+ ] });
28
+ }
29
+
30
+ export { RiScAppliesToChange };
31
+ //# sourceMappingURL=RiScAppliesToChange.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RiScAppliesToChange.esm.js","sources":["../../../../src/components/riScInfo/changeset/RiScAppliesToChange.tsx"],"sourcesContent":["import { SimpleTrackedProperty } from '../../../utils/types.ts';\nimport { ChangeSetBox } from './components/ChangeSetBox.tsx';\nimport { ChangeSetBoxTitle } from './components/ChangeSetBoxTitle.tsx';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { pluginRiScTranslationRef } from '../../../utils/translations.ts';\nimport { ChangeSetAddedValue } from './components/ChangeSetAddedValue.tsx';\nimport { ChangeSetRemovedValue } from './components/ChangeSetRemovedValue.tsx';\nimport { ChangeSetSimpleBox } from './components/ChangeSetSimpleBox.tsx';\n\ninterface RiScAppliesToChangeProps {\n appliesToChanges: SimpleTrackedProperty<string>[];\n}\n\nexport function RiScAppliesToChange({\n appliesToChanges,\n}: RiScAppliesToChangeProps) {\n const { t } = useTranslationRef(pluginRiScTranslationRef);\n return (\n <ChangeSetBox type=\"primary\">\n <ChangeSetBoxTitle title={t('dictionary.appliesTo')} />\n {appliesToChanges.map(entityChange => (\n <div key={JSON.stringify(entityChange)}>\n {entityChange.type === 'ADDED' && (\n <ChangeSetAddedValue newValue={entityChange.newValue} />\n )}\n {entityChange.type === 'DELETED' && (\n <ChangeSetRemovedValue oldValue={entityChange.oldValue} />\n )}\n {entityChange.type === 'CONTENT_CHANGED' && (\n <ChangeSetSimpleBox\n prop={entityChange}\n title={t('dictionary.appliesTo')}\n />\n )}\n </div>\n ))}\n </ChangeSetBox>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAaO,SAAS,mBAAA,CAAoB;AAAA,EAClC;AACF,CAAA,EAA6B;AAC3B,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,wBAAwB,CAAA;AACxD,EAAA,uBACE,IAAA,CAAC,YAAA,EAAA,EAAa,IAAA,EAAK,SAAA,EACjB,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,iBAAA,EAAA,EAAkB,KAAA,EAAO,CAAA,CAAE,sBAAsB,CAAA,EAAG,CAAA;AAAA,IACpD,gBAAA,CAAiB,GAAA,CAAI,CAAA,YAAA,qBACpB,IAAA,CAAC,KAAA,EAAA,EACE,QAAA,EAAA;AAAA,MAAA,YAAA,CAAa,SAAS,OAAA,oBACrB,GAAA,CAAC,mBAAA,EAAA,EAAoB,QAAA,EAAU,aAAa,QAAA,EAAU,CAAA;AAAA,MAEvD,aAAa,IAAA,KAAS,SAAA,wBACpB,qBAAA,EAAA,EAAsB,QAAA,EAAU,aAAa,QAAA,EAAU,CAAA;AAAA,MAEzD,YAAA,CAAa,SAAS,iBAAA,oBACrB,GAAA;AAAA,QAAC,kBAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAM,YAAA;AAAA,UACN,KAAA,EAAO,EAAE,sBAAsB;AAAA;AAAA;AACjC,KAAA,EAAA,EAXM,IAAA,CAAK,SAAA,CAAU,YAAY,CAarC,CACD;AAAA,GAAA,EACH,CAAA;AAEJ;;;;"}
@@ -7,12 +7,14 @@ import { dtoToScenario } from '../../../utils/DTOs.esm.js';
7
7
  import { ChangeSetSimpleBox } from './components/ChangeSetSimpleBox.esm.js';
8
8
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
9
9
  import { pluginRiScTranslationRef } from '../../../utils/translations.esm.js';
10
+ import { RiScAppliesToChange } from './RiScAppliesToChange.esm.js';
10
11
 
11
12
  function RiScChangeSet({ changeset }) {
12
13
  const { t } = useTranslationRef(pluginRiScTranslationRef);
13
14
  const migrationChanges = changeset.differenceState.migrationChanges;
14
15
  const changes = changeset.differenceState;
15
- const hasChanges = changes.scenarios.length > 0 || changes.valuations.length > 0 || changes.title || changes.scope;
16
+ const appliesToChanges = changes.appliesTo ?? [];
17
+ const hasChanges = changes.scenarios.length > 0 || changes.valuations.length > 0 || changes.title || changes.scope || appliesToChanges.length > 0;
16
18
  const hasAnyChanges = changes.migrationChanges.migrationChanges || hasChanges;
17
19
  if (!hasAnyChanges) {
18
20
  return /* @__PURE__ */ jsx("i", { children: t("comparisonDialog.noChanges") });
@@ -35,6 +37,7 @@ function RiScChangeSet({ changeset }) {
35
37
  title: t("dictionary.scope")
36
38
  }
37
39
  ),
40
+ appliesToChanges.length > 1 && /* @__PURE__ */ jsx(RiScAppliesToChange, { appliesToChanges }),
38
41
  changes.scenarios.map((scenario) => /* @__PURE__ */ jsxs(Fragment, { children: [
39
42
  (scenario.type === "ADDED" || scenario.type === "DELETED") && /* @__PURE__ */ jsx(
40
43
  RiScScenarioChange,