@kyverno/backstage-plugin-policy-reporter 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # backstage-policy-reporter-plugin
2
+
3
+ The Frontend for the Policy Reporter plugin
4
+
5
+ This plugin integrates [Policy Reporter](https://kyverno.github.io/policy-reporter/) with Backstage to provide a clear and detailed view of Kyverno Policies applied to your entities
6
+
7
+ The [Backend](https://www.npmjs.com/package/@kyverno/backstage-plugin-policy-reporter-backend?activeTab=readme) plugin is required for this plugin to work
8
+
9
+ ## Installation
10
+
11
+ Add the plugin to your frontend app
12
+
13
+ ```bash
14
+ yarn --cwd packages/app add @kyverno/backstage-plugin-policy-reporter
15
+ ```
16
+
17
+ Add the **EntityKyvernoPoliciesContent** component to the Entity routes in `packages/app/src/components/catalog/EntityPage.tsx`
18
+
19
+ ```diff
20
+
21
+ + import { EntityKyvernoPoliciesContent } from '@kyverno/backstage-plugin-policy-reporter';
22
+
23
+ const serviceEntityPage = (
24
+
25
+ <EntityLayout>
26
+
27
+ // ...
28
+
29
+ + <EntityLayout.Route path="/kyverno" title="kyverno policy">
30
+ + <EntityKyvernoPoliciesContent />
31
+ + </EntityLayout.Route>
32
+
33
+ // ..
34
+
35
+ </EntityLayout>
36
+ )
37
+ ```
38
+
39
+ ## Configuration
40
+
41
+ ### Define Kubernetes Clusters
42
+
43
+ In your Backstage instance, define your Kubernetes clusters using the `Resource` kind and `kubernetes-cluster` type. Add the `kyverno.io/endpoint` annotation with the URL to the Policy Reporter API for each cluster.
44
+
45
+ ```yaml
46
+ apiVersion: backstage.io/v1alpha1
47
+ kind: Resource
48
+ metadata:
49
+ name: aks-dev
50
+ annotations:
51
+ # Add the Policy Reporter API endpoint as an annotation
52
+ kyverno.io/endpoint: http://kyverno.io/policy-reporter/api/
53
+ spec:
54
+ type: kubernetes-cluster
55
+ ```
56
+
57
+ ### Annotate Services
58
+
59
+ To show the policies on the service, add a dependency to the Kubernetes cluster resource in the `catalog-info.yaml` file of your service. Ensure that the necessary annotations are added as well. For more details, refer to the [How to annotate services](../../README.md#how-to-annotate-services) section.
60
+
61
+ ```yaml
62
+ metadata:
63
+ annotations:
64
+ kyverno.io/namespace: default # Specify the namespace of the service
65
+ kyverno.io/kind: Deployment,Pod # Specify the kind(s) of the Kubernetes resource(s)
66
+ kyverno.io/resource-name: policy-reporter # Specify the name of the resource
67
+ spec:
68
+ dependsOn:
69
+ # Add dependency to all environments the service is deployed to using the Resource entityRef
70
+ - resource:default/aks-dev
71
+ - resource:default/aks-tst
72
+ - resource:default/aks-qa
73
+ - resource:default/aks-prd
74
+ ```
75
+
76
+ ## Customization
77
+
78
+ To configure the plugin to make the policy Chip a link to custom documentation, follow the steps below.
79
+
80
+ To enable policy Chip links, the **EntityKyvernoPolicyReportsContent** component requires the **policyDocumentationUrl** prop to be set to the URL of the documentation.
81
+
82
+ ```typescript
83
+ const serviceEntityPage = (
84
+ <EntityLayout>
85
+ // ...
86
+ <EntityLayout.Route path="/kyverno" title="kyverno policy">
87
+ <EntityKyvernoPoliciesContent policyDocumentationUrl="Your full URL link" />
88
+ </EntityLayout.Route>
89
+ // ..
90
+ </EntityLayout>
91
+ );
92
+ ```
93
+
94
+ The policy documentation file provided in the above step needs to follow a specific structure.
95
+
96
+ All policies being used should have a header that matches the exact same name as the policy. Under this header, you can add information about the policy and provide a guide on how to solve it.
97
+
98
+ The plugin will create a link using the following format: `<DocumentationUrl>#<PolicyName>`
99
+
100
+ See the [example/policy-documentation.md](../../example/policy-documentation.md) file for an example of how this could look.
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+ import { makeStyles, Paper, Box, Typography, Card, CardHeader, CardContent, Grid, Divider } from '@material-ui/core';
3
+ import { SeverityComponent } from '../SeverityComponent/SeverityComponent.esm.js';
4
+ import { StatusComponent } from '../StatusComponent/StatusComponent.esm.js';
5
+
6
+ const useStyles = makeStyles((theme) => ({
7
+ root: {
8
+ marginBottom: theme.spacing(2)
9
+ },
10
+ sectionTitle: {
11
+ marginBottom: theme.spacing(1),
12
+ fontWeight: 500
13
+ },
14
+ propertyLabel: {
15
+ color: theme.palette.text.secondary,
16
+ fontWeight: 500
17
+ },
18
+ propertyValue: {
19
+ textAlign: "right"
20
+ },
21
+ propertyContainer: {
22
+ marginBottom: theme.spacing(1),
23
+ display: "flex",
24
+ justifyContent: "space-between"
25
+ },
26
+ divider: {
27
+ margin: theme.spacing(2, 0)
28
+ },
29
+ message: {
30
+ padding: theme.spacing(2),
31
+ backgroundColor: theme.palette.grey[50],
32
+ borderRadius: theme.shape.borderRadius,
33
+ color: "black"
34
+ },
35
+ propertiesContainer: {
36
+ padding: theme.spacing(2),
37
+ backgroundColor: theme.palette.grey[50],
38
+ borderRadius: theme.shape.borderRadius
39
+ },
40
+ propertyItem: {
41
+ display: "flex",
42
+ justifyContent: "space-between",
43
+ borderBottom: `1px solid ${theme.palette.divider}`,
44
+ padding: theme.spacing(1, 0),
45
+ "&:last-child": {
46
+ borderBottom: "none"
47
+ }
48
+ }
49
+ }));
50
+ const PolicyReportsDrawerComponent = ({
51
+ content
52
+ }) => {
53
+ const classes = useStyles();
54
+ if (!content) {
55
+ return /* @__PURE__ */ React.createElement(Paper, { className: classes.root }, /* @__PURE__ */ React.createElement(Box, { p: 2 }, /* @__PURE__ */ React.createElement(Typography, { variant: "body1", color: "textSecondary" }, "No policy information available")));
56
+ }
57
+ const formattedDate = new Date(content.timestamp * 1e3).toLocaleString();
58
+ return /* @__PURE__ */ React.createElement(Card, { className: classes.root, "data-testid": "policy-reports-drawer" }, /* @__PURE__ */ React.createElement(CardHeader, { title: "Policy Details" }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: classes.sectionTitle }, "General Information"), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "ID"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, content.id))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Name"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, content.name))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Namespace"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, content.namespace))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Kind"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, content.kind))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Resource ID"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, content.resourceId))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Timestamp"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, formattedDate)))), /* @__PURE__ */ React.createElement(Divider, { className: classes.divider }), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: classes.sectionTitle }, "Status Information"), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Status"), /* @__PURE__ */ React.createElement(StatusComponent, { status: content.status }))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Severity"), /* @__PURE__ */ React.createElement(SeverityComponent, { severity: content.severity })))), /* @__PURE__ */ React.createElement(Divider, { className: classes.divider }), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: classes.sectionTitle }, "Policy Information"), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Policy"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, content.policy))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Box, { className: classes.propertyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, "Rule"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyValue }, content.rule)))), /* @__PURE__ */ React.createElement(Divider, { className: classes.divider }), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: classes.sectionTitle }, "Message"), /* @__PURE__ */ React.createElement(Paper, { elevation: 0, className: classes.message }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, content.message)), content.properties && Object.keys(content.properties).length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Divider, { className: classes.divider }), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: classes.sectionTitle }, "Additional Properties"), /* @__PURE__ */ React.createElement(Paper, { elevation: 0, className: classes.propertiesContainer }, Object.entries(content.properties).map(([key, value]) => /* @__PURE__ */ React.createElement(Box, { key, className: classes.propertyItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.propertyLabel }, key), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, value)))))));
59
+ };
60
+
61
+ export { PolicyReportsDrawerComponent };
62
+ //# sourceMappingURL=PolicyReportsDrawerComponent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PolicyReportsDrawerComponent.esm.js","sources":["../../../src/components/PolicyReportsDrawerComponent/PolicyReportsDrawerComponent.tsx"],"sourcesContent":["import { ListResult } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport React from 'react';\nimport {\n Card,\n CardHeader,\n CardContent,\n Typography,\n Divider,\n Grid,\n Box,\n Paper,\n makeStyles,\n} from '@material-ui/core';\nimport { SeverityComponent } from '../SeverityComponent';\nimport { StatusComponent } from '../StatusComponent';\n\ninterface PolicyReportsDrawerProps {\n content: ListResult | undefined;\n}\n\n// Material-UI styles\nconst useStyles = makeStyles(theme => ({\n root: {\n marginBottom: theme.spacing(2),\n },\n sectionTitle: {\n marginBottom: theme.spacing(1),\n fontWeight: 500,\n },\n propertyLabel: {\n color: theme.palette.text.secondary,\n fontWeight: 500,\n },\n propertyValue: {\n textAlign: 'right',\n },\n propertyContainer: {\n marginBottom: theme.spacing(1),\n display: 'flex',\n justifyContent: 'space-between',\n },\n divider: {\n margin: theme.spacing(2, 0),\n },\n message: {\n padding: theme.spacing(2),\n backgroundColor: theme.palette.grey[50],\n borderRadius: theme.shape.borderRadius,\n color: 'black',\n },\n propertiesContainer: {\n padding: theme.spacing(2),\n backgroundColor: theme.palette.grey[50],\n borderRadius: theme.shape.borderRadius,\n },\n propertyItem: {\n display: 'flex',\n justifyContent: 'space-between',\n borderBottom: `1px solid ${theme.palette.divider}`,\n padding: theme.spacing(1, 0),\n '&:last-child': {\n borderBottom: 'none',\n },\n },\n}));\n\nexport const PolicyReportsDrawerComponent = ({\n content,\n}: PolicyReportsDrawerProps) => {\n const classes = useStyles();\n\n if (!content) {\n return (\n <Paper className={classes.root}>\n <Box p={2}>\n <Typography variant=\"body1\" color=\"textSecondary\">\n No policy information available\n </Typography>\n </Box>\n </Paper>\n );\n }\n\n // Format timestamp to readable date\n const formattedDate = new Date(content.timestamp * 1000).toLocaleString();\n\n return (\n <Card className={classes.root} data-testid=\"policy-reports-drawer\">\n <CardHeader title=\"Policy Details\" />\n <CardContent>\n {/* General Information */}\n <Typography variant=\"h6\" className={classes.sectionTitle}>\n General Information\n </Typography>\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n ID\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {content.id}\n </Typography>\n </Box>\n </Grid>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Name\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {content.name}\n </Typography>\n </Box>\n </Grid>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Namespace\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {content.namespace}\n </Typography>\n </Box>\n </Grid>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Kind\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {content.kind}\n </Typography>\n </Box>\n </Grid>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Resource ID\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {content.resourceId}\n </Typography>\n </Box>\n </Grid>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Timestamp\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {formattedDate}\n </Typography>\n </Box>\n </Grid>\n </Grid>\n\n <Divider className={classes.divider} />\n\n {/* Status Information */}\n <Typography variant=\"h6\" className={classes.sectionTitle}>\n Status Information\n </Typography>\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Status\n </Typography>\n <StatusComponent status={content.status} />\n </Box>\n </Grid>\n <Grid item xs={12} md={6}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Severity\n </Typography>\n <SeverityComponent severity={content.severity} />\n </Box>\n </Grid>\n </Grid>\n\n <Divider className={classes.divider} />\n\n {/* Policy Information */}\n <Typography variant=\"h6\" className={classes.sectionTitle}>\n Policy Information\n </Typography>\n <Grid container spacing={2}>\n <Grid item xs={12}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Policy\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {content.policy}\n </Typography>\n </Box>\n </Grid>\n <Grid item xs={12}>\n <Box className={classes.propertyContainer}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n Rule\n </Typography>\n <Typography variant=\"body2\" className={classes.propertyValue}>\n {content.rule}\n </Typography>\n </Box>\n </Grid>\n </Grid>\n\n <Divider className={classes.divider} />\n\n {/* Message */}\n <Typography variant=\"h6\" className={classes.sectionTitle}>\n Message\n </Typography>\n <Paper elevation={0} className={classes.message}>\n <Typography variant=\"body2\">{content.message}</Typography>\n </Paper>\n\n {/* Additional Properties */}\n {content.properties && Object.keys(content.properties).length > 0 && (\n <>\n <Divider className={classes.divider} />\n <Typography variant=\"h6\" className={classes.sectionTitle}>\n Additional Properties\n </Typography>\n <Paper elevation={0} className={classes.propertiesContainer}>\n {Object.entries(content.properties).map(([key, value]) => (\n <Box key={key} className={classes.propertyItem}>\n <Typography variant=\"body2\" className={classes.propertyLabel}>\n {key}\n </Typography>\n <Typography variant=\"body2\">{value}</Typography>\n </Box>\n ))}\n </Paper>\n </>\n )}\n </CardContent>\n </Card>\n );\n};\n"],"names":[],"mappings":";;;;;AAqBA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,IAAM,EAAA;AAAA,IACJ,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC;AAAA,GAC/B;AAAA,EACA,YAAc,EAAA;AAAA,IACZ,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC7B,UAAY,EAAA;AAAA,GACd;AAAA,EACA,aAAe,EAAA;AAAA,IACb,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,IAAK,CAAA,SAAA;AAAA,IAC1B,UAAY,EAAA;AAAA,GACd;AAAA,EACA,aAAe,EAAA;AAAA,IACb,SAAW,EAAA;AAAA,GACb;AAAA,EACA,iBAAmB,EAAA;AAAA,IACjB,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC7B,OAAS,EAAA,MAAA;AAAA,IACT,cAAgB,EAAA;AAAA,GAClB;AAAA,EACA,OAAS,EAAA;AAAA,IACP,MAAQ,EAAA,KAAA,CAAM,OAAQ,CAAA,CAAA,EAAG,CAAC;AAAA,GAC5B;AAAA,EACA,OAAS,EAAA;AAAA,IACP,OAAA,EAAS,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IACxB,eAAiB,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,CAAK,EAAE,CAAA;AAAA,IACtC,YAAA,EAAc,MAAM,KAAM,CAAA,YAAA;AAAA,IAC1B,KAAO,EAAA;AAAA,GACT;AAAA,EACA,mBAAqB,EAAA;AAAA,IACnB,OAAA,EAAS,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IACxB,eAAiB,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,CAAK,EAAE,CAAA;AAAA,IACtC,YAAA,EAAc,MAAM,KAAM,CAAA;AAAA,GAC5B;AAAA,EACA,YAAc,EAAA;AAAA,IACZ,OAAS,EAAA,MAAA;AAAA,IACT,cAAgB,EAAA,eAAA;AAAA,IAChB,YAAc,EAAA,CAAA,UAAA,EAAa,KAAM,CAAA,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,IAChD,OAAS,EAAA,KAAA,CAAM,OAAQ,CAAA,CAAA,EAAG,CAAC,CAAA;AAAA,IAC3B,cAAgB,EAAA;AAAA,MACd,YAAc,EAAA;AAAA;AAChB;AAEJ,CAAE,CAAA,CAAA;AAEK,MAAM,+BAA+B,CAAC;AAAA,EAC3C;AACF,CAAgC,KAAA;AAC9B,EAAA,MAAM,UAAU,SAAU,EAAA;AAE1B,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAA,2CACG,KAAM,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,IAAA,EAAA,sCACvB,GAAI,EAAA,EAAA,CAAA,EAAG,CACN,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,OAAQ,EAAA,OAAA,EAAQ,OAAM,eAAgB,EAAA,EAAA,iCAElD,CACF,CACF,CAAA;AAAA;AAKJ,EAAA,MAAM,gBAAgB,IAAI,IAAA,CAAK,QAAQ,SAAY,GAAA,GAAI,EAAE,cAAe,EAAA;AAExE,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,IAAA,EAAM,aAAY,EAAA,uBAAA,EAAA,kBACxC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,KAAM,EAAA,gBAAA,EAAiB,CACnC,kBAAA,KAAA,CAAA,aAAA,CAAC,WAEC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,SAAA,EAAW,OAAQ,CAAA,YAAA,EAAA,EAAc,qBAE1D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,SAAS,EAAA,IAAA,EAAC,OAAS,EAAA,CAAA,EAAA,sCACtB,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,CACrB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,iBAAA,EAAA,kBACrB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAAe,EAAA,EAAA,IAE9D,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAC5C,OAAQ,CAAA,EACX,CACF,CACF,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,EAAA,EAAI,EAAI,EAAA,CAAA,EAAA,kBACpB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,iBACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAAe,MAE9D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAC5C,EAAA,EAAA,OAAA,CAAQ,IACX,CACF,CACF,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,EAAA,EAAI,EAAI,EAAA,CAAA,EAAA,kBACpB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,iBACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAAe,WAE9D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,WAAW,OAAQ,CAAA,aAAA,EAAA,EAC5C,OAAQ,CAAA,SACX,CACF,CACF,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,CACrB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,iBAAA,EAAA,kBACrB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAAe,EAAA,EAAA,MAE9D,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAC5C,OAAQ,CAAA,IACX,CACF,CACF,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,CACrB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,iBAAA,EAAA,kBACrB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAAe,EAAA,EAAA,aAE9D,mBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAC5C,EAAA,EAAA,OAAA,CAAQ,UACX,CACF,CACF,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,EAAA,EAAI,EAAI,EAAA,CAAA,EAAA,kBACpB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,iBACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAAe,WAE9D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAC5C,EAAA,EAAA,aACH,CACF,CACF,CACF,CAAA,kBAEC,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,OAAS,EAAA,CAAA,kBAGpC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAK,SAAW,EAAA,OAAA,CAAQ,YAAc,EAAA,EAAA,oBAE1D,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,SAAS,EAAA,IAAA,EAAC,OAAS,EAAA,CAAA,EAAA,kBACtB,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,EAAA,EAAI,EAAI,EAAA,CAAA,EAAA,kBACpB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,iBACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAAe,QAE9D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,eAAA,EAAA,EAAgB,MAAQ,EAAA,OAAA,CAAQ,MAAQ,EAAA,CAC3C,CACF,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,EAAA,EAAI,EAAI,EAAA,CAAA,EAAA,kBACpB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,iBACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAAe,UAE9D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,EAAkB,QAAU,EAAA,OAAA,CAAQ,QAAU,EAAA,CACjD,CACF,CACF,CAAA,kBAEC,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,OAAS,EAAA,CAAA,kBAGpC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAK,SAAW,EAAA,OAAA,CAAQ,YAAc,EAAA,EAAA,oBAE1D,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,OAAA,EAAS,CACvB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EACb,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,iBAAA,EAAA,kBACrB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAAe,EAAA,EAAA,QAE9D,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAC5C,OAAQ,CAAA,MACX,CACF,CACF,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EACb,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,SAAW,EAAA,OAAA,CAAQ,iBACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAAe,MAE9D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,aAC5C,EAAA,EAAA,OAAA,CAAQ,IACX,CACF,CACF,CACF,CAEA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAQ,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,OAAA,EAAS,CAGrC,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,IAAK,EAAA,SAAA,EAAW,OAAQ,CAAA,YAAA,EAAA,EAAc,SAE1D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAM,SAAW,EAAA,CAAA,EAAG,SAAW,EAAA,OAAA,CAAQ,OACtC,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAS,EAAA,EAAA,OAAA,CAAQ,OAAQ,CAC/C,CAGC,EAAA,OAAA,CAAQ,UAAc,IAAA,MAAA,CAAO,IAAK,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAE,SAAS,CAC9D,oBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBACG,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,SAAW,EAAA,OAAA,CAAQ,OAAS,EAAA,CAAA,kBACpC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,IAAA,EAAK,SAAW,EAAA,OAAA,CAAQ,YAAc,EAAA,EAAA,uBAE1D,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,KAAM,EAAA,EAAA,SAAA,EAAW,CAAG,EAAA,SAAA,EAAW,OAAQ,CAAA,mBAAA,EAAA,EACrC,MAAO,CAAA,OAAA,CAAQ,OAAQ,CAAA,UAAU,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,GAAK,EAAA,KAAK,CAClD,qBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,GAAA,EAAU,SAAW,EAAA,OAAA,CAAQ,YAChC,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,SAAA,EAAW,OAAQ,CAAA,aAAA,EAAA,EAC5C,GACH,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAA,EAAS,KAAM,CACrC,CACD,CACH,CACF,CAEJ,CACF,CAAA;AAEJ;;;;"}
@@ -1,11 +1,12 @@
1
1
  import { ResponseErrorPanel, Table } from '@backstage/core-components';
