@kyverno/backstage-plugin-policy-reporter 2.10.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/alpha/components/PolicyReporterPoliciesSubPage/PolicyReporterPoliciesSubPage.esm.js +38 -0
  3. package/dist/alpha/components/PolicyReporterPoliciesSubPage/PolicyReporterPoliciesSubPage.esm.js.map +1 -0
  4. package/dist/alpha/components/PolicyReporterPoliciesSubPage/index.esm.js +6 -0
  5. package/dist/alpha/components/PolicyReporterPoliciesSubPage/index.esm.js.map +1 -0
  6. package/dist/alpha/plugin.esm.js +51 -8
  7. package/dist/alpha/plugin.esm.js.map +1 -1
  8. package/dist/alpha.d.ts +25 -0
  9. package/dist/components/EntityCustomPoliciesContent/EntityCustomPoliciesContent.esm.js +1 -0
  10. package/dist/components/EntityCustomPoliciesContent/EntityCustomPoliciesContent.esm.js.map +1 -1
  11. package/dist/components/EntityKyvernoPoliciesContent/EntityKyvernoPoliciesContent.esm.js +1 -0
  12. package/dist/components/EntityKyvernoPoliciesContent/EntityKyvernoPoliciesContent.esm.js.map +1 -1
  13. package/dist/components/MissingKubernetesCluster/MissingKubernetesCluster.esm.js +27 -0
  14. package/dist/components/MissingKubernetesCluster/MissingKubernetesCluster.esm.js.map +1 -0
  15. package/dist/components/PolicyReportsPage/PolicyReportsPage.esm.js +6 -23
  16. package/dist/components/PolicyReportsPage/PolicyReportsPage.esm.js.map +1 -1
  17. package/dist/components/PolicyReportsTable/PolicyReportsTable.esm.js +12 -9
  18. package/dist/components/PolicyReportsTable/PolicyReportsTable.esm.js.map +1 -1
  19. package/dist/components/SelectCategory/SelectCategory.esm.js +4 -3
  20. package/dist/components/SelectCategory/SelectCategory.esm.js.map +1 -1
  21. package/dist/components/SelectKind/SelectKind.esm.js +4 -3
  22. package/dist/components/SelectKind/SelectKind.esm.js.map +1 -1
  23. package/dist/components/SelectPolicy/SelectPolicy.esm.js +4 -3
  24. package/dist/components/SelectPolicy/SelectPolicy.esm.js.map +1 -1
  25. package/dist/components/SelectSource/SelectSource.esm.js +4 -3
  26. package/dist/components/SelectSource/SelectSource.esm.js.map +1 -1
  27. package/dist/hooks/usePolicyReportsFilters.esm.js +5 -3
  28. package/dist/hooks/usePolicyReportsFilters.esm.js.map +1 -1
  29. package/dist/package.json.esm.js +1 -1
  30. package/package.json +13 -13
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @kyverno/backstage-plugin-policy-reporter
2
2
 
3
+ ## 2.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 32f327e: Add cluster-scoped source, kind, category and policy filters.
8
+ - 32f327e: NFS (/alpha): Add a new subpage for viewing cluster-scoped policies.
9
+ - 32f327e: Backstage verion bump to v1.55.3
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [32f327e]
14
+ - Updated dependencies [32f327e]
15
+ - Updated dependencies [32f327e]
16
+ - @kyverno/backstage-plugin-policy-reporter-common@2.6.0
17
+
3
18
  ## 2.10.0
4
19
 
5
20
  ### Minor Changes
@@ -0,0 +1,38 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { Progress } from '@backstage/core-components';
3
+ import { Flex } from '@backstage/ui';
4
+ import { useEnvironments } from '../../../hooks/useEnvironments.esm.js';
5
+ import { SelectEnvironment } from '../../../components/SelectEnvironment/SelectEnvironment.esm.js';
6
+ import { PolicyReportsTable } from '../../../components/PolicyReportsTable/PolicyReportsTable.esm.js';
7
+ import { SearchField } from '../../../components/SearchField/SearchField.esm.js';
8
+ import { PolicyReportsFiltersProvider } from '../../../hooks/usePolicyReportsFilters.esm.js';
9
+ import { FilterLayout } from '../../../components/FilterLayout/FilterLayout.esm.js';
10
+ import { MissingKubernetesCluster } from '../../../components/MissingKubernetesCluster/MissingKubernetesCluster.esm.js';
11
+
12
+ const PolicyReporterPoliciesSubPage = (props) => {
13
+ const { initiallySelectedFilter, filters, context } = props;
14
+ const { environments, environmentsLoading } = useEnvironments();
15
+ if (environmentsLoading) return /* @__PURE__ */ jsx(Progress, {});
16
+ if (!environments?.length) return /* @__PURE__ */ jsx(MissingKubernetesCluster, {});
17
+ return /* @__PURE__ */ jsx(
18
+ PolicyReportsFiltersProvider,
19
+ {
20
+ defaultEnvironment: environments[0].entityRef,
21
+ context,
22
+ defaultFilters: initiallySelectedFilter,
23
+ children: /* @__PURE__ */ jsxs(FilterLayout, { children: [
24
+ /* @__PURE__ */ jsxs(FilterLayout.Filters, { children: [
25
+ /* @__PURE__ */ jsx(SelectEnvironment, { environments }),
26
+ filters
27
+ ] }),
28
+ /* @__PURE__ */ jsx(FilterLayout.Content, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "4", children: [
29
+ /* @__PURE__ */ jsx(SearchField, {}),
30
+ /* @__PURE__ */ jsx(PolicyReportsTable, { emptyContentText: "No policies found" })
31
+ ] }) })
32
+ ] })
33
+ }
34
+ );
35
+ };
36
+
37
+ export { PolicyReporterPoliciesSubPage };
38
+ //# sourceMappingURL=PolicyReporterPoliciesSubPage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PolicyReporterPoliciesSubPage.esm.js","sources":["../../../../src/alpha/components/PolicyReporterPoliciesSubPage/PolicyReporterPoliciesSubPage.tsx"],"sourcesContent":["import { Progress } from '@backstage/core-components';\nimport { Flex } from '@backstage/ui';\nimport { useEnvironments } from '../../../hooks/useEnvironments';\nimport { SelectEnvironment } from '../../../components/SelectEnvironment';\nimport { PolicyReportsTable } from '../../../components/PolicyReportsTable';\nimport { SearchField } from '../../../components/SearchField';\nimport { PolicyReportsFiltersProvider } from '../../../hooks/usePolicyReportsFilters';\nimport { FilterLayout } from '../../../components/FilterLayout';\nimport { MissingKubernetesCluster } from '../../../components/MissingKubernetesCluster';\nimport { Filter } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { ReactNode } from 'react';\n\nexport interface PolicyReporterPoliciesSubPageProps {\n // This naming aligns with the current Backstage catalog page\n initiallySelectedFilter?: Filter;\n // TODO: Could we implement something like this ?\n // columns?: TableColumn<CatalogTableRow>[] | CatalogTableColumnsFunc;\n filters?: ReactNode;\n context: 'namespaced' | 'cluster';\n}\n\nexport const PolicyReporterPoliciesSubPage = (\n props: PolicyReporterPoliciesSubPageProps,\n) => {\n const { initiallySelectedFilter, filters, context } = props;\n const { environments, environmentsLoading } = useEnvironments();\n\n // Loading environments\n if (environmentsLoading) return <Progress />;\n\n // Environment missing\n if (!environments?.length) return <MissingKubernetesCluster />;\n\n return (\n <PolicyReportsFiltersProvider\n defaultEnvironment={environments[0].entityRef}\n context={context}\n defaultFilters={initiallySelectedFilter}\n >\n <FilterLayout>\n <FilterLayout.Filters>\n <SelectEnvironment environments={environments} />\n {filters}\n </FilterLayout.Filters>\n <FilterLayout.Content>\n <Flex direction=\"column\" gap=\"4\">\n <SearchField />\n <PolicyReportsTable emptyContentText=\"No policies found\" />\n </Flex>\n </FilterLayout.Content>\n </FilterLayout>\n </PolicyReportsFiltersProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAqBO,MAAM,6BAAA,GAAgC,CAC3C,KAAA,KACG;AACH,EAAA,MAAM,EAAE,uBAAA,EAAyB,OAAA,EAAS,OAAA,EAAQ,GAAI,KAAA;AACtD,EAAA,MAAM,EAAE,YAAA,EAAc,mBAAA,EAAoB,GAAI,eAAA,EAAgB;AAG9D,EAAA,IAAI,mBAAA,EAAqB,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,CAAA;AAG1C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAA,EAAQ,2BAAQ,wBAAA,EAAA,EAAyB,CAAA;AAE5D,EAAA,uBACE,GAAA;AAAA,IAAC,4BAAA;AAAA,IAAA;AAAA,MACC,kBAAA,EAAoB,YAAA,CAAa,CAAC,CAAA,CAAE,SAAA;AAAA,MACpC,OAAA;AAAA,MACA,cAAA,EAAgB,uBAAA;AAAA,MAEhB,+BAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,YAAA,CAAa,SAAb,EACC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,qBAAkB,YAAA,EAA4B,CAAA;AAAA,UAC9C;AAAA,SAAA,EACH,CAAA;AAAA,wBACA,GAAA,CAAC,aAAa,OAAA,EAAb,EACC,+BAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,GAAA,EAAI,GAAA,EAC3B,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA;AAAA,0BACb,GAAA,CAAC,kBAAA,EAAA,EAAmB,gBAAA,EAAiB,mBAAA,EAAoB;AAAA,SAAA,EAC3D,CAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,6 @@
1
+ import { PolicyReporterPoliciesSubPage } from './PolicyReporterPoliciesSubPage.esm.js';
2
+
3
+
4
+
5
+ export { PolicyReporterPoliciesSubPage };
6
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -1,4 +1,4 @@
1
- import { jsx } from 'react/jsx-runtime';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { ApiBlueprint, fetchApiRef, discoveryApiRef, PageBlueprint, SubPageBlueprint, createRouteRef, createFrontendPlugin } from '@backstage/frontend-plugin-api';
3
3
  import { rootRouteRef } from '../routes.esm.js';
4
4
  import { policyReporterApiRef } from '../api/PolicyReporterClient.esm.js';
@@ -6,6 +6,14 @@ import { DefaultApiClient } from '@kyverno/backstage-plugin-policy-reporter-comm
6
6
  import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
7
7
  import { isPolicyReporterAvailable } from '../utils/annotations.esm.js';
8
8
  import PolicyIcon from '@material-ui/icons/Policy';
9
+ import { Container } from '@backstage/ui';
10
+ import { SelectStatus } from '../components/SelectStatus/SelectStatus.esm.js';
11
+ import { SelectSeverity } from '../components/SelectSeverity/SelectSeverity.esm.js';
12
+ import { SelectNamespace } from '../components/SelectNamespace/SelectNamespace.esm.js';
13
+ import { SelectSource } from '../components/SelectSource/SelectSource.esm.js';
14
+ import { SelectKind } from '../components/SelectKind/SelectKind.esm.js';
15
+ import { SelectCategory } from '../components/SelectCategory/SelectCategory.esm.js';
16
+ import { SelectPolicy } from '../components/SelectPolicy/SelectPolicy.esm.js';
9
17
 