2
- import React from 'react';
3
- import { makeStyles } from '@material-ui/core';
2
+ import React, { useState } from 'react';
3
+ import { makeStyles, Drawer } from '@material-ui/core';
4
4
  import Chip from '@material-ui/core/Chip';
5
5
  import { StatusComponent } from '../StatusComponent/StatusComponent.esm.js';
6
6
  import { SeverityComponent } from '../SeverityComponent/SeverityComponent.esm.js';
7
7
  import Launch from '@material-ui/icons/Launch';
8
8
  import { usePaginatedPolicies } from '../../hooks/usePaginatedPolicies.esm.js';
9
+ import { PolicyReportsDrawerComponent } from '../PolicyReportsDrawerComponent/PolicyReportsDrawerComponent.esm.js';
9
10
 
10
11
  const PolicyReportsTable = ({
11
12
  title,
@@ -21,6 +22,10 @@ const PolicyReportsTable = ({
21
22
  justifyContent: "center"
22
23
  }
23
24
  }));
25
+ const [showDrawer, setShowDrawer] = useState(false);
26
+ const [drawerContent, setDrawerContent] = useState(
27
+ void 0
28
+ );
24
29
  const classes = useStyles();
25
30
  const columns = [
26
31
  {
@@ -98,13 +103,26 @@ const PolicyReportsTable = ({
98
103
  title
99
104
  }
100
105
  );
101
- return /* @__PURE__ */ React.createElement(
106
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
107
+ Drawer,
108
+ {
109
+ anchor: "right",
110
+ open: showDrawer,
111
+ onClose: () => setShowDrawer(false)
112
+ },
113
+ /* @__PURE__ */ React.createElement(PolicyReportsDrawerComponent, { content: drawerContent })
114
+ ), /* @__PURE__ */ React.createElement(
102
115
  Table,
103
116
  {
104
117
  options: {
105
118
  sorting: true,
106
119
  padding: "dense"
107
120
  },
121
+ onRowClick: (event, rowData) => {
122
+ event?.preventDefault();
123
+ setShowDrawer(true);
124
+ setDrawerContent(rowData);
125
+ },
108
126
  data: policies?.items ?? [],
109
127
  columns,
110
128
  title,
@@ -114,7 +132,7 @@ const PolicyReportsTable = ({
114
132
  onPageChange: (page) => setCurrentPage(page),
115
133
  emptyContent: /* @__PURE__ */ React.createElement("div", { className: classes.empty }, emptyContentText)
116
134
  }
117
- );
135
+ ));
118
136
  };
119
137
 
120
138
  export { PolicyReportsTable };
@@ -1 +1 @@
1
- {"version":3,"file":"PolicyReportsTable.esm.js","sources":["../../../src/components/PolicyReportsTable/PolicyReportsTable.tsx"],"sourcesContent":["import {\n ResponseErrorPanel,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport React from 'react';\nimport {\n Filter,\n ListResult,\n} from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { makeStyles } from '@material-ui/core';\nimport Chip from '@material-ui/core/Chip';\nimport { StatusComponent } from '../StatusComponent';\nimport { SeverityComponent } from '../SeverityComponent';\nimport Launch from '@material-ui/icons/Launch';\nimport { Environment } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { usePaginatedPolicies } from '../../hooks/usePaginatedPolicies';\n\ninterface PolicyReportsTableProps {\n currentEnvironment: Environment;\n filter: Filter;\n title: string;\n emptyContentText: string;\n policyDocumentationUrl?: string;\n}\n\nexport const PolicyReportsTable = ({\n title,\n emptyContentText,\n currentEnvironment,\n filter,\n policyDocumentationUrl,\n}: PolicyReportsTableProps) => {\n const useStyles = makeStyles(theme => ({\n empty: {\n padding: theme.spacing(2),\n display: 'flex',\n justifyContent: 'center',\n },\n }));\n\n const classes = useStyles();\n\n const columns: TableColumn<ListResult>[] = [\n {\n title: 'name',\n field: 'name',\n },\n {\n title: 'namespace',\n field: 'namespace',\n },\n {\n title: 'kind',\n field: 'kind',\n },\n {\n title: 'policy',\n field: 'policy',\n render: (listResult: ListResult) => {\n // When policyDocumentationUrl is provided create link to the Policy section\n if (policyDocumentationUrl)\n return (\n <Chip\n label={listResult.policy}\n component=\"a\"\n target=\"_blank\"\n href={`${policyDocumentationUrl}#${listResult.policy}`}\n clickable\n icon={<Launch fontSize=\"small\" />}\n />\n );\n\n return <Chip label={listResult.policy} />;\n },\n },\n {\n title: 'rule',\n field: 'rule',\n render: (listResult: ListResult) => {\n return <Chip label={listResult.rule} />;\n },\n },\n {\n title: 'status',\n field: 'status',\n width: '30',\n render: (listResult: ListResult) => {\n return <StatusComponent status={listResult.status} />;\n },\n },\n {\n title: 'severity',\n field: 'severity',\n width: '30',\n render: (listResult: ListResult) => {\n return <SeverityComponent severity={listResult.severity} />;\n },\n },\n ];\n\n const {\n policies,\n policiesError,\n currentPage,\n setCurrentPage,\n setCurrentOffset,\n initialLoading,\n } = usePaginatedPolicies(currentEnvironment, filter);\n\n if (policiesError) return <ResponseErrorPanel error={policiesError} />;\n\n // Return loading table\n if (initialLoading)\n return (\n <Table\n options={{ paging: false, padding: 'dense' }}\n data={[]}\n columns={columns}\n isLoading\n title={title}\n />\n );\n\n return (\n <Table\n options={{\n sorting: true,\n padding: 'dense',\n }}\n data={policies?.items ?? []}\n columns={columns}\n title={title}\n totalCount={policies?.count}\n page={currentPage}\n onRowsPerPageChange={page => setCurrentOffset(page)}\n onPageChange={page => setCurrentPage(page)}\n emptyContent={<div className={classes.empty}>{emptyContentText}</div>}\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 {\n ResponseErrorPanel,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport React, { useState } from 'react';\nimport {\n Filter,\n ListResult,\n} from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { Drawer, makeStyles } from '@material-ui/core';\nimport Chip from '@material-ui/core/Chip';\nimport { StatusComponent } from '../StatusComponent';\nimport { SeverityComponent } from '../SeverityComponent';\nimport Launch from '@material-ui/icons/Launch';\nimport { Environment } from '@kyverno/backstage-plugin-policy-reporter-common';\nimport { usePaginatedPolicies } from '../../hooks/usePaginatedPolicies';\nimport { PolicyReportsDrawerComponent } from '../PolicyReportsDrawerComponent/PolicyReportsDrawerComponent';\n\ninterface PolicyReportsTableProps {\n currentEnvironment: Environment;\n filter: Filter;\n title: string;\n emptyContentText: string;\n policyDocumentationUrl?: string;\n}\n\nexport const PolicyReportsTable = ({\n title,\n emptyContentText,\n currentEnvironment,\n filter,\n policyDocumentationUrl,\n}: PolicyReportsTableProps) => {\n const useStyles = makeStyles(theme => ({\n empty: {\n padding: theme.spacing(2),\n display: 'flex',\n justifyContent: 'center',\n },\n }));\n\n const [showDrawer, setShowDrawer] = useState<boolean>(false);\n const [drawerContent, setDrawerContent] = useState<ListResult | undefined>(\n undefined,\n );\n const classes = useStyles();\n\n const columns: TableColumn<ListResult>[] = [\n {\n title: 'name',\n field: 'name',\n },\n {\n title: 'namespace',\n field: 'namespace',\n },\n {\n title: 'kind',\n field: 'kind',\n },\n {\n title: 'policy',\n field: 'policy',\n render: (listResult: ListResult) => {\n // When policyDocumentationUrl is provided create link to the Policy section\n if (policyDocumentationUrl)\n return (\n <Chip\n label={listResult.policy}\n component=\"a\"\n target=\"_blank\"\n href={`${policyDocumentationUrl}#${listResult.policy}`}\n clickable\n icon={<Launch fontSize=\"small\" />}\n />\n );\n\n return <Chip label={listResult.policy} />;\n },\n },\n {\n title: 'rule',\n field: 'rule',\n render: (listResult: ListResult) => {\n return <Chip label={listResult.rule} />;\n },\n },\n {\n title: 'status',\n field: 'status',\n width: '30',\n render: (listResult: ListResult) => {\n return <StatusComponent status={listResult.status} />;\n },\n },\n {\n title: 'severity',\n field: 'severity',\n width: '30',\n render: (listResult: ListResult) => {\n return <SeverityComponent severity={listResult.severity} />;\n },\n },\n ];\n\n const {\n policies,\n policiesError,\n currentPage,\n setCurrentPage,\n setCurrentOffset,\n initialLoading,\n } = usePaginatedPolicies(currentEnvironment, filter);\n\n if (policiesError) return <ResponseErrorPanel error={policiesError} />;\n\n // Return loading table\n if (initialLoading)\n return (\n <Table\n options={{ paging: false, padding: 'dense' }}\n data={[]}\n columns={columns}\n isLoading\n title={title}\n />\n );\n\n return (\n <>\n <Drawer\n anchor=\"right\"\n open={showDrawer}\n onClose={() => setShowDrawer(false)}\n >\n <PolicyReportsDrawerComponent content={drawerContent} />\n </Drawer>\n <Table\n options={{\n sorting: true,\n padding: 'dense',\n }}\n onRowClick={(\n event?: React.MouseEvent<Element, MouseEvent>,\n rowData?: ListResult,\n ) => {\n event?.preventDefault();\n setShowDrawer(true);\n setDrawerContent(rowData);\n }}\n data={policies?.items ?? []}\n columns={columns}\n title={title}\n totalCount={policies?.count}\n page={currentPage}\n onRowsPerPageChange={page => setCurrentOffset(page)}\n onPageChange={page => setCurrentPage(page)}\n emptyContent={<div className={classes.empty}>{emptyContentText}</div>}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@kyverno/backstage-plugin-policy-reporter",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "main": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
7
+ "keywords": [
8
+ "backstage",
9
+ "kyverno",
10
+ "policy-reporter"
11
+ ],
7
12
  "backstage": {
8
13
  "role": "frontend-plugin",
9
14
  "pluginId": "policy-reporter",
@@ -36,11 +41,11 @@
36
41
  "dependencies": {
37
42
  "@backstage/catalog-client": "^1.9.1",
38
43
  "@backstage/catalog-model": "^1.7.3",
39
- "@backstage/core-components": "^0.16.3",
40
- "@backstage/core-plugin-api": "^1.10.3",
41
- "@backstage/plugin-catalog-react": "^1.15.1",
42
- "@backstage/theme": "^0.6.3",
43
- "@kyverno/backstage-plugin-policy-reporter-common": "^2.0.1",
44
+ "@backstage/core-components": "^0.16.4",
45
+ "@backstage/core-plugin-api": "^1.10.4",
46
+ "@backstage/plugin-catalog-react": "^1.15.2",
47
+ "@backstage/theme": "^0.6.4",
48
+ "@kyverno/backstage-plugin-policy-reporter-common": "^2.0.3",
44
49
  "@material-ui/core": "^4.9.13",
45
50
  "@material-ui/icons": "^4.9.1",
46
51
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -50,10 +55,10 @@
50
55
  "react": "^16.13.1 || ^17.0.0 || ^18.0.0"
51
56
  },
52
57
  "devDependencies": {
53
- "@backstage/cli": "^0.29.5",
54
- "@backstage/core-app-api": "^1.15.4",
55
- "@backstage/dev-utils": "^1.1.6",
56
- "@backstage/test-utils": "^1.7.4",
58
+ "@backstage/cli": "^0.30.0",
59
+ "@backstage/core-app-api": "^1.15.5",
60
+ "@backstage/dev-utils": "^1.1.7",
61
+ "@backstage/test-utils": "^1.7.5",
57
62
  "@testing-library/jest-dom": "^6.0.0",
58
63
  "@testing-library/react": "^14.0.0",
59
64
  "@testing-library/user-event": "^14.0.0",
@@ -62,7 +67,7 @@
62
67
  "files": [
63
68
  "dist"
64
69
  ],
65
- "gitHead": "e5cedc7d766a1a56893ecda78c9cd5d7905bad8d",
70
+ "gitHead": "f16449996db64192842fa919e25dd9439258fab6",
66
71
  "typesVersions": {
67
72
  "*": {
68
73
  "index": [