10
18
  const policyReporterApi = ApiBlueprint.make({
11
19
  params: (defineParams) => defineParams({
@@ -25,17 +33,51 @@ const policyReporterPage = PageBlueprint.make({
25
33
  icon: /* @__PURE__ */ jsx(PolicyIcon, {})
26
34
  }
27
35
  });
28
- const policyReporterNamespacedPoliciesPage = SubPageBlueprint.make({
36
+ const policyReporterClusterPoliciesSubPage = SubPageBlueprint.make({
37
+ name: "cluster-policy",
38
+ params: {
39
+ path: "cluster-policies",
40
+ routeRef: createRouteRef(),
41
+ title: "Cluster Policies",
42
+ loader: () => import('./components/PolicyReporterPoliciesSubPage/index.esm.js').then((m) => /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx(
43
+ m.PolicyReporterPoliciesSubPage,
44
+ {
45
+ initiallySelectedFilter: { status: ["fail"] },
46
+ context: "cluster",
47
+ filters: /* @__PURE__ */ jsxs(Fragment, { children: [
48
+ /* @__PURE__ */ jsx(SelectStatus, {}),
49
+ /* @__PURE__ */ jsx(SelectSeverity, {}),
50
+ /* @__PURE__ */ jsx(SelectSource, {}),
51
+ /* @__PURE__ */ jsx(SelectKind, {}),
52
+ /* @__PURE__ */ jsx(SelectCategory, {}),
53
+ /* @__PURE__ */ jsx(SelectPolicy, {})
54
+ ] })
55
+ }
56
+ ) }))
57
+ }
58
+ });
59
+ const policyReporterNamespacedPoliciesSubPage = SubPageBlueprint.make({
29
60
  name: "namespaced-policy",
30
61
  params: {
31
62
  path: "namespaced-policies",
32
63
  routeRef: createRouteRef(),
33
- // TODO: Support configuration of the actual component
34
64
  title: "Namespaced Policies",
35
- loader: () => (
36
- // TODO: Create dedicated PolicyReporterNamespacedPoliciesPage Component
37
- import('../components/PolicyReportsPage/index.esm.js').then((m) => /* @__PURE__ */ jsx(m.PolicyReportsPage, {}))
38
- )
65
+ loader: () => import('./components/PolicyReporterPoliciesSubPage/index.esm.js').then((m) => /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx(
66
+ m.PolicyReporterPoliciesSubPage,
67
+ {
68
+ initiallySelectedFilter: { status: ["fail"] },
69
+ context: "namespaced",
70
+ filters: /* @__PURE__ */ jsxs(Fragment, { children: [
71
+ /* @__PURE__ */ jsx(SelectStatus, {}),
72
+ /* @__PURE__ */ jsx(SelectSeverity, {}),
73
+ /* @__PURE__ */ jsx(SelectNamespace, {}),
74
+ /* @__PURE__ */ jsx(SelectSource, {}),
75
+ /* @__PURE__ */ jsx(SelectKind, {}),
76
+ /* @__PURE__ */ jsx(SelectCategory, {}),
77
+ /* @__PURE__ */ jsx(SelectPolicy, {})
78
+ ] })
79
+ }
80
+ ) }))
39
81
  }
40
82
  });
41
83
  const policyReporterEntityContent = EntityContentBlueprint.make({
@@ -62,7 +104,8 @@ var plugin = createFrontendPlugin({
62
104
  policyReporterApi,
63
105
  policyReporterEntityContent,
64
106
  policyReporterPage,
65
- policyReporterNamespacedPoliciesPage
107
+ policyReporterNamespacedPoliciesSubPage,
108
+ policyReporterClusterPoliciesSubPage
66
109
  ]
67
110
  });
68
111
 
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../../src/alpha/plugin.tsx"],"sourcesContent":["import {\n ApiBlueprint,\n createFrontendPlugin,\n createRouteRef,\n discoveryApiRef,\n fetchApiRef,\n PageBlueprint,\n SubPageBlueprint,\n} from '@backstage/frontend-plugin-api';\n\nimport { rootRouteRef } from '../routes';\nimport { policyReporterApiRef } from '../api';\nimport { DefaultApiClient } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport { isPolicyReporterAvailable } from '../utils/annotations';\nimport PolicyIcon from '@material-ui/icons/Policy';\n\n/** @alpha */\nexport const policyReporterApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: policyReporterApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new DefaultApiClient({ discoveryApi, fetchApi }),\n }),\n});\n\n/** @alpha */\nconst policyReporterPage = PageBlueprint.make({\n params: {\n path: '/policy-reporter',\n routeRef: rootRouteRef,\n title: 'Policy Reporter',\n icon: <PolicyIcon />,\n },\n});\n\n/** @alpha */\nconst policyReporterNamespacedPoliciesPage = SubPageBlueprint.make({\n name: 'namespaced-policy',\n params: {\n path: 'namespaced-policies',\n routeRef: createRouteRef(),\n // TODO: Support configuration of the actual component\n title: 'Namespaced Policies',\n loader: () =>\n // TODO: Create dedicated PolicyReporterNamespacedPoliciesPage Component\n import('../components/PolicyReportsPage/').then(m => (\n <m.PolicyReportsPage /> // TODO: Update the PolicyReportsPage to be only used for old frontend system to mimic PageBlueprint from NFS\n )),\n },\n});\n\n/** @alpha */\nconst policyReporterEntityContent = EntityContentBlueprint.make({\n name: 'policy-reporter',\n params: {\n path: '/policy-reporter',\n title: 'Policy Reporter',\n // TODO: Support configuration of the actual component\n filter: isPolicyReporterAvailable,\n loader: () =>\n // TODO: Create dedicated EntityPolicyReporterContent component as replacement for Kyverno and Custom content components\n import('../components/EntityKyvernoPoliciesContent/').then(m => (\n <m.EntityKyvernoPoliciesContent />\n )),\n },\n});\n\n/** @alpha */\nexport default createFrontendPlugin({\n pluginId: 'policy-reporter',\n title: 'Policy Reporter',\n info: { packageJson: () => import('../../package.json') },\n routes: {\n root: rootRouteRef,\n },\n extensions: [\n policyReporterApi,\n policyReporterEntityContent,\n policyReporterPage,\n policyReporterNamespacedPoliciesPage,\n ],\n});\n"],"names":[],"mappings":";;;;;;;;;AAmBO,MAAM,iBAAA,GAAoB,aAAa,IAAA,CAAK;AAAA,EACjD,MAAA,EAAQ,kBACN,YAAA,CAAa;AAAA,IACX,GAAA,EAAK,oBAAA;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,YAAA,EAAc,eAAA;AAAA,MACd,QAAA,EAAU;AAAA,KACZ;AAAA,IACA,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,QAAA,EAAS,KACjC,IAAI,gBAAA,CAAiB,EAAE,YAAA,EAAc,QAAA,EAAU;AAAA,GAClD;AACL,CAAC;AAGD,MAAM,kBAAA,GAAqB,cAAc,IAAA,CAAK;AAAA,EAC5C,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,kBAAA;AAAA,IACN,QAAA,EAAU,YAAA;AAAA,IACV,KAAA,EAAO,iBAAA;AAAA,IACP,IAAA,sBAAO,UAAA,EAAA,EAAW;AAAA;AAEtB,CAAC,CAAA;AAGD,MAAM,oCAAA,GAAuC,iBAAiB,IAAA,CAAK;AAAA,EACjE,IAAA,EAAM,mBAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,qBAAA;AAAA,IACN,UAAU,cAAA,EAAe;AAAA;AAAA,IAEzB,KAAA,EAAO,qBAAA;AAAA,IACP,MAAA,EAAQ;AAAA;AAAA,MAEN,OAAO,8CAAkC,CAAA,CAAE,IAAA,CAAK,uBAC9C,GAAA,CAAC,CAAA,CAAE,iBAAA,EAAF,EAAoB,CACtB;AAAA;AAAA;AAEP,CAAC,CAAA;AAGD,MAAM,2BAAA,GAA8B,uBAAuB,IAAA,CAAK;AAAA,EAC9D,IAAA,EAAM,iBAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,kBAAA;AAAA,IACN,KAAA,EAAO,iBAAA;AAAA;AAAA,IAEP,MAAA,EAAQ,yBAAA;AAAA,IACR,MAAA,EAAQ;AAAA;AAAA,MAEN,OAAO,yDAA6C,CAAA,CAAE,IAAA,CAAK,uBACzD,GAAA,CAAC,CAAA,CAAE,4BAAA,EAAF,EAA+B,CACjC;AAAA;AAAA;AAEP,CAAC,CAAA;AAGD,aAAe,oBAAA,CAAqB;AAAA,EAClC,QAAA,EAAU,iBAAA;AAAA,EACV,KAAA,EAAO,iBAAA;AAAA,EACP,MAAM,EAAE,WAAA,EAAa,MAAM,OAAO,wBAAoB,CAAA,EAAE;AAAA,EACxD,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA,GACR;AAAA,EACA,UAAA,EAAY;AAAA,IACV,iBAAA;AAAA,IACA,2BAAA;AAAA,IACA,kBAAA;AAAA,IACA;AAAA;AAEJ,CAAC,CAAA;;;;"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../../src/alpha/plugin.tsx"],"sourcesContent":["import {\n ApiBlueprint,\n createFrontendPlugin,\n createRouteRef,\n discoveryApiRef,\n fetchApiRef,\n PageBlueprint,\n SubPageBlueprint,\n} from '@backstage/frontend-plugin-api';\n\nimport { rootRouteRef } from '../routes';\nimport { policyReporterApiRef } from '../api';\nimport { DefaultApiClient } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport { isPolicyReporterAvailable } from '../utils/annotations';\nimport PolicyIcon from '@material-ui/icons/Policy';\nimport { Container } from '@backstage/ui';\nimport { SelectStatus } from '../components/SelectStatus';\nimport { SelectSeverity } from '../components/SelectSeverity';\nimport { SelectNamespace } from '../components/SelectNamespace';\nimport { SelectSource } from '../components/SelectSource';\nimport { SelectKind } from '../components/SelectKind';\nimport { SelectCategory } from '../components/SelectCategory';\nimport { SelectPolicy } from '../components/SelectPolicy';\n\n/** @alpha */\nexport const policyReporterApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: policyReporterApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new DefaultApiClient({ discoveryApi, fetchApi }),\n }),\n});\n\n/** @alpha */\nconst policyReporterPage = PageBlueprint.make({\n params: {\n path: '/policy-reporter',\n routeRef: rootRouteRef,\n title: 'Policy Reporter',\n icon: <PolicyIcon />,\n },\n});\n\n/** @alpha */\nconst policyReporterClusterPoliciesSubPage = SubPageBlueprint.make({\n name: 'cluster-policy',\n params: {\n path: 'cluster-policies',\n routeRef: createRouteRef(),\n title: 'Cluster Policies',\n loader: () =>\n import('./components/PolicyReporterPoliciesSubPage').then(m => (\n <Container>\n <m.PolicyReporterPoliciesSubPage\n // TODO: Add support for configuring initiallySelectedFilter using NFS\n initiallySelectedFilter={{ status: ['fail'] }}\n context=\"cluster\"\n // TODO: Add support for configuring filters using NFS blueprint/extension\n filters={\n <>\n <SelectStatus />\n <SelectSeverity />\n <SelectSource />\n <SelectKind />\n <SelectCategory />\n <SelectPolicy />\n </>\n }\n />\n </Container>\n )),\n },\n});\n\n/** @alpha */\nconst policyReporterNamespacedPoliciesSubPage = SubPageBlueprint.make({\n name: 'namespaced-policy',\n params: {\n path: 'namespaced-policies',\n routeRef: createRouteRef(),\n title: 'Namespaced Policies',\n loader: () =>\n import('./components/PolicyReporterPoliciesSubPage').then(m => (\n <Container>\n <m.PolicyReporterPoliciesSubPage\n // TODO: Add support for configuring initiallySelectedFilter using NFS\n initiallySelectedFilter={{ status: ['fail'] }}\n context=\"namespaced\"\n // TODO: Add support for configuring filters using NFS blueprint/extension\n filters={\n <>\n <SelectStatus />\n <SelectSeverity />\n <SelectNamespace />\n <SelectSource />\n <SelectKind />\n <SelectCategory />\n <SelectPolicy />\n </>\n }\n />\n </Container>\n )),\n },\n});\n\n/** @alpha */\nconst policyReporterEntityContent = EntityContentBlueprint.make({\n name: 'policy-reporter',\n params: {\n path: '/policy-reporter',\n title: 'Policy Reporter',\n // TODO: Support configuration of the actual component\n filter: isPolicyReporterAvailable,\n loader: () =>\n // TODO: Create dedicated EntityPolicyReporterContent component as replacement for Kyverno and Custom content components\n import('../components/EntityKyvernoPoliciesContent/').then(m => (\n <m.EntityKyvernoPoliciesContent />\n )),\n },\n});\n\n/** @alpha */\nexport default createFrontendPlugin({\n pluginId: 'policy-reporter',\n title: 'Policy Reporter',\n info: { packageJson: () => import('../../package.json') },\n routes: {\n root: rootRouteRef,\n },\n extensions: [\n policyReporterApi,\n policyReporterEntityContent,\n policyReporterPage,\n policyReporterNamespacedPoliciesSubPage,\n policyReporterClusterPoliciesSubPage,\n ],\n});\n"],"names":[],"mappings":"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"}
package/dist/alpha.d.ts CHANGED
@@ -99,6 +99,31 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
99
99
  noHeader?: boolean;
100
100
  };
101
101
  }>;
102
+ "sub-page:policy-reporter/cluster-policy": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
103
+ kind: "sub-page";
104
+ name: "cluster-policy";
105
+ config: {
106
+ path: string | undefined;
107
+ title: string | undefined;
108
+ };
109
+ configInput: {
110
+ path?: string | undefined;
111
+ title?: string | undefined;
112
+ };
113
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
114
+ optional: true;
115
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
116
+ optional: true;
117
+ }>;
118
+ inputs: {};
119
+ params: {
120
+ path: string;
121
+ title: string;
122
+ icon?: _backstage_frontend_plugin_api.IconElement;
123
+ loader: () => Promise<JSX.Element>;
124
+ routeRef?: _backstage_frontend_plugin_api.RouteRef;
125
+ };
126
+ }>;
102
127
  "sub-page:policy-reporter/namespaced-policy": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
103
128
  kind: "sub-page";
104
129
  name: "namespaced-policy";
@@ -47,6 +47,7 @@ const EntityCustomPoliciesContent = ({
47
47
  search: getResourceName(annotations)
48
48
  },
49
49
  defaultEnvironment: environments[0].entityRef,
50
+ context: "namespaced",
50
51
  children: /* @__PURE__ */ jsxs(Container, { children: [
51
52
  /* @__PURE__ */ jsx(
52
53
  Header,
@@ -1 +1 @@
1
- {"version":3,"file":"EntityCustomPoliciesContent.esm.js","sources":["../../../src/components/EntityCustomPoliciesContent/EntityCustomPoliciesContent.tsx"],"sourcesContent":["import { Content, Progress } from '@backstage/core-components';\nimport {\n MissingAnnotationEmptyState,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Container, Header } from '@backstage/ui';\nimport { PolicyReportsTable } from '../PolicyReportsTable';\nimport { SelectEnvironment } from '../SelectEnvironment';\nimport {\n getKinds,\n getNamespaces,\n getResourceName,\n isPolicyReporterAvailable,\n} from '../../utils/annotations';\nimport { MissingEnvironmentsEmptyState } from '../MissingEnvironmentsEmptyState';\nimport { useEntityEnvironment } from '../../hooks/useEntityEnvironment';\nimport { PolicyReportsFiltersProvider } from '../../hooks/usePolicyReportsFilters';\nimport { KYVERNO_RESOURCE_NAME_ANNOTATION } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { SelectStatus } from '../SelectStatus';\nimport { SelectSeverity } from '../SelectSeverity';\nimport { FilterLayout } from '../FilterLayout';\n\ntype EntityCustomPoliciesContentProps = {\n annotationsDocumentationUrl?: string;\n policyDocumentationUrl?: string;\n sources: string[];\n title: string;\n};\n\nexport const EntityCustomPoliciesContent = ({\n annotationsDocumentationUrl,\n policyDocumentationUrl,\n sources,\n title,\n}: EntityCustomPoliciesContentProps) => {\n const { entity } = useEntity();\n const annotations = entity.metadata.annotations;\n\n const annotationsState = isPolicyReporterAvailable(entity);\n\n const { environments, environmentsLoading } = useEntityEnvironment(\n entity,\n annotationsState,\n );\n\n // Annotations missing\n if (!annotationsState)\n return (\n <Container>\n <Content>\n <MissingAnnotationEmptyState\n readMoreUrl={annotationsDocumentationUrl}\n annotation={KYVERNO_RESOURCE_NAME_ANNOTATION}\n />\n </Content>\n </Container>\n );\n\n // Fetching environments\n if (environmentsLoading) return <Progress />;\n\n // Environments missing\n if (!environments?.length)\n return (\n <Container>\n <Content>\n <MissingEnvironmentsEmptyState entity={entity} />\n </Content>\n </Container>\n );\n\n return (\n <PolicyReportsFiltersProvider\n defaultFilters={{\n namespaces: getNamespaces(annotations),\n kinds: getKinds(annotations),\n sources: sources,\n search: getResourceName(annotations),\n }}\n defaultEnvironment={environments[0].entityRef}\n >\n <Container>\n <Header\n title={title}\n customActions={<SelectEnvironment environments={environments} />}\n />\n <Content>\n <FilterLayout>\n <FilterLayout.Filters>\n <SelectStatus />\n <SelectSeverity />\n </FilterLayout.Filters>\n <FilterLayout.Content>\n <PolicyReportsTable\n emptyContentText=\"No policies\"\n policyDocumentationUrl={policyDocumentationUrl}\n />\n </FilterLayout.Content>\n </FilterLayout>\n </Content>\n </Container>\n </PolicyReportsFiltersProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AA6BO,MAAM,8BAA8B,CAAC;AAAA,EAC1C,2BAAA;AAAA,EACA,sBAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,KAAwC;AACtC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,CAAS,WAAA;AAEpC,EAAA,MAAM,gBAAA,GAAmB,0BAA0B,MAAM,CAAA;AAEzD,EAAA,MAAM,EAAE,YAAA,EAAc,mBAAA,EAAoB,GAAI,oBAAA;AAAA,IAC5C,MAAA;AAAA,IACA;AAAA,GACF;AAGA,EAAA,IAAI,CAAC,gBAAA;AACH,IAAA,uBACE,GAAA,CAAC,SAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,MAAC,2BAAA;AAAA,MAAA;AAAA,QACC,WAAA,EAAa,2BAAA;AAAA,QACb,UAAA,EAAY;AAAA;AAAA,OAEhB,CAAA,EACF,CAAA;AAIJ,EAAA,IAAI,mBAAA,EAAqB,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,CAAA;AAG1C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAA;AACjB,IAAA,uBACE,GAAA,CAAC,aACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,8BAAC,6BAAA,EAAA,EAA8B,MAAA,EAAgB,GACjD,CAAA,EACF,CAAA;AAGJ,EAAA,uBACE,GAAA;AAAA,IAAC,4BAAA;AAAA,IAAA;AAAA,MACC,cAAA,EAAgB;AAAA,QACd,UAAA,EAAY,cAAc,WAAW,CAAA;AAAA,QACrC,KAAA,EAAO,SAAS,WAAW,CAAA;AAAA,QAC3B,OAAA;AAAA,QACA,MAAA,EAAQ,gBAAgB,WAAW;AAAA,OACrC;AAAA,MACA,kBAAA,EAAoB,YAAA,CAAa,CAAC,CAAA,CAAE,SAAA;AAAA,MAEpC,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,aAAA,kBAAe,GAAA,CAAC,iBAAA,EAAA,EAAkB,YAAA,EAA4B;AAAA;AAAA,SAChE;AAAA,wBACA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,YAAA,CAAa,SAAb,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,cAAA,EAAA,EAAe;AAAA,WAAA,EAClB,CAAA;AAAA,0BACA,GAAA,CAAC,YAAA,CAAa,OAAA,EAAb,EACC,QAAA,kBAAA,GAAA;AAAA,YAAC,kBAAA;AAAA,YAAA;AAAA,cACC,gBAAA,EAAiB,aAAA;AAAA,cACjB;AAAA;AAAA,WACF,EACF;AAAA,SAAA,EACF,CAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
1
+ {"version":3,"file":"EntityCustomPoliciesContent.esm.js","sources":["../../../src/components/EntityCustomPoliciesContent/EntityCustomPoliciesContent.tsx"],"sourcesContent":["import { Content, Progress } from '@backstage/core-components';\nimport {\n MissingAnnotationEmptyState,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Container, Header } from '@backstage/ui';\nimport { PolicyReportsTable } from '../PolicyReportsTable';\nimport { SelectEnvironment } from '../SelectEnvironment';\nimport {\n getKinds,\n getNamespaces,\n getResourceName,\n isPolicyReporterAvailable,\n} from '../../utils/annotations';\nimport { MissingEnvironmentsEmptyState } from '../MissingEnvironmentsEmptyState';\nimport { useEntityEnvironment } from '../../hooks/useEntityEnvironment';\nimport { PolicyReportsFiltersProvider } from '../../hooks/usePolicyReportsFilters';\nimport { KYVERNO_RESOURCE_NAME_ANNOTATION } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { SelectStatus } from '../SelectStatus';\nimport { SelectSeverity } from '../SelectSeverity';\nimport { FilterLayout } from '../FilterLayout';\n\ntype EntityCustomPoliciesContentProps = {\n annotationsDocumentationUrl?: string;\n policyDocumentationUrl?: string;\n sources: string[];\n title: string;\n};\n\nexport const EntityCustomPoliciesContent = ({\n annotationsDocumentationUrl,\n policyDocumentationUrl,\n sources,\n title,\n}: EntityCustomPoliciesContentProps) => {\n const { entity } = useEntity();\n const annotations = entity.metadata.annotations;\n\n const annotationsState = isPolicyReporterAvailable(entity);\n\n const { environments, environmentsLoading } = useEntityEnvironment(\n entity,\n annotationsState,\n );\n\n // Annotations missing\n if (!annotationsState)\n return (\n <Container>\n <Content>\n <MissingAnnotationEmptyState\n readMoreUrl={annotationsDocumentationUrl}\n annotation={KYVERNO_RESOURCE_NAME_ANNOTATION}\n />\n </Content>\n </Container>\n );\n\n // Fetching environments\n if (environmentsLoading) return <Progress />;\n\n // Environments missing\n if (!environments?.length)\n return (\n <Container>\n <Content>\n <MissingEnvironmentsEmptyState entity={entity} />\n </Content>\n </Container>\n );\n\n return (\n <PolicyReportsFiltersProvider\n defaultFilters={{\n namespaces: getNamespaces(annotations),\n kinds: getKinds(annotations),\n sources: sources,\n search: getResourceName(annotations),\n }}\n defaultEnvironment={environments[0].entityRef}\n context=\"namespaced\"\n >\n <Container>\n <Header\n title={title}\n customActions={<SelectEnvironment environments={environments} />}\n />\n <Content>\n <FilterLayout>\n <FilterLayout.Filters>\n <SelectStatus />\n <SelectSeverity />\n </FilterLayout.Filters>\n <FilterLayout.Content>\n <PolicyReportsTable\n emptyContentText=\"No policies\"\n policyDocumentationUrl={policyDocumentationUrl}\n />\n </FilterLayout.Content>\n </FilterLayout>\n </Content>\n </Container>\n </PolicyReportsFiltersProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AA6BO,MAAM,8BAA8B,CAAC;AAAA,EAC1C,2BAAA;AAAA,EACA,sBAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,KAAwC;AACtC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,CAAS,WAAA;AAEpC,EAAA,MAAM,gBAAA,GAAmB,0BAA0B,MAAM,CAAA;AAEzD,EAAA,MAAM,EAAE,YAAA,EAAc,mBAAA,EAAoB,GAAI,oBAAA;AAAA,IAC5C,MAAA;AAAA,IACA;AAAA,GACF;AAGA,EAAA,IAAI,CAAC,gBAAA;AACH,IAAA,uBACE,GAAA,CAAC,SAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,MAAC,2BAAA;AAAA,MAAA;AAAA,QACC,WAAA,EAAa,2BAAA;AAAA,QACb,UAAA,EAAY;AAAA;AAAA,OAEhB,CAAA,EACF,CAAA;AAIJ,EAAA,IAAI,mBAAA,EAAqB,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,CAAA;AAG1C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAA;AACjB,IAAA,uBACE,GAAA,CAAC,aACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,8BAAC,6BAAA,EAAA,EAA8B,MAAA,EAAgB,GACjD,CAAA,EACF,CAAA;AAGJ,EAAA,uBACE,GAAA;AAAA,IAAC,4BAAA;AAAA,IAAA;AAAA,MACC,cAAA,EAAgB;AAAA,QACd,UAAA,EAAY,cAAc,WAAW,CAAA;AAAA,QACrC,KAAA,EAAO,SAAS,WAAW,CAAA;AAAA,QAC3B,OAAA;AAAA,QACA,MAAA,EAAQ,gBAAgB,WAAW;AAAA,OACrC;AAAA,MACA,kBAAA,EAAoB,YAAA,CAAa,CAAC,CAAA,CAAE,SAAA;AAAA,MACpC,OAAA,EAAQ,YAAA;AAAA,MAER,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,aAAA,kBAAe,GAAA,CAAC,iBAAA,EAAA,EAAkB,YAAA,EAA4B;AAAA;AAAA,SAChE;AAAA,wBACA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,YAAA,CAAa,SAAb,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,cAAA,EAAA,EAAe;AAAA,WAAA,EAClB,CAAA;AAAA,0BACA,GAAA,CAAC,YAAA,CAAa,OAAA,EAAb,EACC,QAAA,kBAAA,GAAA;AAAA,YAAC,kBAAA;AAAA,YAAA;AAAA,cACC,gBAAA,EAAiB,aAAA;AAAA,cACjB;AAAA;AAAA,WACF,EACF;AAAA,SAAA,EACF,CAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -45,6 +45,7 @@ const EntityKyvernoPoliciesContent = ({
45
45
  search: getResourceName(annotations)
46
46
  },
47
47
  defaultEnvironment: environments[0].entityRef,
48
+ context: "namespaced",
48
49
  children: /* @__PURE__ */ jsxs(Container, { children: [
49
50
  /* @__PURE__ */ jsx(
50
51
  Header,
@@ -1 +1 @@
1
- {"version":3,"file":"EntityKyvernoPoliciesContent.esm.js","sources":["../../../src/components/EntityKyvernoPoliciesContent/EntityKyvernoPoliciesContent.tsx"],"sourcesContent":["import { Content, Progress } from '@backstage/core-components';\nimport {\n MissingAnnotationEmptyState,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Container, Header } from '@backstage/ui';\nimport { PolicyReportsTable } from '../PolicyReportsTable';\nimport { SelectEnvironment } from '../SelectEnvironment';\nimport {\n getKinds,\n getNamespaces,\n getResourceName,\n isPolicyReporterAvailable,\n} from '../../utils/annotations';\nimport { MissingEnvironmentsEmptyState } from '../MissingEnvironmentsEmptyState';\nimport { useEntityEnvironment } from '../../hooks/useEntityEnvironment';\nimport { PolicyReportsFiltersProvider } from '../../hooks/usePolicyReportsFilters';\nimport { KYVERNO_RESOURCE_NAME_ANNOTATION } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { SelectSeverity } from '../SelectSeverity';\nimport { SelectStatus } from '../SelectStatus';\nimport { FilterLayout } from '../FilterLayout';\n\ntype KyvernoPoliciesContentProps = {\n annotationsDocumentationUrl?: string;\n policyDocumentationUrl?: string;\n};\n\nexport const EntityKyvernoPoliciesContent = ({\n annotationsDocumentationUrl,\n policyDocumentationUrl,\n}: KyvernoPoliciesContentProps) => {\n const { entity } = useEntity();\n const annotations = entity.metadata.annotations;\n\n const annotationsState = isPolicyReporterAvailable(entity);\n\n const { environments, environmentsLoading } = useEntityEnvironment(\n entity,\n annotationsState,\n );\n\n // Annotations missing\n if (!annotationsState)\n return (\n <Container>\n <Content>\n <MissingAnnotationEmptyState\n readMoreUrl={annotationsDocumentationUrl}\n annotation={KYVERNO_RESOURCE_NAME_ANNOTATION}\n />\n </Content>\n </Container>\n );\n\n // Fetching environments\n if (environmentsLoading) return <Progress />;\n\n // Environments missing\n if (!environments?.length)\n return (\n <Container>\n <Content>\n <MissingEnvironmentsEmptyState entity={entity} />\n </Content>\n </Container>\n );\n\n return (\n <PolicyReportsFiltersProvider\n defaultFilters={{\n namespaces: getNamespaces(annotations),\n kinds: getKinds(annotations),\n sources: ['kyverno'],\n search: getResourceName(annotations),\n }}\n defaultEnvironment={environments[0].entityRef}\n >\n <Container>\n <Header\n title=\"Kyverno Policy Reports\"\n customActions={<SelectEnvironment environments={environments} />}\n />\n <Content>\n <FilterLayout>\n <FilterLayout.Filters>\n <SelectStatus />\n <SelectSeverity />\n </FilterLayout.Filters>\n <FilterLayout.Content>\n <PolicyReportsTable\n emptyContentText=\"No policies found\"\n policyDocumentationUrl={policyDocumentationUrl}\n />\n </FilterLayout.Content>\n </FilterLayout>\n </Content>\n </Container>\n </PolicyReportsFiltersProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AA2BO,MAAM,+BAA+B,CAAC;AAAA,EAC3C,2BAAA;AAAA,EACA;AACF,CAAA,KAAmC;AACjC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,CAAS,WAAA;AAEpC,EAAA,MAAM,gBAAA,GAAmB,0BAA0B,MAAM,CAAA;AAEzD,EAAA,MAAM,EAAE,YAAA,EAAc,mBAAA,EAAoB,GAAI,oBAAA;AAAA,IAC5C,MAAA;AAAA,IACA;AAAA,GACF;AAGA,EAAA,IAAI,CAAC,gBAAA;AACH,IAAA,uBACE,GAAA,CAAC,SAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,MAAC,2BAAA;AAAA,MAAA;AAAA,QACC,WAAA,EAAa,2BAAA;AAAA,QACb,UAAA,EAAY;AAAA;AAAA,OAEhB,CAAA,EACF,CAAA;AAIJ,EAAA,IAAI,mBAAA,EAAqB,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,CAAA;AAG1C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAA;AACjB,IAAA,uBACE,GAAA,CAAC,aACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,8BAAC,6BAAA,EAAA,EAA8B,MAAA,EAAgB,GACjD,CAAA,EACF,CAAA;AAGJ,EAAA,uBACE,GAAA;AAAA,IAAC,4BAAA;AAAA,IAAA;AAAA,MACC,cAAA,EAAgB;AAAA,QACd,UAAA,EAAY,cAAc,WAAW,CAAA;AAAA,QACrC,KAAA,EAAO,SAAS,WAAW,CAAA;AAAA,QAC3B,OAAA,EAAS,CAAC,SAAS,CAAA;AAAA,QACnB,MAAA,EAAQ,gBAAgB,WAAW;AAAA,OACrC;AAAA,MACA,kBAAA,EAAoB,YAAA,CAAa,CAAC,CAAA,CAAE,SAAA;AAAA,MAEpC,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,wBAAA;AAAA,YACN,aAAA,kBAAe,GAAA,CAAC,iBAAA,EAAA,EAAkB,YAAA,EAA4B;AAAA;AAAA,SAChE;AAAA,wBACA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,YAAA,CAAa,SAAb,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,cAAA,EAAA,EAAe;AAAA,WAAA,EAClB,CAAA;AAAA,0BACA,GAAA,CAAC,YAAA,CAAa,OAAA,EAAb,EACC,QAAA,kBAAA,GAAA;AAAA,YAAC,kBAAA;AAAA,YAAA;AAAA,cACC,gBAAA,EAAiB,mBAAA;AAAA,cACjB;AAAA;AAAA,WACF,EACF;AAAA,SAAA,EACF,CAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
1
+ {"version":3,"file":"EntityKyvernoPoliciesContent.esm.js","sources":["../../../src/components/EntityKyvernoPoliciesContent/EntityKyvernoPoliciesContent.tsx"],"sourcesContent":["import { Content, Progress } from '@backstage/core-components';\nimport {\n MissingAnnotationEmptyState,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Container, Header } from '@backstage/ui';\nimport { PolicyReportsTable } from '../PolicyReportsTable';\nimport { SelectEnvironment } from '../SelectEnvironment';\nimport {\n getKinds,\n getNamespaces,\n getResourceName,\n isPolicyReporterAvailable,\n} from '../../utils/annotations';\nimport { MissingEnvironmentsEmptyState } from '../MissingEnvironmentsEmptyState';\nimport { useEntityEnvironment } from '../../hooks/useEntityEnvironment';\nimport { PolicyReportsFiltersProvider } from '../../hooks/usePolicyReportsFilters';\nimport { KYVERNO_RESOURCE_NAME_ANNOTATION } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { SelectSeverity } from '../SelectSeverity';\nimport { SelectStatus } from '../SelectStatus';\nimport { FilterLayout } from '../FilterLayout';\n\ntype KyvernoPoliciesContentProps = {\n annotationsDocumentationUrl?: string;\n policyDocumentationUrl?: string;\n};\n\nexport const EntityKyvernoPoliciesContent = ({\n annotationsDocumentationUrl,\n policyDocumentationUrl,\n}: KyvernoPoliciesContentProps) => {\n const { entity } = useEntity();\n const annotations = entity.metadata.annotations;\n\n const annotationsState = isPolicyReporterAvailable(entity);\n\n const { environments, environmentsLoading } = useEntityEnvironment(\n entity,\n annotationsState,\n );\n\n // Annotations missing\n if (!annotationsState)\n return (\n <Container>\n <Content>\n <MissingAnnotationEmptyState\n readMoreUrl={annotationsDocumentationUrl}\n annotation={KYVERNO_RESOURCE_NAME_ANNOTATION}\n />\n </Content>\n </Container>\n );\n\n // Fetching environments\n if (environmentsLoading) return <Progress />;\n\n // Environments missing\n if (!environments?.length)\n return (\n <Container>\n <Content>\n <MissingEnvironmentsEmptyState entity={entity} />\n </Content>\n </Container>\n );\n\n return (\n <PolicyReportsFiltersProvider\n defaultFilters={{\n namespaces: getNamespaces(annotations),\n kinds: getKinds(annotations),\n sources: ['kyverno'],\n search: getResourceName(annotations),\n }}\n defaultEnvironment={environments[0].entityRef}\n context=\"namespaced\"\n >\n <Container>\n <Header\n title=\"Kyverno Policy Reports\"\n customActions={<SelectEnvironment environments={environments} />}\n />\n <Content>\n <FilterLayout>\n <FilterLayout.Filters>\n <SelectStatus />\n <SelectSeverity />\n </FilterLayout.Filters>\n <FilterLayout.Content>\n <PolicyReportsTable\n emptyContentText=\"No policies found\"\n policyDocumentationUrl={policyDocumentationUrl}\n />\n </FilterLayout.Content>\n </FilterLayout>\n </Content>\n </Container>\n </PolicyReportsFiltersProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AA2BO,MAAM,+BAA+B,CAAC;AAAA,EAC3C,2BAAA;AAAA,EACA;AACF,CAAA,KAAmC;AACjC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,CAAS,WAAA;AAEpC,EAAA,MAAM,gBAAA,GAAmB,0BAA0B,MAAM,CAAA;AAEzD,EAAA,MAAM,EAAE,YAAA,EAAc,mBAAA,EAAoB,GAAI,oBAAA;AAAA,IAC5C,MAAA;AAAA,IACA;AAAA,GACF;AAGA,EAAA,IAAI,CAAC,gBAAA;AACH,IAAA,uBACE,GAAA,CAAC,SAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,MAAC,2BAAA;AAAA,MAAA;AAAA,QACC,WAAA,EAAa,2BAAA;AAAA,QACb,UAAA,EAAY;AAAA;AAAA,OAEhB,CAAA,EACF,CAAA;AAIJ,EAAA,IAAI,mBAAA,EAAqB,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,CAAA;AAG1C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAA;AACjB,IAAA,uBACE,GAAA,CAAC,aACC,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EACC,8BAAC,6BAAA,EAAA,EAA8B,MAAA,EAAgB,GACjD,CAAA,EACF,CAAA;AAGJ,EAAA,uBACE,GAAA;AAAA,IAAC,4BAAA;AAAA,IAAA;AAAA,MACC,cAAA,EAAgB;AAAA,QACd,UAAA,EAAY,cAAc,WAAW,CAAA;AAAA,QACrC,KAAA,EAAO,SAAS,WAAW,CAAA;AAAA,QAC3B,OAAA,EAAS,CAAC,SAAS,CAAA;AAAA,QACnB,MAAA,EAAQ,gBAAgB,WAAW;AAAA,OACrC;AAAA,MACA,kBAAA,EAAoB,YAAA,CAAa,CAAC,CAAA,CAAE,SAAA;AAAA,MACpC,OAAA,EAAQ,YAAA;AAAA,MAER,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,wBAAA;AAAA,YACN,aAAA,kBAAe,GAAA,CAAC,iBAAA,EAAA,EAAkB,YAAA,EAA4B;AAAA;AAAA,SAChE;AAAA,wBACA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,YAAA,CAAa,SAAb,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,cAAA,EAAA,EAAe;AAAA,WAAA,EAClB,CAAA;AAAA,0BACA,GAAA,CAAC,YAAA,CAAa,OAAA,EAAb,EACC,QAAA,kBAAA,GAAA;AAAA,YAAC,kBAAA;AAAA,YAAA;AAAA,cACC,gBAAA,EAAiB,mBAAA;AAAA,cACjB;AAAA;AAAA,WACF,EACF;AAAA,SAAA,EACF,CAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,27 @@
1
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
+ import { EmptyState } from '@backstage/core-components';
3
+ import { ButtonLink } from '@backstage/ui';
4
+
5
+ const MissingKubernetesCluster = () => /* @__PURE__ */ jsx(
6
+ EmptyState,
7
+ {
8
+ missing: "content",
9
+ title: "No kubernetes-cluster Resources found",
10
+ description: /* @__PURE__ */ jsxs(Fragment, { children: [
11
+ "You need to define a Resource with the kubernetes-cluster type and a",
12
+ /* @__PURE__ */ jsx("code", { children: " kyverno.io/endpoint " }),
13
+ " annotation for this plugin to work."
14
+ ] }),
15
+ action: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
16
+ ButtonLink,
17
+ {
18
+ target: "_blank",
19
+ href: "https://github.com/kyverno/backstage-policy-reporter-plugin",
20
+ children: "Read More"
21
+ }
22
+ ) })
23
+ }
24
+ );
25
+
26
+ export { MissingKubernetesCluster };
27
+ //# sourceMappingURL=MissingKubernetesCluster.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MissingKubernetesCluster.esm.js","sources":["../../../src/components/MissingKubernetesCluster/MissingKubernetesCluster.tsx"],"sourcesContent":["import { EmptyState } from '@backstage/core-components';\nimport { ButtonLink } from '@backstage/ui';\n\nexport const MissingKubernetesCluster = () => (\n <EmptyState\n missing=\"content\"\n title=\"No kubernetes-cluster Resources found\"\n description={\n <>\n You need to define a Resource with the kubernetes-cluster type and a\n <code> kyverno.io/endpoint </code> annotation for this plugin to work.\n </>\n }\n action={\n <>\n <ButtonLink\n target=\"_blank\"\n href=\"https://github.com/kyverno/backstage-policy-reporter-plugin\"\n >\n Read More\n </ButtonLink>\n </>\n }\n />\n);\n"],"names":[],"mappings":";;;;AAGO,MAAM,2BAA2B,sBACtC,GAAA;AAAA,EAAC,UAAA;AAAA,EAAA;AAAA,IACC,OAAA,EAAQ,SAAA;AAAA,IACR,KAAA,EAAM,uCAAA;AAAA,IACN,6BACE,IAAA,CAAA,QAAA,EAAA,EAAE,QAAA,EAAA;AAAA,MAAA,sEAAA;AAAA,sBAEA,GAAA,CAAC,UAAK,QAAA,EAAA,uBAAA,EAAqB,CAAA;AAAA,MAAO;AAAA,KAAA,EACpC,CAAA;AAAA,IAEF,wBACE,GAAA,CAAA,QAAA,EAAA,EACE,QAAA,kBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAO,QAAA;AAAA,QACP,IAAA,EAAK,6DAAA;AAAA,QACN,QAAA,EAAA;AAAA;AAAA,KAED,EACF;AAAA;AAEJ;;;;"}
@@ -1,6 +1,6 @@
1
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { Progress, Content, EmptyState } from '@backstage/core-components';
3
- import { Container, Header, ButtonLink, Flex } from '@backstage/ui';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { Progress, Content } from '@backstage/core-components';
3
+ import { Container, Header, Flex } from '@backstage/ui';
4
4
  import { useEnvironments } from '../../hooks/useEnvironments.esm.js';
5
5
  import { SelectEnvironment } from '../SelectEnvironment/SelectEnvironment.esm.js';
6
6
  import { PolicyReportsTable } from '../PolicyReportsTable/PolicyReportsTable.esm.js';
@@ -14,6 +14,7 @@ import { SelectSource } from '../SelectSource/SelectSource.esm.js';
14
14
  import { SelectKind } from '../SelectKind/SelectKind.esm.js';
15
15
  import { SelectCategory } from '../SelectCategory/SelectCategory.esm.js';
16
16
  import { SelectPolicy } from '../SelectPolicy/SelectPolicy.esm.js';
17
+ import { MissingKubernetesCluster } from '../MissingKubernetesCluster/MissingKubernetesCluster.esm.js';
17
18
 
18
19
  const PolicyReportsPage = ({
19
20
  title = "Policy Reports",
@@ -28,30 +29,12 @@ const PolicyReportsPage = ({
28
29
  if (!environments?.length)
29
30
  return /* @__PURE__ */ jsxs(Container, { children: [
30
31
  /* @__PURE__ */ jsx(Header, { title }),
31
- /* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(
32
- EmptyState,
33
- {
34
- missing: "content",
35
- title: "No kubernetes-cluster Resources found",
36
- description: /* @__PURE__ */ jsxs(Fragment, { children: [
37
- "You need to define a Resource with the kubernetes-cluster type and a",
38
- /* @__PURE__ */ jsx("code", { children: " kyverno.io/endpoint " }),
39
- " annotation for this plugin to work."
40
- ] }),
41
- action: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
42
- ButtonLink,
43
- {
44
- target: "_blank",
45
- href: "https://github.com/kyverno/backstage-policy-reporter-plugin",
46
- children: "Read More"
47
- }
48
- ) })
49
- }
50
- ) })
32
+ /* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(MissingKubernetesCluster, {}) })
51
33
  ] });
52
34
  return /* @__PURE__ */ jsx(
53
35
  PolicyReportsFiltersProvider,
54
36
  {
37
+ context: "namespaced",
55
38
  defaultFilters: defaultFilter,
56
39
  defaultEnvironment: environments[0].entityRef,
57
40
  children: /* @__PURE__ */ jsxs(Container, { children: [
@@ -1 +1 @@
1
- {"version":3,"file":"PolicyReportsPage.esm.js","sources":["../../../src/components/PolicyReportsPage/PolicyReportsPage.tsx"],"sourcesContent":["import { Content, EmptyState, Progress } from '@backstage/core-components';\nimport { Container, Flex, Header, ButtonLink } from '@backstage/ui';\nimport { useEnvironments } from '../../hooks/useEnvironments';\nimport { SelectEnvironment } from '../SelectEnvironment';\nimport { PolicyReportsTable } from '../PolicyReportsTable';\nimport { SelectStatus } from '../SelectStatus';\nimport { SelectSeverity } from '../SelectSeverity';\nimport { SelectNamespace } from '../SelectNamespace';\nimport { SearchField } from '../SearchField';\nimport { PolicyReportsFiltersProvider } from '../../hooks/usePolicyReportsFilters';\nimport { Filter } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { FilterLayout } from '../FilterLayout';\nimport { SelectSource } from '../SelectSource';\nimport { SelectKind } from '../SelectKind';\nimport { SelectCategory } from '../SelectCategory';\nimport { SelectPolicy } from '../SelectPolicy';\n\nexport interface PolicyReportsPageProps {\n title?: string;\n policyDocumentationUrl?: string;\n subtitle?: string;\n}\n\nexport const PolicyReportsPage = ({\n title = 'Policy Reports',\n policyDocumentationUrl,\n subtitle,\n}: PolicyReportsPageProps) => {\n const { environments, environmentsLoading } = useEnvironments();\n\n const defaultFilter: Filter = {\n status: ['fail'],\n };\n\n // Loading environments\n if (environmentsLoading) return <Progress />;\n\n // Environments missing\n if (!environments?.length)\n return (\n <Container>\n <Header title={title} />\n <Content>\n <EmptyState\n missing=\"content\"\n title=\"No kubernetes-cluster Resources found\"\n description={\n <>\n You need to define a Resource with the kubernetes-cluster type\n and a<code> kyverno.io/endpoint </code> annotation for this\n plugin to work.\n </>\n }\n action={\n <>\n <ButtonLink\n target=\"_blank\"\n href=\"https://github.com/kyverno/backstage-policy-reporter-plugin\"\n >\n Read More\n </ButtonLink>\n </>\n }\n />\n </Content>\n </Container>\n );\n\n return (\n <PolicyReportsFiltersProvider\n defaultFilters={defaultFilter}\n defaultEnvironment={environments[0].entityRef}\n >\n <Container>\n <Header\n title={title}\n description={subtitle}\n customActions={<SelectEnvironment environments={environments} />}\n />\n <Content>\n <FilterLayout>\n <FilterLayout.Filters>\n <SelectStatus />\n <SelectSeverity />\n <SelectNamespace />\n <SelectSource />\n <SelectKind />\n <SelectCategory />\n <SelectPolicy />\n </FilterLayout.Filters>\n <FilterLayout.Content>\n <Flex direction=\"column\" gap=\"4\">\n <SearchField />\n <PolicyReportsTable\n emptyContentText=\"No policies found\"\n policyDocumentationUrl={policyDocumentationUrl}\n />\n </Flex>\n </FilterLayout.Content>\n </FilterLayout>\n </Content>\n </Container>\n </PolicyReportsFiltersProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAuBO,MAAM,oBAAoB,CAAC;AAAA,EAChC,KAAA,GAAQ,gBAAA;AAAA,EACR,sBAAA;AAAA,EACA;AACF,CAAA,KAA8B;AAC5B,EAAA,MAAM,EAAE,YAAA,EAAc,mBAAA,EAAoB,GAAI,eAAA,EAAgB;AAE9D,EAAA,MAAM,aAAA,GAAwB;AAAA,IAC5B,MAAA,EAAQ,CAAC,MAAM;AAAA,GACjB;AAGA,EAAA,IAAI,mBAAA,EAAqB,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,CAAA;AAG1C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAA;AACjB,IAAA,4BACG,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,UAAO,KAAA,EAAc,CAAA;AAAA,0BACrB,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAQ,SAAA;AAAA,UACR,KAAA,EAAM,uCAAA;AAAA,UACN,6BACE,IAAA,CAAA,QAAA,EAAA,EAAE,QAAA,EAAA;AAAA,YAAA,sEAAA;AAAA,4BAEK,GAAA,CAAC,UAAK,QAAA,EAAA,uBAAA,EAAqB,CAAA;AAAA,YAAO;AAAA,WAAA,EAEzC,CAAA;AAAA,UAEF,wBACE,GAAA,CAAA,QAAA,EAAA,EACE,QAAA,kBAAA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,MAAA,EAAO,QAAA;AAAA,cACP,IAAA,EAAK,6DAAA;AAAA,cACN,QAAA,EAAA;AAAA;AAAA,WAED,EACF;AAAA;AAAA,OAEJ,EACF;AAAA,KAAA,EACF,CAAA;AAGJ,EAAA,uBACE,GAAA;AAAA,IAAC,4BAAA;AAAA,IAAA;AAAA,MACC,cAAA,EAAgB,aAAA;AAAA,MAChB,kBAAA,EAAoB,YAAA,CAAa,CAAC,CAAA,CAAE,SAAA;AAAA,MAEpC,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,WAAA,EAAa,QAAA;AAAA,YACb,aAAA,kBAAe,GAAA,CAAC,iBAAA,EAAA,EAAkB,YAAA,EAA4B;AAAA;AAAA,SAChE;AAAA,wBACA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,YAAA,CAAa,SAAb,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,cAAA,EAAA,EAAe,CAAA;AAAA,gCACf,eAAA,EAAA,EAAgB,CAAA;AAAA,gCAChB,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,UAAA,EAAA,EAAW,CAAA;AAAA,gCACX,cAAA,EAAA,EAAe,CAAA;AAAA,gCACf,YAAA,EAAA,EAAa;AAAA,WAAA,EAChB,CAAA;AAAA,0BACA,GAAA,CAAC,aAAa,OAAA,EAAb,EACC,+BAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,GAAA,EAAI,GAAA,EAC3B,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA;AAAA,4BACb,GAAA;AAAA,cAAC,kBAAA;AAAA,cAAA;AAAA,gBACC,gBAAA,EAAiB,mBAAA;AAAA,gBACjB;AAAA;AAAA;AACF,WAAA,EACF,CAAA,EACF;AAAA,SAAA,EACF,CAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
1
+ {"version":3,"file":"PolicyReportsPage.esm.js","sources":["../../../src/components/PolicyReportsPage/PolicyReportsPage.tsx"],"sourcesContent":["import { Content, Progress } from '@backstage/core-components';\nimport { Container, Flex, Header } from '@backstage/ui';\nimport { useEnvironments } from '../../hooks/useEnvironments';\nimport { SelectEnvironment } from '../SelectEnvironment';\nimport { PolicyReportsTable } from '../PolicyReportsTable';\nimport { SelectStatus } from '../SelectStatus';\nimport { SelectSeverity } from '../SelectSeverity';\nimport { SelectNamespace } from '../SelectNamespace';\nimport { SearchField } from '../SearchField';\nimport { PolicyReportsFiltersProvider } from '../../hooks/usePolicyReportsFilters';\nimport { Filter } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { FilterLayout } from '../FilterLayout';\nimport { SelectSource } from '../SelectSource';\nimport { SelectKind } from '../SelectKind';\nimport { SelectCategory } from '../SelectCategory';\nimport { SelectPolicy } from '../SelectPolicy';\nimport { MissingKubernetesCluster } from '../MissingKubernetesCluster';\n\nexport interface PolicyReportsPageProps {\n title?: string;\n policyDocumentationUrl?: string;\n subtitle?: string;\n}\n\nexport const PolicyReportsPage = ({\n title = 'Policy Reports',\n policyDocumentationUrl,\n subtitle,\n}: PolicyReportsPageProps) => {\n const { environments, environmentsLoading } = useEnvironments();\n\n const defaultFilter: Filter = {\n status: ['fail'],\n };\n\n // Loading environments\n if (environmentsLoading) return <Progress />;\n\n // Environments missing\n if (!environments?.length)\n return (\n <Container>\n <Header title={title} />\n <Content>\n <MissingKubernetesCluster />\n </Content>\n </Container>\n );\n\n return (\n <PolicyReportsFiltersProvider\n context=\"namespaced\"\n defaultFilters={defaultFilter}\n defaultEnvironment={environments[0].entityRef}\n >\n <Container>\n <Header\n title={title}\n description={subtitle}\n customActions={<SelectEnvironment environments={environments} />}\n />\n <Content>\n <FilterLayout>\n <FilterLayout.Filters>\n <SelectStatus />\n <SelectSeverity />\n <SelectNamespace />\n <SelectSource />\n <SelectKind />\n <SelectCategory />\n <SelectPolicy />\n </FilterLayout.Filters>\n <FilterLayout.Content>\n <Flex direction=\"column\" gap=\"4\">\n <SearchField />\n <PolicyReportsTable\n emptyContentText=\"No policies found\"\n policyDocumentationUrl={policyDocumentationUrl}\n />\n </Flex>\n </FilterLayout.Content>\n </FilterLayout>\n </Content>\n </Container>\n </PolicyReportsFiltersProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAwBO,MAAM,oBAAoB,CAAC;AAAA,EAChC,KAAA,GAAQ,gBAAA;AAAA,EACR,sBAAA;AAAA,EACA;AACF,CAAA,KAA8B;AAC5B,EAAA,MAAM,EAAE,YAAA,EAAc,mBAAA,EAAoB,GAAI,eAAA,EAAgB;AAE9D,EAAA,MAAM,aAAA,GAAwB;AAAA,IAC5B,MAAA,EAAQ,CAAC,MAAM;AAAA,GACjB;AAGA,EAAA,IAAI,mBAAA,EAAqB,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAS,CAAA;AAG1C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAA;AACjB,IAAA,4BACG,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,UAAO,KAAA,EAAc,CAAA;AAAA,sBACtB,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,wBAAA,EAAA,EAAyB,CAAA,EAC5B;AAAA,KAAA,EACF,CAAA;AAGJ,EAAA,uBACE,GAAA;AAAA,IAAC,4BAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,YAAA;AAAA,MACR,cAAA,EAAgB,aAAA;AAAA,MAChB,kBAAA,EAAoB,YAAA,CAAa,CAAC,CAAA,CAAE,SAAA;AAAA,MAEpC,+BAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,WAAA,EAAa,QAAA;AAAA,YACb,aAAA,kBAAe,GAAA,CAAC,iBAAA,EAAA,EAAkB,YAAA,EAA4B;AAAA;AAAA,SAChE;AAAA,wBACA,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,YAAA,CAAa,SAAb,EACC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,cAAA,EAAA,EAAe,CAAA;AAAA,gCACf,eAAA,EAAA,EAAgB,CAAA;AAAA,gCAChB,YAAA,EAAA,EAAa,CAAA;AAAA,gCACb,UAAA,EAAA,EAAW,CAAA;AAAA,gCACX,cAAA,EAAA,EAAe,CAAA;AAAA,gCACf,YAAA,EAAA,EAAa;AAAA,WAAA,EAChB,CAAA;AAAA,0BACA,GAAA,CAAC,aAAa,OAAA,EAAb,EACC,+BAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,GAAA,EAAI,GAAA,EAC3B,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA;AAAA,4BACb,GAAA;AAAA,cAAC,kBAAA;AAAA,cAAA;AAAA,gBACC,gBAAA,EAAiB,mBAAA;AAAA,gBACjB;AAAA;AAAA;AACF,WAAA,EACF,CAAA,EACF;AAAA,SAAA,EACF,CAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -14,7 +14,7 @@ const PolicyReportsTable = ({
14
14
  policyDocumentationUrl
15
15
  }) => {
16
16
  const policyReporterApi = useApi(policyReporterApiRef);
17
- const { filter, environment } = usePolicyReportsFilters();
17
+ const { filter, environment, context } = usePolicyReportsFilters();
18
18
  const search = filter.search;
19
19
  const toast = useApi(toastApiRef);
20
20
  const [drawerContent, setDrawerContent] = useState(
@@ -31,7 +31,7 @@ const PolicyReportsTable = ({
31
31
  search: searchParam
32
32
  }) => {
33
33
  const page = Math.floor(offset / pageSize) + 1;
34
- const response = await policyReporterApi.getNamespacedResults({
34
+ const request = {
35
35
  query: {
36
36
  environment: encodeURI(environment),
37
37
  page,
@@ -39,7 +39,8 @@ const PolicyReportsTable = ({
39
39
  ...fetchFilter,
40
40
  search: searchParam === "" ? void 0 : searchParam
41
41
  }
42
- });
42
+ };
43
+ const response = context === "cluster" ? await policyReporterApi.getClusterResults(request) : await policyReporterApi.getNamespacedResults(request);
43
44
  const result = await response.json();
44
45
  if (!response.ok) {
45
46
  toast.post({
@@ -62,12 +63,14 @@ const PolicyReportsTable = ({
62
63
  isRowHeader: true,
63
64
  cell: (item) => /* @__PURE__ */ jsx(CellText, { title: item.name })
64
65
  },
65
- {
66
- id: "namespace",
67
- label: "Namespace",
68
- isRowHeader: true,
69
- cell: (item) => /* @__PURE__ */ jsx(CellText, { title: item.namespace })
70
- },
66
+ ...context === "namespaced" ? [
67
+ {
68
+ id: "namespace",
69
+ label: "Namespace",
70
+ isRowHeader: true,
71
+ cell: (item) => /* @__PURE__ */ jsx(CellText, { title: item.namespace })
72
+ }
73
+ ] : [],
71
74
  {
72
75
  id: "kind",
73
76
  label: "Kind",
@@ -1 +1 @@
1
- {"version":3,"file":"PolicyReportsTable.esm.js","sources":["../../../src/components/PolicyReportsTable/PolicyReportsTable.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n ListResult,\n RequestError,\n} from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { Drawer } from '@material-ui/core';\nimport { StatusComponent } from '../StatusComponent';\nimport { SeverityComponent } from '../SeverityComponent';\nimport { PolicyReportsDrawerComponent } from '../PolicyReportsDrawerComponent';\nimport {\n CellText,\n ColumnConfig,\n Text,\n useTable,\n Table,\n Cell,\n Link,\n} from '@backstage/ui';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { policyReporterApiRef } from '../../api';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\n\ninterface PolicyReportsTableProps {\n emptyContentText: string;\n policyDocumentationUrl?: string;\n}\n\nexport const PolicyReportsTable = ({\n emptyContentText,\n policyDocumentationUrl,\n}: PolicyReportsTableProps) => {\n const policyReporterApi = useApi(policyReporterApiRef);\n const { filter, environment } = usePolicyReportsFilters();\n const search = filter.search;\n const toast = useApi(toastApiRef);\n\n const [drawerContent, setDrawerContent] = useState<ListResult | undefined>(\n undefined,\n );\n\n const { tableProps } = useTable({\n filter,\n mode: 'offset',\n search: search,\n getData: async ({\n offset,\n pageSize,\n filter: fetchFilter,\n search: searchParam,\n }) => {\n // useTable provides:\n // - offset: absolute record position (0, 20, 40, 60...)\n // - pageSize: number of records per page (20)\n //\n // Policy Reporter API expects:\n // - page: page number starting from 1 (1, 2, 3, 4...)\n // - offset: number of results per page (this is actually pageSize)\n //\n // Example calculations:\n // useTable offset=0, pageSize=20 → page=1 (first 20 records)\n // useTable offset=20, pageSize=20 → page=2 (records 21-40)\n // useTable offset=40, pageSize=20 → page=3 (records 41-60)\n\n // Convert useTable's absolute offset to 1-indexed page number\n // Math.floor(0/20) + 1 = 1, Math.floor(20/20) + 1 = 2, etc.\n const page = Math.floor(offset / pageSize) + 1;\n\n const response = await policyReporterApi.getNamespacedResults({\n query: {\n environment: encodeURI(environment),\n page: page,\n offset: pageSize,\n ...fetchFilter,\n search: searchParam === '' ? undefined : searchParam,\n },\n });\n\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch policies',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { data: [], totalCount: 0 };\n }\n\n return {\n data: result.items,\n totalCount: result.count,\n };\n },\n });\n\n const columns: ColumnConfig<ListResult>[] = [\n {\n id: 'name',\n label: 'Name',\n isRowHeader: true,\n cell: item => <CellText title={item.name} />,\n },\n {\n id: 'namespace',\n label: 'Namespace',\n isRowHeader: true,\n cell: item => <CellText title={item.namespace} />,\n },\n {\n id: 'kind',\n label: 'Kind',\n isRowHeader: true,\n cell: item => <CellText title={item.kind} />,\n },\n {\n id: 'policy',\n label: 'Policy',\n isRowHeader: true,\n cell: item => {\n if (policyDocumentationUrl) {\n return (\n <Cell>\n <Link\n target=\"_blank\"\n href={`${policyDocumentationUrl}#${item.policy}`}\n >\n {item.policy}\n </Link>\n </Cell>\n );\n }\n return <CellText title={item.policy} />;\n },\n },\n {\n id: 'rule',\n label: 'Rule',\n isRowHeader: true,\n cell: item => <CellText title={item.rule} />,\n },\n {\n id: 'status',\n label: 'Status',\n isRowHeader: true,\n cell: item => (\n <Cell>\n <StatusComponent status={item.status} />\n </Cell>\n ),\n },\n {\n id: 'severity',\n label: 'Severity',\n isRowHeader: true,\n cell: item => (\n <Cell>\n <SeverityComponent severity={item.severity} />\n </Cell>\n ),\n },\n ];\n\n return (\n <>\n <Drawer\n anchor=\"right\"\n open={Boolean(drawerContent)}\n onClose={() => setDrawerContent(undefined)}\n >\n <PolicyReportsDrawerComponent content={drawerContent} />\n </Drawer>\n <Table\n rowConfig={{\n onClick: item => setDrawerContent(item),\n }}\n emptyState={\n search ? (\n <Text>No results match \"{search}\"</Text>\n ) : (\n <Text>{emptyContentText}</Text>\n )\n }\n columnConfig={columns}\n {...tableProps}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PolicyReportsTable.esm.js","sources":["../../../src/components/PolicyReportsTable/PolicyReportsTable.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n GetClusterResults,\n GetNamespacedResults,\n ListResult,\n RequestError,\n} from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { Drawer } from '@material-ui/core';\nimport { StatusComponent } from '../StatusComponent';\nimport { SeverityComponent } from '../SeverityComponent';\nimport { PolicyReportsDrawerComponent } from '../PolicyReportsDrawerComponent';\nimport {\n CellText,\n ColumnConfig,\n Text,\n useTable,\n Table,\n Cell,\n Link,\n} from '@backstage/ui';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { policyReporterApiRef } from '../../api';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\n\ninterface PolicyReportsTableProps {\n emptyContentText: string;\n policyDocumentationUrl?: string;\n}\n\nexport const PolicyReportsTable = ({\n emptyContentText,\n policyDocumentationUrl,\n}: PolicyReportsTableProps) => {\n const policyReporterApi = useApi(policyReporterApiRef);\n const { filter, environment, context } = usePolicyReportsFilters();\n const search = filter.search;\n const toast = useApi(toastApiRef);\n\n const [drawerContent, setDrawerContent] = useState<ListResult | undefined>(\n undefined,\n );\n\n const { tableProps } = useTable({\n filter,\n mode: 'offset',\n search: search,\n getData: async ({\n offset,\n pageSize,\n filter: fetchFilter,\n search: searchParam,\n }) => {\n // useTable provides:\n // - offset: absolute record position (0, 20, 40, 60...)\n // - pageSize: number of records per page (20)\n //\n // Policy Reporter API expects:\n // - page: page number starting from 1 (1, 2, 3, 4...)\n // - offset: number of results per page (this is actually pageSize)\n //\n // Example calculations:\n // useTable offset=0, pageSize=20 → page=1 (first 20 records)\n // useTable offset=20, pageSize=20 → page=2 (records 21-40)\n // useTable offset=40, pageSize=20 → page=3 (records 41-60)\n\n // Convert useTable's absolute offset to 1-indexed page number\n // Math.floor(0/20) + 1 = 1, Math.floor(20/20) + 1 = 2, etc.\n const page = Math.floor(offset / pageSize) + 1;\n\n const request: GetClusterResults | GetNamespacedResults = {\n query: {\n environment: encodeURI(environment),\n page: page,\n offset: pageSize,\n ...fetchFilter,\n search: searchParam === '' ? undefined : searchParam,\n },\n };\n\n const response =\n context === 'cluster'\n ? await policyReporterApi.getClusterResults(request)\n : await policyReporterApi.getNamespacedResults(request);\n\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch policies',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { data: [], totalCount: 0 };\n }\n\n return {\n data: result.items,\n totalCount: result.count,\n };\n },\n });\n\n const columns: ColumnConfig<ListResult>[] = [\n {\n id: 'name',\n label: 'Name',\n isRowHeader: true,\n cell: item => <CellText title={item.name} />,\n },\n ...(context === 'namespaced'\n ? ([\n {\n id: 'namespace',\n label: 'Namespace',\n isRowHeader: true,\n cell: item => <CellText title={item.namespace} />,\n },\n ] as ColumnConfig<ListResult>[])\n : []),\n {\n id: 'kind',\n label: 'Kind',\n isRowHeader: true,\n cell: item => <CellText title={item.kind} />,\n },\n {\n id: 'policy',\n label: 'Policy',\n isRowHeader: true,\n cell: item => {\n if (policyDocumentationUrl) {\n return (\n <Cell>\n <Link\n target=\"_blank\"\n href={`${policyDocumentationUrl}#${item.policy}`}\n >\n {item.policy}\n </Link>\n </Cell>\n );\n }\n return <CellText title={item.policy} />;\n },\n },\n {\n id: 'rule',\n label: 'Rule',\n isRowHeader: true,\n cell: item => <CellText title={item.rule} />,\n },\n {\n id: 'status',\n label: 'Status',\n isRowHeader: true,\n cell: item => (\n <Cell>\n <StatusComponent status={item.status} />\n </Cell>\n ),\n },\n {\n id: 'severity',\n label: 'Severity',\n isRowHeader: true,\n cell: item => (\n <Cell>\n <SeverityComponent severity={item.severity} />\n </Cell>\n ),\n },\n ];\n\n return (\n <>\n <Drawer\n anchor=\"right\"\n open={Boolean(drawerContent)}\n onClose={() => setDrawerContent(undefined)}\n >\n <PolicyReportsDrawerComponent content={drawerContent} />\n </Drawer>\n <Table\n rowConfig={{\n onClick: item => setDrawerContent(item),\n }}\n emptyState={\n search ? (\n <Text>No results match \"{search}\"</Text>\n ) : (\n <Text>{emptyContentText}</Text>\n )\n }\n columnConfig={columns}\n {...tableProps}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -6,13 +6,14 @@ import { policyReporterApiRef } from '../../api/PolicyReporterClient.esm.js';
6
6
  import { useApi, toastApiRef } from '@backstage/frontend-plugin-api';
7
7
 
8
8
  const SelectCategory = () => {
9
- const { filter, updateFilter, environment } = usePolicyReportsFilters();
9
+ const { filter, updateFilter, environment, context } = usePolicyReportsFilters();
10
10
  const api = useApi(policyReporterApiRef);
11
11
  const toast = useApi(toastApiRef);
12
12
  const categoryOptions = useAsyncList({
13
13
  async load({}) {
14
14
  if (!environment) return { items: [] };
15
- const response = await api.getCategories({ query: { environment } });
15
+ const request = { query: { environment } };
16
+ const response = context === "cluster" ? await api.getClusterCategories(request) : await api.getCategories(request);
16
17
  const result = await response.json();
17
18
  if (!response.ok) {
18
19
  toast.post({
@@ -37,7 +38,7 @@ const SelectCategory = () => {
37
38
  categoryRef.current = categoryOptions;
38
39
  useEffect(() => {
39
40
  categoryRef.current.reload();
40
- }, [environment]);
41
+ }, [environment, context]);
41
42
  const selectedCategories = filter.categories ?? [];
42
43
  const selectedCategoriesRef = useRef(selectedCategories);
43
44
  selectedCategoriesRef.current = selectedCategories;
@@ -1 +1 @@
1
- {"version":3,"file":"SelectCategory.esm.js","sources":["../../../src/components/SelectCategory/SelectCategory.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectCategory = () => {\n const { filter, updateFilter, environment } = usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const categoryOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const response = await api.getCategories({ query: { environment } });\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch categories',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map(c => ({ id: c, label: c })),\n };\n },\n });\n\n const categories = useMemo(() => {\n if (categoryOptions.isLoading || categoryOptions.items.length === 0) {\n return undefined;\n }\n\n return new Set(categoryOptions.items.map(c => c.label));\n }, [categoryOptions.isLoading, categoryOptions.items]);\n\n // useRef to avoid dependency on the useAsyncList result\n const categoryRef = useRef(categoryOptions);\n categoryRef.current = categoryOptions;\n\n // Fetch sources again after changes to the environment\n useEffect(() => {\n categoryRef.current.reload();\n }, [environment]);\n\n const selectedCategories = filter.categories ?? [];\n\n // Keep a ref so the effect can read the latest selection without making it\n // a dependency — the effect should only trigger when available sources change.\n const selectedCategoriesRef = useRef(selectedCategories);\n selectedCategoriesRef.current = selectedCategories;\n\n useEffect(() => {\n if (!categories) return;\n\n const selected = selectedCategoriesRef.current;\n\n if (selected.every(category => categories.has(category))) return;\n\n updateFilter({\n categories: selected.filter(category => categories.has(category)),\n });\n }, [categories, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (key === null) {\n updateFilter({ categories: [] });\n return;\n }\n\n if (!categories) return;\n\n if (!Array.isArray(key)) {\n updateFilter({\n categories: categories.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n categories.has(item as string),\n );\n updateFilter({ categories: filtered });\n };\n\n return (\n <Select\n label=\"Category\"\n selectionMode=\"multiple\"\n options={categoryOptions}\n value={selectedCategories}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelectCategory.esm.js","sources":["../../../src/components/SelectCategory/SelectCategory.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectCategory = () => {\n const { filter, updateFilter, environment, context } =\n usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const categoryOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const request = { query: { environment } };\n const response =\n context === 'cluster'\n ? await api.getClusterCategories(request)\n : await api.getCategories(request);\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch categories',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map(c => ({ id: c, label: c })),\n };\n },\n });\n\n const categories = useMemo(() => {\n if (categoryOptions.isLoading || categoryOptions.items.length === 0) {\n return undefined;\n }\n\n return new Set(categoryOptions.items.map(c => c.label));\n }, [categoryOptions.isLoading, categoryOptions.items]);\n\n // useRef to avoid dependency on the useAsyncList result\n const categoryRef = useRef(categoryOptions);\n categoryRef.current = categoryOptions;\n\n // Fetch sources again after changes to the environment\n useEffect(() => {\n categoryRef.current.reload();\n }, [environment, context]);\n\n const selectedCategories = filter.categories ?? [];\n\n // Keep a ref so the effect can read the latest selection without making it\n // a dependency — the effect should only trigger when available sources change.\n const selectedCategoriesRef = useRef(selectedCategories);\n selectedCategoriesRef.current = selectedCategories;\n\n useEffect(() => {\n if (!categories) return;\n\n const selected = selectedCategoriesRef.current;\n\n if (selected.every(category => categories.has(category))) return;\n\n updateFilter({\n categories: selected.filter(category => categories.has(category)),\n });\n }, [categories, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (key === null) {\n updateFilter({ categories: [] });\n return;\n }\n\n if (!categories) return;\n\n if (!Array.isArray(key)) {\n updateFilter({\n categories: categories.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n categories.has(item as string),\n );\n updateFilter({ categories: filtered });\n };\n\n return (\n <Select\n label=\"Category\"\n selectionMode=\"multiple\"\n options={categoryOptions}\n value={selectedCategories}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
@@ -6,13 +6,14 @@ import { policyReporterApiRef } from '../../api/PolicyReporterClient.esm.js';
6
6
  import { useApi, toastApiRef } from '@backstage/frontend-plugin-api';
7
7
 
8
8
  const SelectKind = () => {
9
- const { filter, updateFilter, environment } = usePolicyReportsFilters();
9
+ const { filter, updateFilter, environment, context } = usePolicyReportsFilters();
10
10
  const api = useApi(policyReporterApiRef);
11
11
  const toast = useApi(toastApiRef);
12
12
  const kindOptions = useAsyncList({
13
13
  async load({}) {
14
14
  if (!environment) return { items: [] };
15
- const response = await api.getKinds({ query: { environment } });
15
+ const request = { query: { environment } };
16
+ const response = context === "cluster" ? await api.getClusterKinds(request) : await api.getKinds(request);
16
17
  const result = await response.json();
17
18
  if (!response.ok) {
18
19
  toast.post({
@@ -37,7 +38,7 @@ const SelectKind = () => {
37
38
  kindRef.current = kindOptions;
38
39
  useEffect(() => {
39
40
  kindRef.current.reload();
40
- }, [environment]);
41
+ }, [environment, context]);
41
42
  const selectedKinds = filter.kinds ?? [];
42
43
  const selectedKindsRef = useRef(selectedKinds);
43
44
  selectedKindsRef.current = selectedKinds;
@@ -1 +1 @@
1
- {"version":3,"file":"SelectKind.esm.js","sources":["../../../src/components/SelectKind/SelectKind.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectKind = () => {\n const { filter, updateFilter, environment } = usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const kindOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const response = await api.getKinds({ query: { environment } });\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch kinds',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map((k: string) => ({ id: k, label: k })),\n };\n },\n });\n\n const kinds = useMemo(() => {\n if (kindOptions.isLoading || kindOptions.items.length === 0) {\n return undefined;\n }\n\n return new Set(kindOptions.items.map(k => k.label));\n }, [kindOptions.isLoading, kindOptions.items]);\n\n const kindRef = useRef(kindOptions);\n kindRef.current = kindOptions;\n\n useEffect(() => {\n kindRef.current.reload();\n }, [environment]);\n\n const selectedKinds = filter.kinds ?? [];\n\n const selectedKindsRef = useRef(selectedKinds);\n selectedKindsRef.current = selectedKinds;\n\n useEffect(() => {\n if (!kinds) return;\n\n const selected = selectedKindsRef.current;\n\n if (selected.every(kind => kinds.has(kind))) return;\n\n updateFilter({\n kinds: selected.filter(kind => kinds.has(kind)),\n });\n }, [kinds, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (key === null) {\n updateFilter({ kinds: [] });\n return;\n }\n\n if (!kinds) return;\n\n if (!Array.isArray(key)) {\n updateFilter({\n kinds: kinds.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n kinds.has(item as string),\n );\n updateFilter({ kinds: filtered });\n };\n\n return (\n <Select\n label=\"Kind\"\n selectionMode=\"multiple\"\n options={kindOptions}\n value={selectedKinds}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelectKind.esm.js","sources":["../../../src/components/SelectKind/SelectKind.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectKind = () => {\n const { filter, updateFilter, environment, context } =\n usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const kindOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const request = { query: { environment } };\n const response =\n context === 'cluster'\n ? await api.getClusterKinds(request)\n : await api.getKinds(request);\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch kinds',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map((k: string) => ({ id: k, label: k })),\n };\n },\n });\n\n const kinds = useMemo(() => {\n if (kindOptions.isLoading || kindOptions.items.length === 0) {\n return undefined;\n }\n\n return new Set(kindOptions.items.map(k => k.label));\n }, [kindOptions.isLoading, kindOptions.items]);\n\n const kindRef = useRef(kindOptions);\n kindRef.current = kindOptions;\n\n useEffect(() => {\n kindRef.current.reload();\n }, [environment, context]);\n\n const selectedKinds = filter.kinds ?? [];\n\n const selectedKindsRef = useRef(selectedKinds);\n selectedKindsRef.current = selectedKinds;\n\n useEffect(() => {\n if (!kinds) return;\n\n const selected = selectedKindsRef.current;\n\n if (selected.every(kind => kinds.has(kind))) return;\n\n updateFilter({\n kinds: selected.filter(kind => kinds.has(kind)),\n });\n }, [kinds, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (key === null) {\n updateFilter({ kinds: [] });\n return;\n }\n\n if (!kinds) return;\n\n if (!Array.isArray(key)) {\n updateFilter({\n kinds: kinds.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n kinds.has(item as string),\n );\n updateFilter({ kinds: filtered });\n };\n\n return (\n <Select\n label=\"Kind\"\n selectionMode=\"multiple\"\n options={kindOptions}\n value={selectedKinds}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
@@ -6,13 +6,14 @@ import { policyReporterApiRef } from '../../api/PolicyReporterClient.esm.js';
6
6
  import { useApi, toastApiRef } from '@backstage/frontend-plugin-api';
7
7
 
8
8
  const SelectPolicy = () => {
9
- const { filter, updateFilter, environment } = usePolicyReportsFilters();
9
+ const { filter, updateFilter, environment, context } = usePolicyReportsFilters();
10
10
  const api = useApi(policyReporterApiRef);
11
11
  const toast = useApi(toastApiRef);
12
12
  const policyOptions = useAsyncList({
13
13
  async load({}) {
14
14
  if (!environment) return { items: [] };
15
- const response = await api.getPolicies({ query: { environment } });
15
+ const request = { query: { environment } };
16
+ const response = context === "cluster" ? await api.getClusterPolicies(request) : await api.getPolicies(request);
16
17
  const result = await response.json();
17
18
  if (!response.ok) {
18
19
  toast.post({
@@ -37,7 +38,7 @@ const SelectPolicy = () => {
37
38
  policyRef.current = policyOptions;
38
39
  useEffect(() => {
39
40
  policyRef.current.reload();
40
- }, [environment]);
41
+ }, [environment, context]);
41
42
  const selectedPolicies = filter.policies ?? [];
42
43
  const selectedPoliciesRef = useRef(selectedPolicies);
43
44
  selectedPoliciesRef.current = selectedPolicies;
@@ -1 +1 @@
1
- {"version":3,"file":"SelectPolicy.esm.js","sources":["../../../src/components/SelectPolicy/SelectPolicy.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectPolicy = () => {\n const { filter, updateFilter, environment } = usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const policyOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const response = await api.getPolicies({ query: { environment } });\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch policies',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map(s => ({ id: s, label: s })),\n };\n },\n });\n\n const policies = useMemo(() => {\n if (policyOptions.isLoading || policyOptions.items.length === 0) {\n return undefined;\n }\n\n return new Set(policyOptions.items.map(s => s.label));\n }, [policyOptions.items, policyOptions.isLoading]);\n\n // useRef to avoid dependency on the useAsyncList result\n const policyRef = useRef(policyOptions);\n policyRef.current = policyOptions;\n\n // Fetch policies again after changes to the environment\n useEffect(() => {\n policyRef.current.reload();\n }, [environment]);\n\n const selectedPolicies = filter.policies ?? [];\n\n // Keep a ref so the effect can read the latest selection without making it\n // a dependency — the effect should only trigger when available policies change.\n const selectedPoliciesRef = useRef(selectedPolicies);\n selectedPoliciesRef.current = selectedPolicies;\n\n useEffect(() => {\n if (!policies) return;\n const selected = selectedPoliciesRef.current;\n\n if (selected.every(policy => policies.has(policy))) return;\n\n updateFilter({\n policies: selected.filter(policy => policies.has(policy)),\n });\n }, [policies, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (!policies) return;\n\n if (key === null) {\n updateFilter({ policies: [] });\n return;\n }\n\n if (!Array.isArray(key)) {\n updateFilter({\n policies: policies.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n policies.has(item as string),\n );\n updateFilter({ policies: filtered });\n };\n\n return (\n <Select\n label=\"Policy\"\n selectionMode=\"multiple\"\n options={policyOptions}\n value={selectedPolicies}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelectPolicy.esm.js","sources":["../../../src/components/SelectPolicy/SelectPolicy.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectPolicy = () => {\n const { filter, updateFilter, environment, context } =\n usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const policyOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const request = { query: { environment } };\n const response =\n context === 'cluster'\n ? await api.getClusterPolicies(request)\n : await api.getPolicies(request);\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch policies',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map(s => ({ id: s, label: s })),\n };\n },\n });\n\n const policies = useMemo(() => {\n if (policyOptions.isLoading || policyOptions.items.length === 0) {\n return undefined;\n }\n\n return new Set(policyOptions.items.map(s => s.label));\n }, [policyOptions.items, policyOptions.isLoading]);\n\n // useRef to avoid dependency on the useAsyncList result\n const policyRef = useRef(policyOptions);\n policyRef.current = policyOptions;\n\n // Fetch policies again after changes to the environment\n useEffect(() => {\n policyRef.current.reload();\n }, [environment, context]);\n\n const selectedPolicies = filter.policies ?? [];\n\n // Keep a ref so the effect can read the latest selection without making it\n // a dependency — the effect should only trigger when available policies change.\n const selectedPoliciesRef = useRef(selectedPolicies);\n selectedPoliciesRef.current = selectedPolicies;\n\n useEffect(() => {\n if (!policies) return;\n const selected = selectedPoliciesRef.current;\n\n if (selected.every(policy => policies.has(policy))) return;\n\n updateFilter({\n policies: selected.filter(policy => policies.has(policy)),\n });\n }, [policies, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (!policies) return;\n\n if (key === null) {\n updateFilter({ policies: [] });\n return;\n }\n\n if (!Array.isArray(key)) {\n updateFilter({\n policies: policies.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n policies.has(item as string),\n );\n updateFilter({ policies: filtered });\n };\n\n return (\n <Select\n label=\"Policy\"\n selectionMode=\"multiple\"\n options={policyOptions}\n value={selectedPolicies}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
@@ -6,13 +6,14 @@ import { policyReporterApiRef } from '../../api/PolicyReporterClient.esm.js';
6
6
  import { useApi, toastApiRef } from '@backstage/frontend-plugin-api';
7
7
 
8
8
  const SelectSource = () => {
9
- const { filter, updateFilter, environment } = usePolicyReportsFilters();
9
+ const { filter, updateFilter, environment, context } = usePolicyReportsFilters();
10
10
  const api = useApi(policyReporterApiRef);
11
11
  const toast = useApi(toastApiRef);
12
12
  const sourceOptions = useAsyncList({
13
13
  async load({}) {
14
14
  if (!environment) return { items: [] };
15
- const response = await api.getSources({ query: { environment } });
15
+ const request = { query: { environment } };
16
+ const response = context === "cluster" ? await api.getClusterSources(request) : await api.getSources(request);
16
17
  const result = await response.json();
17
18
  if (!response.ok) {
18
19
  toast.post({
@@ -37,7 +38,7 @@ const SelectSource = () => {
37
38
  sourceRef.current = sourceOptions;
38
39
  useEffect(() => {
39
40
  sourceRef.current.reload();
40
- }, [environment]);
41
+ }, [environment, context]);
41
42
  const selectedSources = filter.sources ?? [];
42
43
  const selectedSourcesRef = useRef(selectedSources);
43
44
  selectedSourcesRef.current = selectedSources;
@@ -1 +1 @@
1
- {"version":3,"file":"SelectSource.esm.js","sources":["../../../src/components/SelectSource/SelectSource.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectSource = () => {\n const { filter, updateFilter, environment } = usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const sourceOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const response = await api.getSources({ query: { environment } });\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch sources',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map(s => ({ id: s, label: s })),\n };\n },\n });\n\n const sources = useMemo(() => {\n if (sourceOptions.isLoading || sourceOptions.items.length === 0) {\n return undefined;\n }\n return new Set(sourceOptions.items.map(s => s.label));\n }, [sourceOptions.items, sourceOptions.isLoading]);\n\n // useRef to avoid dependency on the useAsyncList result\n const sourceRef = useRef(sourceOptions);\n sourceRef.current = sourceOptions;\n\n // Fetch sources again after changes to the environment\n useEffect(() => {\n sourceRef.current.reload();\n }, [environment]);\n\n const selectedSources = filter.sources ?? [];\n\n // Keep a ref so the effect can read the latest selection without making it\n // a dependency — the effect should only trigger when available sources change.\n const selectedSourcesRef = useRef(selectedSources);\n selectedSourcesRef.current = selectedSources;\n\n useEffect(() => {\n if (!sources) return;\n const selected = selectedSourcesRef.current;\n\n if (selected.every(source => sources.has(source))) return;\n\n updateFilter({\n sources: selected.filter(source => sources.has(source)),\n });\n }, [sources, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (!sources) return;\n\n if (key === null) {\n updateFilter({ sources: [] });\n return;\n }\n\n if (!Array.isArray(key)) {\n updateFilter({\n sources: sources.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n sources.has(item as string),\n );\n updateFilter({ sources: filtered });\n };\n\n return (\n <Select\n label=\"Source\"\n selectionMode=\"multiple\"\n options={sourceOptions}\n value={selectedSources}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelectSource.esm.js","sources":["../../../src/components/SelectSource/SelectSource.tsx"],"sourcesContent":["import { IdentifiedOption, Select, useAsyncList } from '@backstage/ui';\nimport { Key, useEffect, useMemo, useRef } from 'react';\nimport { usePolicyReportsFilters } from '../../hooks/usePolicyReportsFilters';\nimport { policyReporterApiRef } from '../../api';\nimport { toastApiRef, useApi } from '@backstage/frontend-plugin-api';\nimport { RequestError } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport const SelectSource = () => {\n const { filter, updateFilter, environment, context } =\n usePolicyReportsFilters();\n const api = useApi(policyReporterApiRef);\n const toast = useApi(toastApiRef);\n\n const sourceOptions = useAsyncList<IdentifiedOption>({\n async load({}) {\n if (!environment) return { items: [] };\n const request = { query: { environment } };\n const response =\n context === 'cluster'\n ? await api.getClusterSources(request)\n : await api.getSources(request);\n const result = await response.json();\n\n if (!response.ok) {\n toast.post({\n title: 'Failed to fetch sources',\n description:\n (result as unknown as RequestError).error ||\n response.statusText ||\n `Request failed with status ${response.status}`,\n status: 'danger',\n });\n return { items: [] };\n }\n\n return {\n items: result.map(s => ({ id: s, label: s })),\n };\n },\n });\n\n const sources = useMemo(() => {\n if (sourceOptions.isLoading || sourceOptions.items.length === 0) {\n return undefined;\n }\n return new Set(sourceOptions.items.map(s => s.label));\n }, [sourceOptions.items, sourceOptions.isLoading]);\n\n // useRef to avoid dependency on the useAsyncList result\n const sourceRef = useRef(sourceOptions);\n sourceRef.current = sourceOptions;\n\n // Fetch sources again after changes to the environment\n useEffect(() => {\n sourceRef.current.reload();\n }, [environment, context]);\n\n const selectedSources = filter.sources ?? [];\n\n // Keep a ref so the effect can read the latest selection without making it\n // a dependency — the effect should only trigger when available sources change.\n const selectedSourcesRef = useRef(selectedSources);\n selectedSourcesRef.current = selectedSources;\n\n useEffect(() => {\n if (!sources) return;\n const selected = selectedSourcesRef.current;\n\n if (selected.every(source => sources.has(source))) return;\n\n updateFilter({\n sources: selected.filter(source => sources.has(source)),\n });\n }, [sources, updateFilter]);\n\n const handleChange = (key: Key | Key[] | null) => {\n if (!sources) return;\n\n if (key === null) {\n updateFilter({ sources: [] });\n return;\n }\n\n if (!Array.isArray(key)) {\n updateFilter({\n sources: sources.has(key as string) ? [key as string] : [],\n });\n return;\n }\n\n const filtered = key.filter((item): item is string =>\n sources.has(item as string),\n );\n updateFilter({ sources: filtered });\n };\n\n return (\n <Select\n label=\"Source\"\n selectionMode=\"multiple\"\n options={sourceOptions}\n value={selectedSources}\n onChange={handleChange}\n placeholder=\"All\"\n />\n );\n};\n"],"names":[],"mappings":"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"}
@@ -7,7 +7,8 @@ const PolicyReportsFiltersContext = createContext(void 0);
7
7
  const PolicyReportsFiltersProvider = ({
8
8
  children,
9
9
  defaultFilters,
10
- defaultEnvironment
10
+ defaultEnvironment,
11
+ context
11
12
  }) => {
12
13
  const [searchParams, setSearchParams] = useSearchParams();
13
14
  const parsed = useMemo(
@@ -72,9 +73,10 @@ const PolicyReportsFiltersProvider = ({
72
73
  filter,
73
74
  updateFilter,
74
75
  environment,
75
- setEnvironment
76
+ setEnvironment,
77
+ context
76
78
  }),
77
- [filter, updateFilter, environment, setEnvironment]
79
+ [filter, updateFilter, environment, setEnvironment, context]
78
80
  );
79
81
  return /* @__PURE__ */ jsx(PolicyReportsFiltersContext.Provider, { value, children });
80
82
  };
@@ -1 +1 @@
1
- {"version":3,"file":"usePolicyReportsFilters.esm.js","sources":["../../src/hooks/usePolicyReportsFilters.tsx"],"sourcesContent":["import qs from 'qs';\nimport {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useLayoutEffect,\n useMemo,\n useRef,\n} from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport type { Filter } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport type PolicyReportsFiltersContextValue = {\n filter: Filter;\n updateFilter: (update: Partial<Filter>) => void;\n environment: string;\n setEnvironment: (entityRef: string) => void;\n};\n\nconst PolicyReportsFiltersContext = createContext<\n PolicyReportsFiltersContextValue | undefined\n>(undefined);\n\nexport type PolicyReportsFiltersProviderProps = PropsWithChildren<{\n /**\n * Default filter values written to the URL\n */\n defaultFilters?: Partial<Filter>;\n /**\n * The entityRef of the environment to use\n * when no ?environment= param is present in the URL.\n */\n defaultEnvironment: string;\n}>;\n\n/**\n * Provides shared filter state and selected environment for all policy report\n * filter components.\n */\nexport const PolicyReportsFiltersProvider = ({\n children,\n defaultFilters,\n defaultEnvironment,\n}: PolicyReportsFiltersProviderProps) => {\n const [searchParams, setSearchParams] = useSearchParams();\n\n const parsed = useMemo(\n () => qs.parse(searchParams.toString()),\n [searchParams],\n );\n\n const urlEnvironment = useMemo(\n () => parsed.environment?.toString(),\n [parsed],\n );\n\n // Use defaultFilters until the URL has been initialised (urlEnvironment set).\n // After that, always read from the URL so an explicit empty filter is valid.\n const filter = useMemo(\n () =>\n urlEnvironment ? ((parsed.filter ?? {}) as Filter) : defaultFilters ?? {},\n [parsed, urlEnvironment, defaultFilters],\n );\n\n const environment = useMemo(\n () => urlEnvironment ?? defaultEnvironment,\n [urlEnvironment, defaultEnvironment],\n );\n\n // setSearchParams is not stable (https://github.com/remix-run/react-router/issues/9991),\n // so we hold it in a ref to keep updateParams/updateFilter stable across renders.\n const setSearchParamsRef = useRef(setSearchParams);\n setSearchParamsRef.current = setSearchParams;\n\n const updateParams = useCallback(\n (\n update:\n | Record<string, unknown>\n | ((prev: Record<string, unknown>) => Record<string, unknown>),\n ) => {\n setSearchParamsRef.current(\n prev => {\n const prevParsed = qs.parse(prev.toString());\n const next =\n typeof update === 'function' ? update(prevParsed) : update;\n return qs.stringify(next, {\n arrayFormat: 'indices',\n skipNulls: true,\n });\n },\n { replace: true },\n );\n },\n [],\n );\n\n useLayoutEffect(() => {\n if (!urlEnvironment) {\n updateParams({\n filter: defaultFilters,\n environment: defaultEnvironment,\n });\n }\n }, [defaultEnvironment, urlEnvironment, defaultFilters, updateParams]);\n\n const updateFilter = useCallback(\n (update: Partial<Filter>) => {\n updateParams(prev => ({\n ...prev,\n filter: { ...(prev.filter as object), ...update },\n }));\n },\n [updateParams],\n );\n\n const setEnvironment = useCallback(\n (entityRef: string) => {\n updateParams(prev => ({ ...prev, environment: entityRef }));\n },\n [updateParams],\n );\n\n const value = useMemo(\n () => ({\n filter,\n updateFilter,\n environment,\n setEnvironment,\n }),\n [filter, updateFilter, environment, setEnvironment],\n );\n\n return (\n <PolicyReportsFiltersContext.Provider value={value}>\n {children}\n </PolicyReportsFiltersContext.Provider>\n );\n};\n\n/**\n * Hook for reading and updating policy report filters and the selected\n * environment. Must be used within a PolicyReportsFiltersProvider.\n */\nexport const usePolicyReportsFilters = (): PolicyReportsFiltersContextValue => {\n const ctx = useContext(PolicyReportsFiltersContext);\n if (!ctx) {\n throw new Error(\n 'usePolicyReportsFilters must be used within PolicyReportsFiltersProvider',\n );\n }\n return ctx;\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"usePolicyReportsFilters.esm.js","sources":["../../src/hooks/usePolicyReportsFilters.tsx"],"sourcesContent":["import qs from 'qs';\nimport {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useLayoutEffect,\n useMemo,\n useRef,\n} from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport type { Filter } from '@kyverno/backstage-plugin-policy-reporter-common';\n\nexport type PolicyReportsFiltersContextValue = {\n filter: Filter;\n context: 'cluster' | 'namespaced';\n updateFilter: (update: Partial<Filter>) => void;\n environment: string;\n setEnvironment: (entityRef: string) => void;\n};\n\nconst PolicyReportsFiltersContext = createContext<\n PolicyReportsFiltersContextValue | undefined\n>(undefined);\n\nexport type PolicyReportsFiltersProviderProps = PropsWithChildren<{\n /**\n * Default filter values written to the URL\n */\n defaultFilters?: Partial<Filter>;\n /**\n * The entityRef of the environment to use\n * when no ?environment= param is present in the URL.\n */\n defaultEnvironment: string;\n context: 'cluster' | 'namespaced';\n}>;\n\n/**\n * Provides shared filter state and selected environment for all policy report\n * filter components.\n */\nexport const PolicyReportsFiltersProvider = ({\n children,\n defaultFilters,\n defaultEnvironment,\n context,\n}: PolicyReportsFiltersProviderProps) => {\n const [searchParams, setSearchParams] = useSearchParams();\n\n const parsed = useMemo(\n () => qs.parse(searchParams.toString()),\n [searchParams],\n );\n\n const urlEnvironment = useMemo(\n () => parsed.environment?.toString(),\n [parsed],\n );\n\n // Use defaultFilters until the URL has been initialised (urlEnvironment set).\n // After that, always read from the URL so an explicit empty filter is valid.\n const filter = useMemo(\n () =>\n urlEnvironment ? ((parsed.filter ?? {}) as Filter) : defaultFilters ?? {},\n [parsed, urlEnvironment, defaultFilters],\n );\n\n const environment = useMemo(\n () => urlEnvironment ?? defaultEnvironment,\n [urlEnvironment, defaultEnvironment],\n );\n\n // setSearchParams is not stable (https://github.com/remix-run/react-router/issues/9991),\n // so we hold it in a ref to keep updateParams/updateFilter stable across renders.\n const setSearchParamsRef = useRef(setSearchParams);\n setSearchParamsRef.current = setSearchParams;\n\n const updateParams = useCallback(\n (\n update:\n | Record<string, unknown>\n | ((prev: Record<string, unknown>) => Record<string, unknown>),\n ) => {\n setSearchParamsRef.current(\n prev => {\n const prevParsed = qs.parse(prev.toString());\n const next =\n typeof update === 'function' ? update(prevParsed) : update;\n return qs.stringify(next, {\n arrayFormat: 'indices',\n skipNulls: true,\n });\n },\n { replace: true },\n );\n },\n [],\n );\n\n useLayoutEffect(() => {\n if (!urlEnvironment) {\n updateParams({\n filter: defaultFilters,\n environment: defaultEnvironment,\n });\n }\n }, [defaultEnvironment, urlEnvironment, defaultFilters, updateParams]);\n\n const updateFilter = useCallback(\n (update: Partial<Filter>) => {\n updateParams(prev => ({\n ...prev,\n filter: { ...(prev.filter as object), ...update },\n }));\n },\n [updateParams],\n );\n\n const setEnvironment = useCallback(\n (entityRef: string) => {\n updateParams(prev => ({ ...prev, environment: entityRef }));\n },\n [updateParams],\n );\n\n const value = useMemo(\n () => ({\n filter,\n updateFilter,\n environment,\n setEnvironment,\n context,\n }),\n [filter, updateFilter, environment, setEnvironment, context],\n );\n\n return (\n <PolicyReportsFiltersContext.Provider value={value}>\n {children}\n </PolicyReportsFiltersContext.Provider>\n );\n};\n\n/**\n * Hook for reading and updating policy report filters and the selected\n * environment. Must be used within a PolicyReportsFiltersProvider.\n */\nexport const usePolicyReportsFilters = (): PolicyReportsFiltersContextValue => {\n const ctx = useContext(PolicyReportsFiltersContext);\n if (!ctx) {\n throw new Error(\n 'usePolicyReportsFilters must be used within PolicyReportsFiltersProvider',\n );\n }\n return ctx;\n};\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  var name = "@kyverno/backstage-plugin-policy-reporter";
2
- var version = "2.10.0";
2
+ var version = "2.11.0";
3
3
  var main = "src/index.ts";
4
4
  var types = "src/index.ts";
5
5
  var license = "Apache-2.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kyverno/backstage-plugin-policy-reporter",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
4
4
  "main": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -67,15 +67,15 @@
67
67
  "directory": "plugins/policy-reporter"
68
68
  },
69
69
  "dependencies": {
70
- "@backstage/catalog-client": "^1.16.0",
71
- "@backstage/catalog-model": "^1.9.0",
72
- "@backstage/core-components": "^0.18.11",
73
- "@backstage/core-plugin-api": "^1.12.7",
74
- "@backstage/frontend-plugin-api": "^0.17.2",
75
- "@backstage/plugin-catalog-react": "^3.1.0",
70
+ "@backstage/catalog-client": "^1.16.2",
71
+ "@backstage/catalog-model": "^1.10.1",
72
+ "@backstage/core-components": "^0.18.14",
73
+ "@backstage/core-plugin-api": "^1.12.10",
74
+ "@backstage/frontend-plugin-api": "^0.18.1",
75
+ "@backstage/plugin-catalog-react": "^3.2.3",
76
76
  "@backstage/theme": "^0.7.3",
77
- "@backstage/ui": "^0.16.0",
78
- "@kyverno/backstage-plugin-policy-reporter-common": "^2.5.0",
77
+ "@backstage/ui": "^0.18.0",
78
+ "@kyverno/backstage-plugin-policy-reporter-common": "^2.6.0",
79
79
  "@material-ui/core": "^4.12.4",
80
80
  "@material-ui/icons": "^4.11.3",
81
81
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -88,10 +88,10 @@
88
88
  "react-router-dom": "^6.0.0"
89
89
  },
90
90
  "devDependencies": {
91
- "@backstage/cli": "^0.36.3",
92
- "@backstage/core-app-api": "^1.20.2",
93
- "@backstage/dev-utils": "^1.1.24",
94
- "@backstage/test-utils": "^1.7.19",
91
+ "@backstage/cli": "^0.36.6",
92
+ "@backstage/core-app-api": "^1.20.5",
93
+ "@backstage/dev-utils": "^1.1.27",
94
+ "@backstage/test-utils": "^1.7.22",
95
95
  "@testing-library/jest-dom": "^6.0.0",
96
96
  "@testing-library/react": "^14.0.0",
97
97
  "@testing-library/user-event": "^14.0.0",