@backstage-community/plugin-quay 1.34.0 → 1.36.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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @backstage-community/plugin-quay
2
2
 
3
+ ## 1.36.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 03eff44: Backstage version bump to v1.52.0
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [03eff44]
12
+ - @backstage-community/plugin-quay-common@1.22.0
13
+
14
+ ## 1.35.0
15
+
16
+ ### Minor Changes
17
+
18
+ - c58c3c0: Migrated the Quay plugin and dev app from Material UI to Backstage UI (BUI). Replaced `@material-ui/*` with `@backstage/ui` components and `@remixicon/react` icons. Removed direct MUI dependencies; no breaking API changes to plugin exports.
19
+
20
+ **Note for consuming apps:** import `@backstage/ui/css/styles.css` in your app entry point if it is not already included.
21
+
3
22
  ## 1.34.0
4
23
 
5
24
  ### Minor Changes
@@ -1,11 +1,16 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { Alert, AlertTitle } from '@material-ui/lab';
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Alert } from '@backstage/ui';
3
3
 
4
4
  const PermissionAlert = () => {
5
- return /* @__PURE__ */ jsxs(Alert, { severity: "warning", "data-testid": "no-permission-alert", children: [
6
- /* @__PURE__ */ jsx(AlertTitle, { children: "Permission required" }),
7
- "To view quay image registry, contact your administrator to give you the quay.view.read permission."
8
- ] });
5
+ return /* @__PURE__ */ jsx(
6
+ Alert,
7
+ {
8
+ status: "warning",
9
+ title: "Permission required",
10
+ description: "To view quay image registry, contact your administrator to give you the quay.view.read permission.",
11
+ "data-testid": "no-permission-alert"
12
+ }
13
+ );
9
14
  };
10
15
 
11
16
  export { PermissionAlert as default };
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionAlert.esm.js","sources":["../../../src/components/PermissionAlert/PermissionAlert.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Alert, AlertTitle } from '@material-ui/lab';\n\nconst PermissionAlert = () => {\n return (\n <Alert severity=\"warning\" data-testid=\"no-permission-alert\">\n <AlertTitle>Permission required</AlertTitle>\n To view quay image registry, contact your administrator to give you the\n quay.view.read permission.\n </Alert>\n );\n};\nexport default PermissionAlert;\n"],"names":[],"mappings":";;;AAiBA,MAAM,kBAAkB,MAAM;AAC5B,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAM,QAAA,EAAS,SAAA,EAAU,eAAY,qBAAA,EACpC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cAAW,QAAA,EAAA,qBAAA,EAAmB,CAAA;AAAA,IAAa;AAAA,GAAA,EAG9C,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"PermissionAlert.esm.js","sources":["../../../src/components/PermissionAlert/PermissionAlert.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Alert } from '@backstage/ui';\n\nconst PermissionAlert = () => {\n return (\n <Alert\n status=\"warning\"\n title=\"Permission required\"\n description=\"To view quay image registry, contact your administrator to give you the quay.view.read permission.\"\n data-testid=\"no-permission-alert\"\n />\n );\n};\nexport default PermissionAlert;\n"],"names":[],"mappings":";;;AAiBA,MAAM,kBAAkB,MAAM;AAC5B,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,MAAA,EAAO,SAAA;AAAA,MACP,KAAA,EAAM,qBAAA;AAAA,MACN,WAAA,EAAY,oGAAA;AAAA,MACZ,aAAA,EAAY;AAAA;AAAA,GACd;AAEJ;;;;"}
@@ -1,12 +1,13 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { Progress, Table, Link } from '@backstage/core-components';
3
3
  import { useApi } from '@backstage/core-plugin-api';
4
- import { Box, Typography } from '@material-ui/core';
4
+ import { Box, Flex, Text } from '@backstage/ui';
5
5
  import { quayApiRef } from '../../api/index.esm.js';
6
6
  import { DOC_LINKS } from '../../doc-links.esm.js';
7
7
  import { useRepository, useTags } from '../../hooks/quay.esm.js';
8
8
  import { useQuayViewPermission } from '../../hooks/useQuayViewPermission.esm.js';
9
9
  import PermissionAlert from '../PermissionAlert/PermissionAlert.esm.js';
10
+ import styles from './QuayRepository.module.css.esm.js';
10
11
  import { columns } from './tableHeading.esm.js';
11
12
 
12
13
  function QuayRepository(_props) {
@@ -39,75 +40,48 @@ function QuayRepository(_props) {
39
40
  options: { sorting: true, paging: true, padding: "dense" },
40
41
  data,
41
42
  columns,
42
- emptyContent: /* @__PURE__ */ jsxs(Box, { "data-testid": "quay-repo-table-empty", padding: 2, children: [
43
- /* @__PURE__ */ jsx(Typography, { component: "h3", align: "center", variant: "h6", gutterBottom: true, children: "No container images found" }),
44
- /* @__PURE__ */ jsx(
45
- Typography,
46
- {
47
- component: "p",
48
- align: "center",
49
- variant: "body1",
50
- color: "textSecondary",
51
- gutterBottom: true,
52
- children: "This repository doesn't contain any images yet, or there might be an access issue."
53
- }
54
- ),
55
- /* @__PURE__ */ jsxs(Box, { mt: 2, children: [
56
- /* @__PURE__ */ jsx(
57
- Typography,
58
- {
59
- component: "p",
60
- align: "center",
61
- variant: "body2",
62
- gutterBottom: true,
63
- children: /* @__PURE__ */ jsx("strong", { children: "Possible solutions:" })
64
- }
65
- ),
66
- /* @__PURE__ */ jsx(
67
- Typography,
68
- {
69
- component: "p",
70
- align: "center",
71
- variant: "body2",
72
- gutterBottom: true,
73
- children: "1. Check if images have been pushed to this repository"
74
- }
75
- ),
76
- /* @__PURE__ */ jsx(
77
- Typography,
78
- {
79
- component: "p",
80
- align: "center",
81
- variant: "body2",
82
- gutterBottom: true,
83
- children: "2. Review the application logs in your Backstage instance"
84
- }
85
- ),
86
- /* @__PURE__ */ jsxs(
87
- Typography,
88
- {
89
- component: "p",
90
- align: "center",
91
- variant: "body2",
92
- gutterBottom: true,
93
- children: [
94
- "3. Verify your entity annotations are",
95
- " ",
96
- /* @__PURE__ */ jsx(Link, { to: DOC_LINKS.BACKEND_ANNOTATIONS_GUIDE, children: "configured correctly" })
97
- ]
98
- }
99
- ),
100
- /* @__PURE__ */ jsxs(Typography, { component: "p", align: "center", variant: "body2", children: [
101
- "4. Verify your",
102
- " ",
103
- /* @__PURE__ */ jsx(Link, { to: DOC_LINKS.AUTH_TOKEN_GUIDE, children: "Quay access tokens" }),
104
- " ",
105
- "are",
106
- " ",
107
- /* @__PURE__ */ jsx(Link, { to: DOC_LINKS.BACKEND_CONFIGURATION_GUIDE, children: "configured correctly" })
108
- ] })
109
- ] })
110
- ] })
43
+ emptyContent: /* @__PURE__ */ jsxs(
44
+ Box,
45
+ {
46
+ "data-testid": "quay-repo-table-empty",
47
+ p: "4",
48
+ className: styles.emptyState,
49
+ children: [
50
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", align: "center", gap: "2", children: [
51
+ /* @__PURE__ */ jsx(Text, { variant: "title-small", children: "No container images found" }),
52
+ /* @__PURE__ */ jsx(Text, { variant: "body-medium", color: "secondary", children: "This repository doesn't contain any images yet, or there might be an access issue." })
53
+ ] }),
54
+ /* @__PURE__ */ jsxs(
55
+ Flex,
56
+ {
57
+ direction: "column",
58
+ align: "center",
59
+ gap: "2",
60
+ className: styles.emptyStateSection,
61
+ children: [
62
+ /* @__PURE__ */ jsx(Text, { variant: "body-small", weight: "bold", children: "Possible solutions:" }),
63
+ /* @__PURE__ */ jsx(Text, { variant: "body-small", children: "1. Check if images have been pushed to this repository" }),
64
+ /* @__PURE__ */ jsx(Text, { variant: "body-small", children: "2. Review the application logs in your Backstage instance" }),
65
+ /* @__PURE__ */ jsxs(Text, { variant: "body-small", children: [
66
+ "3. Verify your entity annotations are",
67
+ " ",
68
+ /* @__PURE__ */ jsx(Link, { to: DOC_LINKS.BACKEND_ANNOTATIONS_GUIDE, children: "configured correctly" })
69
+ ] }),
70
+ /* @__PURE__ */ jsxs(Text, { variant: "body-small", children: [
71
+ "4. Verify your",
72
+ " ",
73
+ /* @__PURE__ */ jsx(Link, { to: DOC_LINKS.AUTH_TOKEN_GUIDE, children: "Quay access tokens" }),
74
+ " ",
75
+ "are",
76
+ " ",
77
+ /* @__PURE__ */ jsx(Link, { to: DOC_LINKS.BACKEND_CONFIGURATION_GUIDE, children: "configured correctly" })
78
+ ] })
79
+ ]
80
+ }
81
+ )
82
+ ]
83
+ }
84
+ )
111
85
  }
112
86
  ) });
113
87
  }
@@ -1 +1 @@
1
- {"version":3,"file":"QuayRepository.esm.js","sources":["../../../src/components/QuayRepository/QuayRepository.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Link, Progress, Table } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\n\nimport { Box, Typography } from '@material-ui/core';\n\nimport { quayApiRef } from '../../api';\nimport { DOC_LINKS } from '../../doc-links';\nimport { useRepository, useTags } from '../../hooks';\nimport { useQuayViewPermission } from '../../hooks/useQuayViewPermission';\nimport PermissionAlert from '../PermissionAlert/PermissionAlert';\nimport { columns } from './tableHeading';\n\ntype QuayRepositoryProps = Record<never, any>;\n\nexport function QuayRepository(_props: QuayRepositoryProps) {\n const { instanceName, repository, organization } = useRepository();\n const quayApi = useApi(quayApiRef);\n\n const instanceConfig = quayApi.getQuayInstance(instanceName);\n const quayUiUrl = instanceConfig?.apiUrl ?? instanceConfig?.uiUrl;\n\n const hasViewPermission = useQuayViewPermission();\n\n const title = quayUiUrl ? (\n <>\n {`Quay repository: `}\n <Link\n to={`${quayUiUrl}/repository/${organization}/${repository}`}\n >{`${organization}/${repository}`}</Link>\n </>\n ) : (\n `Quay repository: ${organization}/${repository}`\n );\n const { loading, data } = useTags(instanceName, organization, repository);\n\n if (!hasViewPermission) {\n return <PermissionAlert />;\n }\n\n if (loading) {\n return (\n <div data-testid=\"quay-repo-progress\">\n <Progress />\n </div>\n );\n }\n\n return (\n <div data-testid=\"quay-repo-table\">\n <Table\n title={title}\n options={{ sorting: true, paging: true, padding: 'dense' }}\n data={data}\n columns={columns}\n emptyContent={\n <Box data-testid=\"quay-repo-table-empty\" padding={2}>\n <Typography component=\"h3\" align=\"center\" variant=\"h6\" gutterBottom>\n No container images found\n </Typography>\n <Typography\n component=\"p\"\n align=\"center\"\n variant=\"body1\"\n color=\"textSecondary\"\n gutterBottom\n >\n This repository doesn't contain any images yet, or there might be\n an access issue.\n </Typography>\n <Box mt={2}>\n <Typography\n component=\"p\"\n align=\"center\"\n variant=\"body2\"\n gutterBottom\n >\n <strong>Possible solutions:</strong>\n </Typography>\n <Typography\n component=\"p\"\n align=\"center\"\n variant=\"body2\"\n gutterBottom\n >\n 1. Check if images have been pushed to this repository\n </Typography>\n <Typography\n component=\"p\"\n align=\"center\"\n variant=\"body2\"\n gutterBottom\n >\n 2. Review the application logs in your Backstage instance\n </Typography>\n <Typography\n component=\"p\"\n align=\"center\"\n variant=\"body2\"\n gutterBottom\n >\n 3. Verify your entity annotations are{' '}\n <Link to={DOC_LINKS.BACKEND_ANNOTATIONS_GUIDE}>\n configured correctly\n </Link>\n </Typography>\n <Typography component=\"p\" align=\"center\" variant=\"body2\">\n 4. Verify your{' '}\n <Link to={DOC_LINKS.AUTH_TOKEN_GUIDE}>Quay access tokens</Link>{' '}\n are{' '}\n <Link to={DOC_LINKS.BACKEND_CONFIGURATION_GUIDE}>\n configured correctly\n </Link>\n </Typography>\n </Box>\n </Box>\n }\n />\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"QuayRepository.esm.js","sources":["../../../src/components/QuayRepository/QuayRepository.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Link, Progress, Table } from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Box, Flex, Text } from '@backstage/ui';\n\nimport { quayApiRef } from '../../api';\nimport { DOC_LINKS } from '../../doc-links';\nimport { useRepository, useTags } from '../../hooks';\nimport { useQuayViewPermission } from '../../hooks/useQuayViewPermission';\nimport PermissionAlert from '../PermissionAlert/PermissionAlert';\nimport styles from './QuayRepository.module.css';\nimport { columns } from './tableHeading';\n\ntype QuayRepositoryProps = Record<never, any>;\n\nexport function QuayRepository(_props: QuayRepositoryProps) {\n const { instanceName, repository, organization } = useRepository();\n const quayApi = useApi(quayApiRef);\n\n const instanceConfig = quayApi.getQuayInstance(instanceName);\n const quayUiUrl = instanceConfig?.apiUrl ?? instanceConfig?.uiUrl;\n\n const hasViewPermission = useQuayViewPermission();\n\n const title = quayUiUrl ? (\n <>\n {`Quay repository: `}\n <Link\n to={`${quayUiUrl}/repository/${organization}/${repository}`}\n >{`${organization}/${repository}`}</Link>\n </>\n ) : (\n `Quay repository: ${organization}/${repository}`\n );\n const { loading, data } = useTags(instanceName, organization, repository);\n\n if (!hasViewPermission) {\n return <PermissionAlert />;\n }\n\n if (loading) {\n return (\n <div data-testid=\"quay-repo-progress\">\n <Progress />\n </div>\n );\n }\n\n return (\n <div data-testid=\"quay-repo-table\">\n <Table\n title={title}\n options={{ sorting: true, paging: true, padding: 'dense' }}\n data={data}\n columns={columns}\n emptyContent={\n <Box\n data-testid=\"quay-repo-table-empty\"\n p=\"4\"\n className={styles.emptyState}\n >\n <Flex direction=\"column\" align=\"center\" gap=\"2\">\n <Text variant=\"title-small\">No container images found</Text>\n <Text variant=\"body-medium\" color=\"secondary\">\n This repository doesn't contain any images yet, or there might\n be an access issue.\n </Text>\n </Flex>\n <Flex\n direction=\"column\"\n align=\"center\"\n gap=\"2\"\n className={styles.emptyStateSection}\n >\n <Text variant=\"body-small\" weight=\"bold\">\n Possible solutions:\n </Text>\n <Text variant=\"body-small\">\n 1. Check if images have been pushed to this repository\n </Text>\n <Text variant=\"body-small\">\n 2. Review the application logs in your Backstage instance\n </Text>\n <Text variant=\"body-small\">\n 3. Verify your entity annotations are{' '}\n <Link to={DOC_LINKS.BACKEND_ANNOTATIONS_GUIDE}>\n configured correctly\n </Link>\n </Text>\n <Text variant=\"body-small\">\n 4. Verify your{' '}\n <Link to={DOC_LINKS.AUTH_TOKEN_GUIDE}>Quay access tokens</Link>{' '}\n are{' '}\n <Link to={DOC_LINKS.BACKEND_CONFIGURATION_GUIDE}>\n configured correctly\n </Link>\n </Text>\n </Flex>\n </Box>\n }\n />\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import styleInject from '../../node_modules_dist/style-inject/dist/style-inject.es.esm.js';
2
+
3
+ var css_248z = "@layer components {\n .QuayRepository_emptyState__07436f381e {\n text-align: center;\n }\n\n .QuayRepository_emptyStateSection__07436f381e {\n margin-top: var(--bui-space-4);\n }\n}\n";
4
+ var styles = {"emptyState":"QuayRepository_emptyState__07436f381e","emptyStateSection":"QuayRepository_emptyStateSection__07436f381e"};
5
+ styleInject(css_248z);
6
+
7
+ export { styles as default };
8
+ //# sourceMappingURL=QuayRepository.module.css.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuayRepository.module.css.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -1,7 +1,6 @@
1
- import { jsx } from 'react/jsx-runtime';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { Progress, Link } from '@backstage/core-components';
3
- import { Tooltip } from '@material-ui/core';
4
- import makeStyles from '@material-ui/core/styles/makeStyles';
3
+ import { TooltipTrigger, Tooltip } from '@backstage/ui';
5
4
  import { securityScanComparator, vulnerabilitySummary } from '../../lib/utils.esm.js';
6
5
 
7
6
  const columns = [
@@ -24,10 +23,16 @@ const columns = [
24
23
  return /* @__PURE__ */ jsx("span", { "data-testid": "quay-repo-security-scan-progress", children: /* @__PURE__ */ jsx(Progress, {}) });
25
24
  }
26
25
  if (rowData.securityStatus === "queued") {
27
- return /* @__PURE__ */ jsx(Tooltip, { title: "The manifest for this tag is queued to be scanned for vulnerabilities", children: /* @__PURE__ */ jsx("span", { "data-testid": "quay-repo-queued-for-scan", children: "Queued" }) });
26
+ return /* @__PURE__ */ jsxs(TooltipTrigger, { children: [
27
+ /* @__PURE__ */ jsx("span", { "data-testid": "quay-repo-queued-for-scan", children: "Queued" }),
28
+ /* @__PURE__ */ jsx(Tooltip, { children: "The manifest for this tag is queued to be scanned for vulnerabilities" })
29
+ ] });
28
30
  }
29
31
  if (rowData.securityStatus === "unsupported") {
30
- return /* @__PURE__ */ jsx(Tooltip, { title: "The manifest for this tag has an operating system or package manager unsupported by Quay Security Scanner", children: /* @__PURE__ */ jsx("span", { "data-testid": "quay-repo-security-scan-unsupported", children: "Unsupported" }) });
32
+ return /* @__PURE__ */ jsxs(TooltipTrigger, { children: [
33
+ /* @__PURE__ */ jsx("span", { "data-testid": "quay-repo-security-scan-unsupported", children: "Unsupported" }),
34
+ /* @__PURE__ */ jsx(Tooltip, { children: "The manifest for this tag has an operating system or package manager unsupported by Quay Security Scanner" })
35
+ ] });
31
36
  }
32
37
  const tagManifest = rowData.manifest_digest_raw;
33
38
  const retStr = vulnerabilitySummary(rowData.securityDetails);
@@ -46,7 +51,7 @@ const columns = [
46
51
  {
47
52
  title: "Size",
48
53
  field: "size",
49
- type: "numeric",
54
+ type: "string",
50
55
  customSort: (a, b) => a.rawSize - b.rawSize
51
56
  },
52
57
  {
@@ -62,13 +67,6 @@ const columns = [
62
67
  customSort: (a, b) => a.manifest_digest_raw.localeCompare(b.manifest_digest_raw)
63
68
  }
64
69
  ];
65
- makeStyles((theme) => ({
66
- empty: {
67
- padding: theme.spacing(2),
68
- display: "flex",
69
- justifyContent: "center"
70
- }
71
- }));
72
70
 
73
71
  export { columns };
74
72
  //# sourceMappingURL=tableHeading.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tableHeading.esm.js","sources":["../../../src/components/QuayRepository/tableHeading.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { ReactNode } from 'react';\n\nimport { Link, Progress, TableColumn } from '@backstage/core-components';\n\nimport { Tooltip } from '@material-ui/core';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\n\nimport { securityScanComparator, vulnerabilitySummary } from '../../lib/utils';\nimport type { QuayTagData } from '../../types';\n\nexport const columns: TableColumn<QuayTagData>[] = [\n {\n title: 'Tag',\n field: 'name',\n type: 'string',\n highlight: true,\n },\n {\n title: 'Last Modified',\n field: 'last_modified',\n type: 'date',\n },\n {\n title: 'Security Scan',\n field: 'securityScan',\n render: (rowData: QuayTagData): ReactNode => {\n if (!rowData.securityStatus && !rowData.securityDetails) {\n return (\n <span data-testid=\"quay-repo-security-scan-progress\">\n <Progress />\n </span>\n );\n }\n\n if (rowData.securityStatus === 'queued') {\n return (\n <Tooltip title=\"The manifest for this tag is queued to be scanned for vulnerabilities\">\n <span data-testid=\"quay-repo-queued-for-scan\">Queued</span>\n </Tooltip>\n );\n }\n\n if (rowData.securityStatus === 'unsupported') {\n return (\n <Tooltip title=\"The manifest for this tag has an operating system or package manager unsupported by Quay Security Scanner\">\n <span data-testid=\"quay-repo-security-scan-unsupported\">\n Unsupported\n </span>\n </Tooltip>\n );\n }\n\n const tagManifest = rowData.manifest_digest_raw;\n const retStr = vulnerabilitySummary(rowData.securityDetails);\n return (\n <Link\n data-testid={`${rowData.name}-security-scan`}\n to={`tag/${tagManifest}`}\n >\n {retStr}\n </Link>\n );\n },\n id: 'securityScan',\n customSort: (a: QuayTagData, b: QuayTagData) =>\n securityScanComparator(a, b),\n },\n {\n title: 'Size',\n field: 'size',\n type: 'numeric',\n customSort: (a: QuayTagData, b: QuayTagData) => a.rawSize - b.rawSize,\n },\n {\n title: 'Expires',\n field: 'expiration',\n type: 'date',\n emptyValue: <i>Never</i>,\n },\n {\n title: 'Manifest',\n field: 'manifest_digest',\n type: 'string',\n customSort: (a: QuayTagData, b: QuayTagData) =>\n a.manifest_digest_raw.localeCompare(b.manifest_digest_raw),\n },\n];\n\nexport const useStyles = makeStyles(theme => ({\n empty: {\n padding: theme.spacing(2),\n display: 'flex',\n justifyContent: 'center',\n },\n}));\n"],"names":[],"mappings":";;;;;;AAyBO,MAAM,OAAA,GAAsC;AAAA,EACjD;AAAA,IACE,KAAA,EAAO,KAAA;AAAA,IACP,KAAA,EAAO,MAAA;AAAA,IACP,IAAA,EAAM,QAAA;AAAA,IACN,SAAA,EAAW;AAAA,GACb;AAAA,EACA;AAAA,IACE,KAAA,EAAO,eAAA;AAAA,IACP,KAAA,EAAO,eAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EAAO,eAAA;AAAA,IACP,KAAA,EAAO,cAAA;AAAA,IACP,MAAA,EAAQ,CAAC,OAAA,KAAoC;AAC3C,MAAA,IAAI,CAAC,OAAA,CAAQ,cAAA,IAAkB,CAAC,QAAQ,eAAA,EAAiB;AACvD,QAAA,2BACG,MAAA,EAAA,EAAK,aAAA,EAAY,kCAAA,EAChB,QAAA,kBAAA,GAAA,CAAC,YAAS,CAAA,EACZ,CAAA;AAAA,MAEJ;AAEA,MAAA,IAAI,OAAA,CAAQ,mBAAmB,QAAA,EAAU;AACvC,QAAA,uBACE,GAAA,CAAC,WAAQ,KAAA,EAAM,uEAAA,EACb,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAY,2BAAA,EAA4B,QAAA,EAAA,QAAA,EAAM,CAAA,EACtD,CAAA;AAAA,MAEJ;AAEA,MAAA,IAAI,OAAA,CAAQ,mBAAmB,aAAA,EAAe;AAC5C,QAAA,uBACE,GAAA,CAAC,WAAQ,KAAA,EAAM,2GAAA,EACb,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAY,qCAAA,EAAsC,QAAA,EAAA,aAAA,EAExD,CAAA,EACF,CAAA;AAAA,MAEJ;AAEA,MAAA,MAAM,cAAc,OAAA,CAAQ,mBAAA;AAC5B,MAAA,MAAM,MAAA,GAAS,oBAAA,CAAqB,OAAA,CAAQ,eAAe,CAAA;AAC3D,MAAA,uBACE,GAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,aAAA,EAAa,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA,cAAA,CAAA;AAAA,UAC5B,EAAA,EAAI,OAAO,WAAW,CAAA,CAAA;AAAA,UAErB,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,IAEJ,CAAA;AAAA,IACA,EAAA,EAAI,cAAA;AAAA,IACJ,YAAY,CAAC,CAAA,EAAgB,CAAA,KAC3B,sBAAA,CAAuB,GAAG,CAAC;AAAA,GAC/B;AAAA,EACA;AAAA,IACE,KAAA,EAAO,MAAA;AAAA,IACP,KAAA,EAAO,MAAA;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,YAAY,CAAC,CAAA,EAAgB,CAAA,KAAmB,CAAA,CAAE,UAAU,CAAA,CAAE;AAAA,GAChE;AAAA,EACA;AAAA,IACE,KAAA,EAAO,SAAA;AAAA,IACP,KAAA,EAAO,YAAA;AAAA,IACP,IAAA,EAAM,MAAA;AAAA,IACN,UAAA,kBAAY,GAAA,CAAC,GAAA,EAAA,EAAE,QAAA,EAAA,OAAA,EAAK;AAAA,GACtB;AAAA,EACA;AAAA,IACE,KAAA,EAAO,UAAA;AAAA,IACP,KAAA,EAAO,iBAAA;AAAA,IACP,IAAA,EAAM,QAAA;AAAA,IACN,UAAA,EAAY,CAAC,CAAA,EAAgB,CAAA,KAC3B,EAAE,mBAAA,CAAoB,aAAA,CAAc,EAAE,mBAAmB;AAAA;AAE/D;AAEyB,WAAW,CAAA,KAAA,MAAU;AAAA,EAC5C,KAAA,EAAO;AAAA,IACL,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,IACxB,OAAA,EAAS,MAAA;AAAA,IACT,cAAA,EAAgB;AAAA;AAEpB,CAAA,CAAE;;;;"}
1
+ {"version":3,"file":"tableHeading.esm.js","sources":["../../../src/components/QuayRepository/tableHeading.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { ReactNode } from 'react';\n\nimport { Link, Progress, TableColumn } from '@backstage/core-components';\nimport { Tooltip, TooltipTrigger } from '@backstage/ui';\n\nimport { securityScanComparator, vulnerabilitySummary } from '../../lib/utils';\nimport type { QuayTagData } from '../../types';\n\nexport const columns: TableColumn<QuayTagData>[] = [\n {\n title: 'Tag',\n field: 'name',\n type: 'string',\n highlight: true,\n },\n {\n title: 'Last Modified',\n field: 'last_modified',\n type: 'date',\n },\n {\n title: 'Security Scan',\n field: 'securityScan',\n render: (rowData: QuayTagData): ReactNode => {\n if (!rowData.securityStatus && !rowData.securityDetails) {\n return (\n <span data-testid=\"quay-repo-security-scan-progress\">\n <Progress />\n </span>\n );\n }\n\n if (rowData.securityStatus === 'queued') {\n return (\n <TooltipTrigger>\n <span data-testid=\"quay-repo-queued-for-scan\">Queued</span>\n <Tooltip>\n The manifest for this tag is queued to be scanned for\n vulnerabilities\n </Tooltip>\n </TooltipTrigger>\n );\n }\n\n if (rowData.securityStatus === 'unsupported') {\n return (\n <TooltipTrigger>\n <span data-testid=\"quay-repo-security-scan-unsupported\">\n Unsupported\n </span>\n <Tooltip>\n The manifest for this tag has an operating system or package\n manager unsupported by Quay Security Scanner\n </Tooltip>\n </TooltipTrigger>\n );\n }\n\n const tagManifest = rowData.manifest_digest_raw;\n const retStr = vulnerabilitySummary(rowData.securityDetails);\n return (\n <Link\n data-testid={`${rowData.name}-security-scan`}\n to={`tag/${tagManifest}`}\n >\n {retStr}\n </Link>\n );\n },\n id: 'securityScan',\n customSort: (a: QuayTagData, b: QuayTagData) =>\n securityScanComparator(a, b),\n },\n {\n title: 'Size',\n field: 'size',\n type: 'string',\n customSort: (a: QuayTagData, b: QuayTagData) => a.rawSize - b.rawSize,\n },\n {\n title: 'Expires',\n field: 'expiration',\n type: 'date',\n emptyValue: <i>Never</i>,\n },\n {\n title: 'Manifest',\n field: 'manifest_digest',\n type: 'string',\n customSort: (a: QuayTagData, b: QuayTagData) =>\n a.manifest_digest_raw.localeCompare(b.manifest_digest_raw),\n },\n];\n"],"names":[],"mappings":";;;;;AAuBO,MAAM,OAAA,GAAsC;AAAA,EACjD;AAAA,IACE,KAAA,EAAO,KAAA;AAAA,IACP,KAAA,EAAO,MAAA;AAAA,IACP,IAAA,EAAM,QAAA;AAAA,IACN,SAAA,EAAW;AAAA,GACb;AAAA,EACA;AAAA,IACE,KAAA,EAAO,eAAA;AAAA,IACP,KAAA,EAAO,eAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EAAO,eAAA;AAAA,IACP,KAAA,EAAO,cAAA;AAAA,IACP,MAAA,EAAQ,CAAC,OAAA,KAAoC;AAC3C,MAAA,IAAI,CAAC,OAAA,CAAQ,cAAA,IAAkB,CAAC,QAAQ,eAAA,EAAiB;AACvD,QAAA,2BACG,MAAA,EAAA,EAAK,aAAA,EAAY,kCAAA,EAChB,QAAA,kBAAA,GAAA,CAAC,YAAS,CAAA,EACZ,CAAA;AAAA,MAEJ;AAEA,MAAA,IAAI,OAAA,CAAQ,mBAAmB,QAAA,EAAU;AACvC,QAAA,4BACG,cAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAY,2BAAA,EAA4B,QAAA,EAAA,QAAA,EAAM,CAAA;AAAA,0BACpD,GAAA,CAAC,WAAQ,QAAA,EAAA,uEAAA,EAGT;AAAA,SAAA,EACF,CAAA;AAAA,MAEJ;AAEA,MAAA,IAAI,OAAA,CAAQ,mBAAmB,aAAA,EAAe;AAC5C,QAAA,4BACG,cAAA,EAAA,EACC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAY,qCAAA,EAAsC,QAAA,EAAA,aAAA,EAExD,CAAA;AAAA,0BACA,GAAA,CAAC,WAAQ,QAAA,EAAA,2GAAA,EAGT;AAAA,SAAA,EACF,CAAA;AAAA,MAEJ;AAEA,MAAA,MAAM,cAAc,OAAA,CAAQ,mBAAA;AAC5B,MAAA,MAAM,MAAA,GAAS,oBAAA,CAAqB,OAAA,CAAQ,eAAe,CAAA;AAC3D,MAAA,uBACE,GAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,aAAA,EAAa,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA,cAAA,CAAA;AAAA,UAC5B,EAAA,EAAI,OAAO,WAAW,CAAA,CAAA;AAAA,UAErB,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,IAEJ,CAAA;AAAA,IACA,EAAA,EAAI,cAAA;AAAA,IACJ,YAAY,CAAC,CAAA,EAAgB,CAAA,KAC3B,sBAAA,CAAuB,GAAG,CAAC;AAAA,GAC/B;AAAA,EACA;AAAA,IACE,KAAA,EAAO,MAAA;AAAA,IACP,KAAA,EAAO,MAAA;AAAA,IACP,IAAA,EAAM,QAAA;AAAA,IACN,YAAY,CAAC,CAAA,EAAgB,CAAA,KAAmB,CAAA,CAAE,UAAU,CAAA,CAAE;AAAA,GAChE;AAAA,EACA;AAAA,IACE,KAAA,EAAO,SAAA;AAAA,IACP,KAAA,EAAO,YAAA;AAAA,IACP,IAAA,EAAM,MAAA;AAAA,IACN,UAAA,kBAAY,GAAA,CAAC,GAAA,EAAA,EAAE,QAAA,EAAA,OAAA,EAAK;AAAA,GACtB;AAAA,EACA;AAAA,IACE,KAAA,EAAO,UAAA;AAAA,IACP,KAAA,EAAO,iBAAA;AAAA,IACP,IAAA,EAAM,QAAA;AAAA,IACN,UAAA,EAAY,CAAC,CAAA,EAAgB,CAAA,KAC3B,EAAE,mBAAA,CAAoB,aAAA,CAAc,EAAE,mBAAmB;AAAA;AAE/D;;;;"}
@@ -0,0 +1,8 @@
1
+ import styleInject from '../../node_modules_dist/style-inject/dist/style-inject.es.esm.js';
2
+
3
+ var css_248z = "@layer components {\n .QuayTagDetails_cellContent__62f606d7a1 {\n display: inline-flex;\n width: fit-content;\n }\n\n .QuayTagDetails_severityIcon__62f606d7a1 {\n flex-shrink: 0;\n }\n}\n";
4
+ var styles = {"cellContent":"QuayTagDetails_cellContent__62f606d7a1","severityIcon":"QuayTagDetails_severityIcon__62f606d7a1"};
5
+ styleInject(css_248z);
6
+
7
+ export { styles as default };
8
+ //# sourceMappingURL=QuayTagDetails.module.css.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuayTagDetails.module.css.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -1,11 +1,10 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
2
  import { Link, Table } from '@backstage/core-components';
3
- import { TableContainer, TableHead, makeStyles } from '@material-ui/core';
4
- import KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace';
5
- import LinkIcon from '@material-ui/icons/Link';
6
- import WarningIcon from '@material-ui/icons/Warning';
3
+ import { Flex, Text } from '@backstage/ui';
4
+ import { RiArrowLeftLine, RiLinkM, RiAlertLine } from '@remixicon/react';
7
5
  import { SEVERITY_COLORS } from '../../lib/utils.esm.js';
8
6
  import { VulnerabilityOrder } from '../../types.esm.js';
7
+ import styles from './QuayTagDetails.module.css.esm.js';
9
8
 
10
9
  const getVulnerabilityLink = (link) => link.split(" ")[0];
11
10
  const columns = [
@@ -13,9 +12,17 @@ const columns = [
13
12
  title: "Advisory",
14
13
  field: "name",
15
14
  render: (rowData) => {
16
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
15
+ const link = rowData.Link.trim();
16
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "2", className: styles.cellContent, children: [
17
17
  rowData.Name,
18
- rowData.Link.trim().length > 0 ? /* @__PURE__ */ jsx(Link, { to: getVulnerabilityLink(rowData.Link), children: /* @__PURE__ */ jsx(LinkIcon, { style: { marginLeft: "0.5rem" } }) }) : null
18
+ link.length > 0 ? /* @__PURE__ */ jsx(
19
+ Link,
20
+ {
21
+ to: getVulnerabilityLink(link),
22
+ "aria-label": `Open advisory link for ${rowData.Name}`,
23
+ children: /* @__PURE__ */ jsx(RiLinkM, { size: 16 })
24
+ }
25
+ ) : null
19
26
  ] });
20
27
  },
21
28
  customSort: (a, b) => a.Name.localeCompare(b.Name, "en")
@@ -29,14 +36,13 @@ const columns = [
29
36
  return severityA - severityB;
30
37
  },
31
38
  render: (rowData) => {
32
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
39
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "2", className: styles.cellContent, children: [
33
40
  /* @__PURE__ */ jsx(
34
- WarningIcon,
41
+ RiAlertLine,
35
42
  {
36
- htmlColor: SEVERITY_COLORS[rowData.Severity],
37
- style: {
38
- marginRight: "0.5rem"
39
- }
43
+ className: styles.severityIcon,
44
+ color: SEVERITY_COLORS[rowData.Severity],
45
+ size: 20
40
46
  }
41
47
  ),
42
48
  /* @__PURE__ */ jsx("span", { children: rowData.Severity })
@@ -61,27 +67,11 @@ const columns = [
61
67
  }
62
68
  }
63
69
  ];
64
- const useStyles = makeStyles({
65
- link: {
66
- display: "flex",
67
- alignItems: "center"
68
- },
69
- linkText: {
70
- marginLeft: "0.5rem",
71
- fontSize: "1.1rem"
72
- },
73
- tableHead: {
74
- display: "flex",
75
- alignItems: "center",
76
- marginBottom: "1rem"
77
- }
78
- });
79
70
  const QuayTagDetails = ({
80
71
  layer,
81
72
  rootLink,
82
73
  digest
83
74
  }) => {
84
- const classes = useStyles();
85
75
  const vulnerabilities = layer.Features.filter(
86
76
  (feat) => typeof feat.Vulnerabilities !== "undefined"
87
77
  ).map((feature) => {
@@ -99,11 +89,11 @@ const QuayTagDetails = ({
99
89
  const severityB = VulnerabilityOrder[b.Severity];
100
90
  return severityA - severityB;
101
91
  });
102
- return /* @__PURE__ */ jsxs(TableContainer, { children: [
103
- /* @__PURE__ */ jsx(TableHead, { className: classes.tableHead, children: /* @__PURE__ */ jsxs(Link, { to: rootLink(), className: classes.link, children: [
104
- /* @__PURE__ */ jsx(KeyboardBackspaceIcon, {}),
105
- /* @__PURE__ */ jsx("span", { className: classes.linkText, children: "Back to repository" })
106
- ] }) }),
92
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
93
+ /* @__PURE__ */ jsx(Flex, { align: "center", mb: "4", children: /* @__PURE__ */ jsx(Link, { to: rootLink(), children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "2", children: [
94
+ /* @__PURE__ */ jsx(RiArrowLeftLine, { size: 20 }),
95
+ /* @__PURE__ */ jsx(Text, { variant: "body-medium", children: "Back to repository" })
96
+ ] }) }) }),
107
97
  /* @__PURE__ */ jsx(
108
98
  Table,
109
99
  {
@@ -1 +1 @@
1
- {"version":3,"file":"component.esm.js","sources":["../../../src/components/QuayTagDetails/component.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { ReactNode } from 'react';\n\nimport { Link, Table, TableColumn } from '@backstage/core-components';\nimport type { RouteFunc } from '@backstage/core-plugin-api';\n\nimport { makeStyles, TableContainer, TableHead } from '@material-ui/core';\nimport KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace';\nimport LinkIcon from '@material-ui/icons/Link';\nimport WarningIcon from '@material-ui/icons/Warning';\n\nimport { SEVERITY_COLORS } from '../../lib/utils';\nimport {\n Layer,\n Vulnerability,\n VulnerabilityListItem,\n VulnerabilityOrder,\n} from '../../types';\n\ntype QuayTagDetailsProps = {\n layer: Layer;\n digest: string;\n rootLink: RouteFunc<undefined>;\n};\n\n// from: https://github.com/quay/quay/blob/f1d85588157eababc3cbf789002c5db521dbd616/web/src/routes/TagDetails/SecurityReport/SecurityReportTable.tsx#L43\nconst getVulnerabilityLink = (link: string) => link.split(' ')[0];\n\nconst columns: TableColumn<VulnerabilityListItem>[] = [\n {\n title: 'Advisory',\n field: 'name',\n render: (rowData: VulnerabilityListItem): ReactNode => {\n return (\n <div style={{ display: 'flex', alignItems: 'center' }}>\n {rowData.Name}\n {rowData.Link.trim().length > 0 ? (\n <Link to={getVulnerabilityLink(rowData.Link)}>\n <LinkIcon style={{ marginLeft: '0.5rem' }} />\n </Link>\n ) : null}\n </div>\n );\n },\n customSort: (a: VulnerabilityListItem, b: VulnerabilityListItem) =>\n a.Name.localeCompare(b.Name, 'en'),\n },\n {\n title: 'Severity',\n field: 'Severity',\n customSort: (a: VulnerabilityListItem, b: VulnerabilityListItem) => {\n const severityA = VulnerabilityOrder[a.Severity];\n const severityB = VulnerabilityOrder[b.Severity];\n\n return severityA - severityB;\n },\n render: (rowData: VulnerabilityListItem): ReactNode => {\n return (\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <WarningIcon\n htmlColor={SEVERITY_COLORS[rowData.Severity]}\n style={{\n marginRight: '0.5rem',\n }}\n />\n <span>{rowData.Severity}</span>\n </div>\n );\n },\n },\n {\n title: 'Package Name',\n field: 'PackageName',\n type: 'string',\n },\n {\n title: 'Current Version',\n field: 'CurrentVersion',\n type: 'string',\n },\n {\n title: 'Fixed By',\n field: 'FixedBy',\n render: (rowData: VulnerabilityListItem): ReactNode => {\n return (\n <>\n {rowData.FixedBy.length > 0 ? (\n <span>{rowData.FixedBy}</span>\n ) : (\n '(None)'\n )}\n </>\n );\n },\n },\n];\n\nconst useStyles = makeStyles({\n link: {\n display: 'flex',\n alignItems: 'center',\n },\n linkText: {\n marginLeft: '0.5rem',\n fontSize: '1.1rem',\n },\n tableHead: {\n display: 'flex',\n alignItems: 'center',\n marginBottom: '1rem',\n },\n});\n\nexport const QuayTagDetails = ({\n layer,\n rootLink,\n digest,\n}: QuayTagDetailsProps) => {\n const classes = useStyles();\n const vulnerabilities = layer.Features.filter(\n feat => typeof feat.Vulnerabilities !== 'undefined',\n )\n .map(feature => {\n // TS doesn't seem to register this list as never being undefined from the above filter\n // so we cast it into the list\n // NOSONAR - irrelevant as per above comment\n return (feature.Vulnerabilities as Vulnerability[]).map(\n (v: Vulnerability): VulnerabilityListItem => {\n return {\n ...v,\n PackageName: feature.Name,\n CurrentVersion: feature.Version,\n };\n },\n );\n })\n .flat()\n .sort((a, b) => {\n const severityA = VulnerabilityOrder[a.Severity];\n const severityB = VulnerabilityOrder[b.Severity];\n\n return severityA - severityB;\n });\n\n return (\n <TableContainer>\n <TableHead className={classes.tableHead}>\n <Link to={rootLink()} className={classes.link}>\n <KeyboardBackspaceIcon />\n <span className={classes.linkText}>Back to repository</span>\n </Link>\n </TableHead>\n <Table\n title={`Vulnerabilities for ${digest.substring(0, 17)}`}\n data={vulnerabilities}\n columns={columns}\n />\n </TableContainer>\n );\n};\n\nexport default QuayTagDetails;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"component.esm.js","sources":["../../../src/components/QuayTagDetails/component.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { ReactNode } from 'react';\n\nimport { Link, Table, TableColumn } from '@backstage/core-components';\nimport type { RouteFunc } from '@backstage/core-plugin-api';\nimport { Flex, Text } from '@backstage/ui';\n\nimport { RiAlertLine, RiArrowLeftLine, RiLinkM } from '@remixicon/react';\n\nimport { SEVERITY_COLORS } from '../../lib/utils';\nimport {\n Layer,\n Vulnerability,\n VulnerabilityListItem,\n VulnerabilityOrder,\n} from '../../types';\nimport styles from './QuayTagDetails.module.css';\n\ntype QuayTagDetailsProps = {\n layer: Layer;\n digest: string;\n rootLink: RouteFunc<undefined>;\n};\n\n// from: https://github.com/quay/quay/blob/f1d85588157eababc3cbf789002c5db521dbd616/web/src/routes/TagDetails/SecurityReport/SecurityReportTable.tsx#L43\nconst getVulnerabilityLink = (link: string) => link.split(' ')[0];\n\nconst columns: TableColumn<VulnerabilityListItem>[] = [\n {\n title: 'Advisory',\n field: 'name',\n render: (rowData: VulnerabilityListItem): ReactNode => {\n const link = rowData.Link.trim();\n return (\n <Flex align=\"center\" gap=\"2\" className={styles.cellContent}>\n {rowData.Name}\n {link.length > 0 ? (\n <Link\n to={getVulnerabilityLink(link)}\n aria-label={`Open advisory link for ${rowData.Name}`}\n >\n <RiLinkM size={16} />\n </Link>\n ) : null}\n </Flex>\n );\n },\n customSort: (a: VulnerabilityListItem, b: VulnerabilityListItem) =>\n a.Name.localeCompare(b.Name, 'en'),\n },\n {\n title: 'Severity',\n field: 'Severity',\n customSort: (a: VulnerabilityListItem, b: VulnerabilityListItem) => {\n const severityA = VulnerabilityOrder[a.Severity];\n const severityB = VulnerabilityOrder[b.Severity];\n\n return severityA - severityB;\n },\n render: (rowData: VulnerabilityListItem): ReactNode => {\n return (\n <Flex align=\"center\" gap=\"2\" className={styles.cellContent}>\n <RiAlertLine\n className={styles.severityIcon}\n color={SEVERITY_COLORS[rowData.Severity]}\n size={20}\n />\n <span>{rowData.Severity}</span>\n </Flex>\n );\n },\n },\n {\n title: 'Package Name',\n field: 'PackageName',\n type: 'string',\n },\n {\n title: 'Current Version',\n field: 'CurrentVersion',\n type: 'string',\n },\n {\n title: 'Fixed By',\n field: 'FixedBy',\n render: (rowData: VulnerabilityListItem): ReactNode => {\n return (\n <>\n {rowData.FixedBy.length > 0 ? (\n <span>{rowData.FixedBy}</span>\n ) : (\n '(None)'\n )}\n </>\n );\n },\n },\n];\n\nexport const QuayTagDetails = ({\n layer,\n rootLink,\n digest,\n}: QuayTagDetailsProps) => {\n const vulnerabilities = layer.Features.filter(\n feat => typeof feat.Vulnerabilities !== 'undefined',\n )\n .map(feature => {\n return (feature.Vulnerabilities as Vulnerability[]).map(\n (v: Vulnerability): VulnerabilityListItem => {\n return {\n ...v,\n PackageName: feature.Name,\n CurrentVersion: feature.Version,\n };\n },\n );\n })\n .flat()\n .sort((a, b) => {\n const severityA = VulnerabilityOrder[a.Severity];\n const severityB = VulnerabilityOrder[b.Severity];\n\n return severityA - severityB;\n });\n\n return (\n <>\n <Flex align=\"center\" mb=\"4\">\n <Link to={rootLink()}>\n <Flex align=\"center\" gap=\"2\">\n <RiArrowLeftLine size={20} />\n <Text variant=\"body-medium\">Back to repository</Text>\n </Flex>\n </Link>\n </Flex>\n <Table\n title={`Vulnerabilities for ${digest.substring(0, 17)}`}\n data={vulnerabilities}\n columns={columns}\n />\n </>\n );\n};\n\nexport default QuayTagDetails;\n"],"names":[],"mappings":"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"}
@@ -1,28 +1,24 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useState, useMemo } from 'react';
2
+ import { useRef, useState, useEffect, useMemo } from 'react';
3
3
  import { useAsync } from 'react-use';
4
4
  import { useApi } from '@backstage/core-plugin-api';
5
5
  import { useEntity } from '@backstage/plugin-catalog-react';
6
- import { makeStyles, Box, Chip } from '@material-ui/core';
6
+ import { Flex, TagGroup, Tag, Text } from '@backstage/ui';
7
7
  import { quayApiRef } from '../api/index.esm.js';
8
8
  import { formatDate, formatByteSize } from '../utils.esm.js';
9
9
 
10
- const useLocalStyles = makeStyles({
11
- chip: {
12
- margin: 0,
13
- marginRight: ".2em",
14
- height: "1.5em",
15
- "& > span": {
16
- padding: ".3em"
17
- }
18
- }
19
- });
20
10
  const useTags = (instanceName, organization, repository) => {
21
11
  const quayClient = useApi(quayApiRef);
12
+ const requestIdRef = useRef(0);
22
13
  const [tags, setTags] = useState([]);
23
14
  const [tagManifestLayers, setTagManifestLayers] = useState({});
24
15
  const [tagManifestStatuses, setTagManifestStatuses] = useState({});
25
- const localClasses = useLocalStyles();
16
+ useEffect(() => {
17
+ requestIdRef.current += 1;
18
+ setTags([]);
19
+ setTagManifestLayers({});
20
+ setTagManifestStatuses({});
21
+ }, [instanceName, organization, repository]);
26
22
  const fetchSecurityDetails = async (tag) => {
27
23
  const securityDetails = await quayClient.getSecurityDetails(
28
24
  instanceName,
@@ -33,6 +29,7 @@ const useTags = (instanceName, organization, repository) => {
33
29
  return securityDetails;
34
30
  };
35
31
  const { loading } = useAsync(async () => {
32
+ const requestId = requestIdRef.current;
36
33
  const tagsResponse = await quayClient.getTags(
37
34
  instanceName,
38
35
  organization,
@@ -40,9 +37,16 @@ const useTags = (instanceName, organization, repository) => {
40
37
  void 0,
41
38
  void 0
42
39
  );
43
- Promise.all(
40
+ if (requestId !== requestIdRef.current) {
41
+ return tagsResponse;
42
+ }
43
+ setTags(tagsResponse.tags);
44
+ void Promise.all(
44
45
  tagsResponse.tags.map(async (tag) => {
45
46
  const securityDetails = await fetchSecurityDetails(tag);
47
+ if (requestId !== requestIdRef.current) {
48
+ return;
49
+ }
46
50
  const securityData = securityDetails.data;
47
51
  const securityStatus = securityDetails.status;
48
52
  setTagManifestStatuses((prevState) => ({
@@ -57,9 +61,8 @@ const useTags = (instanceName, organization, repository) => {
57
61
  }
58
62
  })
59
63
  );
60
- setTags((prevTags) => [...prevTags, ...tagsResponse.tags]);
61
64
  return tagsResponse;
62
- });
65
+ }, [instanceName, organization, repository]);
63
66
  const data = useMemo(() => {
64
67
  return Object.values(tags)?.map((tag) => {
65
68
  const hashFunc = tag.manifest_digest.substring(0, 6);
@@ -70,22 +73,17 @@ const useTags = (instanceName, organization, repository) => {
70
73
  last_modified: formatDate(tag.last_modified),
71
74
  size: formatByteSize(tag.size),
72
75
  rawSize: tag.size,
73
- manifest_digest: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center" }, children: [
74
- /* @__PURE__ */ jsx(Chip, { label: hashFunc, className: localClasses.chip }),
75
- shortHash
76
+ manifest_digest: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "1", children: [
77
+ /* @__PURE__ */ jsx(TagGroup, { children: /* @__PURE__ */ jsx(Tag, { size: "small", children: hashFunc }) }),
78
+ /* @__PURE__ */ jsx(Text, { variant: "body-x-small", children: shortHash })
76
79
  ] }),
77
80
  expiration: tag.expiration ? formatDate(tag.expiration) : tag.expiration,
78
81
  securityDetails: tagManifestLayers[tag.manifest_digest],
79
82
  securityStatus: tagManifestStatuses[tag.manifest_digest],
80
83
  manifest_digest_raw: tag.manifest_digest
81
- // is_manifest_list: tag.is_manifest_list,
82
- // reversion: tag.reversion,
83
- // start_ts: tag.start_ts,
84
- // end_ts: tag.end_ts,
85
- // manifest_list: tag.manifest_list,
86
84
  };
87
85
  });
88
- }, [tags, localClasses.chip, tagManifestLayers, tagManifestStatuses]);
86
+ }, [tags, tagManifestLayers, tagManifestStatuses]);
89
87
  return { loading, data };
90
88
  };
91
89
  const QUAY_ANNOTATION_REPOSITORY = "quay.io/repository-slug";
@@ -1 +1 @@
1
- {"version":3,"file":"quay.esm.js","sources":["../../src/hooks/quay.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useMemo, useState } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { Entity } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useEntity } from '@backstage/plugin-catalog-react';\n\nimport { Box, Chip, makeStyles } from '@material-ui/core';\n\nimport { quayApiRef } from '../api';\nimport { Layer, QuayTagData, Tag } from '../types';\nimport { formatByteSize, formatDate } from '../utils';\n\nconst useLocalStyles = makeStyles({\n chip: {\n margin: 0,\n marginRight: '.2em',\n height: '1.5em',\n '& > span': {\n padding: '.3em',\n },\n },\n});\n\nexport const useTags = (\n instanceName: string | undefined,\n organization: string,\n repository: string,\n) => {\n const quayClient = useApi(quayApiRef);\n const [tags, setTags] = useState<Tag[]>([]);\n const [tagManifestLayers, setTagManifestLayers] = useState<\n Record<string, Layer>\n >({});\n const [tagManifestStatuses, setTagManifestStatuses] = useState<\n Record<string, string>\n >({});\n const localClasses = useLocalStyles();\n\n const fetchSecurityDetails = async (tag: Tag) => {\n const securityDetails = await quayClient.getSecurityDetails(\n instanceName,\n organization,\n repository,\n tag.manifest_digest,\n );\n return securityDetails;\n };\n\n const { loading } = useAsync(async () => {\n const tagsResponse = await quayClient.getTags(\n instanceName,\n organization,\n repository,\n undefined,\n undefined,\n );\n Promise.all(\n tagsResponse.tags.map(async tag => {\n const securityDetails = await fetchSecurityDetails(tag);\n const securityData = securityDetails.data;\n const securityStatus = securityDetails.status;\n\n setTagManifestStatuses(prevState => ({\n ...prevState,\n [tag.manifest_digest]: securityStatus,\n }));\n\n if (securityData) {\n setTagManifestLayers(prevState => ({\n ...prevState,\n [tag.manifest_digest]: securityData.Layer,\n }));\n }\n }),\n );\n setTags(prevTags => [...prevTags, ...tagsResponse.tags]);\n return tagsResponse;\n });\n\n const data: QuayTagData[] = useMemo(() => {\n return Object.values(tags)?.map(tag => {\n const hashFunc = tag.manifest_digest.substring(0, 6);\n const shortHash = tag.manifest_digest.substring(7, 19);\n return {\n id: `${tag.manifest_digest}-${tag.name}`,\n name: tag.name,\n last_modified: formatDate(tag.last_modified),\n size: formatByteSize(tag.size),\n rawSize: tag.size,\n manifest_digest: (\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Chip label={hashFunc} className={localClasses.chip} />\n {shortHash}\n </Box>\n ),\n expiration: tag.expiration\n ? formatDate(tag.expiration)\n : tag.expiration,\n securityDetails: tagManifestLayers[tag.manifest_digest],\n securityStatus: tagManifestStatuses[tag.manifest_digest],\n manifest_digest_raw: tag.manifest_digest,\n // is_manifest_list: tag.is_manifest_list,\n // reversion: tag.reversion,\n // start_ts: tag.start_ts,\n // end_ts: tag.end_ts,\n // manifest_list: tag.manifest_list,\n };\n });\n }, [tags, localClasses.chip, tagManifestLayers, tagManifestStatuses]);\n\n return { loading, data };\n};\n\nexport const QUAY_ANNOTATION_REPOSITORY = 'quay.io/repository-slug';\nexport const QUAY_ANNOTATION_INSTANCE = 'quay.io/instance-name';\n\nexport const useQuayAppData = ({ entity }: { entity: Entity }) => {\n const instanceSlug = entity?.metadata.annotations?.[QUAY_ANNOTATION_INSTANCE];\n const repositorySlug =\n entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY] ?? '';\n\n if (!repositorySlug) {\n throw new Error(\"'Quay' annotations are missing\");\n }\n return { instanceSlug, repositorySlug };\n};\n\nexport const useRepository = () => {\n const { entity } = useEntity();\n const { instanceSlug: instanceName, repositorySlug } = useQuayAppData({\n entity,\n });\n const info = repositorySlug.split('/');\n\n const organization = info.shift() as 'string';\n const repository = info.join('/');\n return {\n instanceName,\n organization,\n repository,\n };\n};\n\nexport const useTagDetails = (\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n) => {\n const quayClient = useApi(quayApiRef);\n const result = useAsync(async () => {\n const manifestLayer = await quayClient.getSecurityDetails(\n instanceName,\n org,\n repo,\n digest,\n );\n return manifestLayer;\n });\n return result;\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quay.esm.js","sources":["../../src/hooks/quay.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { Entity } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { Flex, Tag, TagGroup, Text } from '@backstage/ui';\n\nimport { quayApiRef } from '../api';\nimport { Layer, Tag as QuayTag, QuayTagData } from '../types';\nimport { formatByteSize, formatDate } from '../utils';\n\nexport const useTags = (\n instanceName: string | undefined,\n organization: string,\n repository: string,\n) => {\n const quayClient = useApi(quayApiRef);\n const requestIdRef = useRef(0);\n const [tags, setTags] = useState<QuayTag[]>([]);\n const [tagManifestLayers, setTagManifestLayers] = useState<\n Record<string, Layer>\n >({});\n const [tagManifestStatuses, setTagManifestStatuses] = useState<\n Record<string, string>\n >({});\n\n useEffect(() => {\n requestIdRef.current += 1;\n setTags([]);\n setTagManifestLayers({});\n setTagManifestStatuses({});\n }, [instanceName, organization, repository]);\n\n const fetchSecurityDetails = async (tag: QuayTag) => {\n const securityDetails = await quayClient.getSecurityDetails(\n instanceName,\n organization,\n repository,\n tag.manifest_digest,\n );\n return securityDetails;\n };\n\n const { loading } = useAsync(async () => {\n const requestId = requestIdRef.current;\n const tagsResponse = await quayClient.getTags(\n instanceName,\n organization,\n repository,\n undefined,\n undefined,\n );\n if (requestId !== requestIdRef.current) {\n return tagsResponse;\n }\n setTags(tagsResponse.tags);\n\n void Promise.all(\n tagsResponse.tags.map(async tag => {\n const securityDetails = await fetchSecurityDetails(tag);\n if (requestId !== requestIdRef.current) {\n return;\n }\n const securityData = securityDetails.data;\n const securityStatus = securityDetails.status;\n\n setTagManifestStatuses(prevState => ({\n ...prevState,\n [tag.manifest_digest]: securityStatus,\n }));\n\n if (securityData) {\n setTagManifestLayers(prevState => ({\n ...prevState,\n [tag.manifest_digest]: securityData.Layer,\n }));\n }\n }),\n );\n return tagsResponse;\n }, [instanceName, organization, repository]);\n\n const data: QuayTagData[] = useMemo(() => {\n return Object.values(tags)?.map(tag => {\n const hashFunc = tag.manifest_digest.substring(0, 6);\n const shortHash = tag.manifest_digest.substring(7, 19);\n return {\n id: `${tag.manifest_digest}-${tag.name}`,\n name: tag.name,\n last_modified: formatDate(tag.last_modified),\n size: formatByteSize(tag.size),\n rawSize: tag.size,\n manifest_digest: (\n <Flex align=\"center\" gap=\"1\">\n <TagGroup>\n <Tag size=\"small\">{hashFunc}</Tag>\n </TagGroup>\n <Text variant=\"body-x-small\">{shortHash}</Text>\n </Flex>\n ),\n expiration: tag.expiration\n ? formatDate(tag.expiration)\n : tag.expiration,\n securityDetails: tagManifestLayers[tag.manifest_digest],\n securityStatus: tagManifestStatuses[tag.manifest_digest],\n manifest_digest_raw: tag.manifest_digest,\n };\n });\n }, [tags, tagManifestLayers, tagManifestStatuses]);\n\n return { loading, data };\n};\n\nexport const QUAY_ANNOTATION_REPOSITORY = 'quay.io/repository-slug';\nexport const QUAY_ANNOTATION_INSTANCE = 'quay.io/instance-name';\n\nexport const useQuayAppData = ({ entity }: { entity: Entity }) => {\n const instanceSlug = entity?.metadata.annotations?.[QUAY_ANNOTATION_INSTANCE];\n const repositorySlug =\n entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY] ?? '';\n\n if (!repositorySlug) {\n throw new Error(\"'Quay' annotations are missing\");\n }\n return { instanceSlug, repositorySlug };\n};\n\nexport const useRepository = () => {\n const { entity } = useEntity();\n const { instanceSlug: instanceName, repositorySlug } = useQuayAppData({\n entity,\n });\n const info = repositorySlug.split('/');\n\n const organization = info.shift() as 'string';\n const repository = info.join('/');\n return {\n instanceName,\n organization,\n repository,\n };\n};\n\nexport const useTagDetails = (\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n) => {\n const quayClient = useApi(quayApiRef);\n const result = useAsync(async () => {\n const manifestLayer = await quayClient.getSecurityDetails(\n instanceName,\n org,\n repo,\n digest,\n );\n return manifestLayer;\n });\n return result;\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ function styleInject(css, ref) {
2
+ if ( ref === void 0 ) ref = {};
3
+ var insertAt = ref.insertAt;
4
+
5
+ if (!css || typeof document === 'undefined') { return; }
6
+
7
+ var head = document.head || document.getElementsByTagName('head')[0];
8
+ var style = document.createElement('style');
9
+ style.type = 'text/css';
10
+
11
+ if (insertAt === 'top') {
12
+ if (head.firstChild) {
13
+ head.insertBefore(style, head.firstChild);
14
+ } else {
15
+ head.appendChild(style);
16
+ }
17
+ } else {
18
+ head.appendChild(style);
19
+ }
20
+
21
+ if (style.styleSheet) {
22
+ style.styleSheet.cssText = css;
23
+ } else {
24
+ style.appendChild(document.createTextNode(css));
25
+ }
26
+ }
27
+
28
+ export { styleInject as default };
29
+ //# sourceMappingURL=style-inject.es.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-inject.es.esm.js","sources":["../../../../../../node_modules/style-inject/dist/style-inject.es.js"],"sourcesContent":["function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n"],"names":[],"mappings":"AAAA,SAAS,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE;AAC/B,EAAE,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,GAAG,EAAE;AAChC,EAAE,IAAI,QAAQ,GAAG,GAAG,CAAC,QAAQ;;AAE7B,EAAE,IAAI,CAAC,GAAG,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,EAAE,OAAO,CAAC;;AAEzD,EAAE,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtE,EAAE,IAAI,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AAC7C,EAAE,KAAK,CAAC,IAAI,GAAG,UAAU;;AAEzB,EAAE,IAAI,QAAQ,KAAK,KAAK,EAAE;AAC1B,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE;AACzB,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC;AAC/C,IAAI,CAAC,MAAM;AACX,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AAC7B,IAAI;AACJ,EAAE,CAAC,MAAM;AACT,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3B,EAAE;;AAEF,EAAE,IAAI,KAAK,CAAC,UAAU,EAAE;AACxB,IAAI,KAAK,CAAC,UAAU,CAAC,OAAO,GAAG,GAAG;AAClC,EAAE,CAAC,MAAM;AACT,IAAI,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;AACnD,EAAE;AACF;;;;","x_google_ignoreList":[0]}
@@ -1,6 +1,12 @@
1
1
  import { createPlugin, createApiFactory, identityApiRef, configApiRef, discoveryApiRef, createRoutableExtension } from '@backstage/core-plugin-api';
2
2
  import { quayApiRef, QuayApiClient } from './api/index.esm.js';
3
- import './hooks/quay.esm.js';
3
+ import 'react/jsx-runtime';
4
+ import 'react';
5
+ import 'react-use';
6
+ import '@backstage/plugin-catalog-react';
7
+ import '@backstage/ui';
8
+ import 'filesize';
9
+ import 'luxon';
4
10
  import { tagRouteRef, rootRouteRef } from './routes.esm.js';
5
11
 
6
12
  const quayPlugin = createPlugin({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity } from '@backstage/catalog-model';\nimport {\n configApiRef,\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { QuayApiClient, quayApiRef } from './api';\nimport { QUAY_ANNOTATION_REPOSITORY } from './hooks';\nimport { rootRouteRef, tagRouteRef } from './routes';\n\n/**\n * Quay plugin\n *\n * @public\n */\nexport const quayPlugin = createPlugin({\n id: 'quay',\n routes: {\n root: rootRouteRef,\n tag: tagRouteRef,\n },\n apis: [\n createApiFactory({\n api: quayApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n configApi: configApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, configApi, identityApi }) =>\n QuayApiClient.fromConfig({ discoveryApi, configApi, identityApi }),\n }),\n ],\n});\n\n/**\n * Quay page\n *\n * @public\n */\nexport const QuayPage = quayPlugin.provide(\n createRoutableExtension({\n name: 'QuayPage',\n component: () => import('./components/Router').then(m => m.Router),\n mountPoint: rootRouteRef,\n }),\n);\n\n/**\n * Returns true if the catalog entity contains the quay annotation `quay.io/repository-slug`.\n *\n * @public\n */\nexport const isQuayAvailable = (entity: Entity) =>\n Boolean(entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY]);\n"],"names":[],"mappings":";;;;;AAkCO,MAAM,aAAa,YAAA,CAAa;AAAA,EACrC,EAAA,EAAI,MAAA;AAAA,EACJ,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,YAAA;AAAA,IACN,GAAA,EAAK;AAAA,GACP;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,gBAAA,CAAiB;AAAA,MACf,GAAA,EAAK,UAAA;AAAA,MACL,IAAA,EAAM;AAAA,QACJ,YAAA,EAAc,eAAA;AAAA,QACd,SAAA,EAAW,YAAA;AAAA,QACX,WAAA,EAAa;AAAA,OACf;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,SAAA,EAAW,WAAA,EAAY,KAC/C,aAAA,CAAc,UAAA,CAAW,EAAE,YAAA,EAAc,SAAA,EAAW,aAAa;AAAA,KACpE;AAAA;AAEL,CAAC;AAOM,MAAM,WAAW,UAAA,CAAW,OAAA;AAAA,EACjC,uBAAA,CAAwB;AAAA,IACtB,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,EAAW,MAAM,OAAO,4BAAqB,EAAE,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,MAAM,CAAA;AAAA,IACjE,UAAA,EAAY;AAAA,GACb;AACH;;;;"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity } from '@backstage/catalog-model';\nimport {\n configApiRef,\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { QuayApiClient, quayApiRef } from './api';\nimport { QUAY_ANNOTATION_REPOSITORY } from './hooks';\nimport { rootRouteRef, tagRouteRef } from './routes';\n\n/**\n * Quay plugin\n *\n * @public\n */\nexport const quayPlugin = createPlugin({\n id: 'quay',\n routes: {\n root: rootRouteRef,\n tag: tagRouteRef,\n },\n apis: [\n createApiFactory({\n api: quayApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n configApi: configApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, configApi, identityApi }) =>\n QuayApiClient.fromConfig({ discoveryApi, configApi, identityApi }),\n }),\n ],\n});\n\n/**\n * Quay page\n *\n * @public\n */\nexport const QuayPage = quayPlugin.provide(\n createRoutableExtension({\n name: 'QuayPage',\n component: () => import('./components/Router').then(m => m.Router),\n mountPoint: rootRouteRef,\n }),\n);\n\n/**\n * Returns true if the catalog entity contains the quay annotation `quay.io/repository-slug`.\n *\n * @public\n */\nexport const isQuayAvailable = (entity: Entity) =>\n Boolean(entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY]);\n"],"names":[],"mappings":";;;;;;;;;;;AAkCO,MAAM,aAAa,YAAA,CAAa;AAAA,EACrC,EAAA,EAAI,MAAA;AAAA,EACJ,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,YAAA;AAAA,IACN,GAAA,EAAK;AAAA,GACP;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,gBAAA,CAAiB;AAAA,MACf,GAAA,EAAK,UAAA;AAAA,MACL,IAAA,EAAM;AAAA,QACJ,YAAA,EAAc,eAAA;AAAA,QACd,SAAA,EAAW,YAAA;AAAA,QACX,WAAA,EAAa;AAAA,OACf;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,SAAA,EAAW,WAAA,EAAY,KAC/C,aAAA,CAAc,UAAA,CAAW,EAAE,YAAA,EAAc,SAAA,EAAW,aAAa;AAAA,KACpE;AAAA;AAEL,CAAC;AAOM,MAAM,WAAW,UAAA,CAAW,OAAA;AAAA,EACjC,uBAAA,CAAwB;AAAA,IACtB,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,EAAW,MAAM,OAAO,4BAAqB,EAAE,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,MAAM,CAAA;AAAA,IACjE,UAAA,EAAY;AAAA,GACb;AACH;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage-community/plugin-quay",
3
- "version": "1.34.0",
3
+ "version": "1.36.0",
4
4
  "main": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -36,16 +36,15 @@
36
36
  "ui-test": "start-server-and-test start localhost:3000 'playwright test'"
37
37
  },
38
38
  "dependencies": {
39
- "@backstage-community/plugin-quay-common": "^1.21.0",
39
+ "@backstage-community/plugin-quay-common": "^1.22.0",
40
40
  "@backstage/catalog-model": "^1.9.0",
41
- "@backstage/core-components": "^0.18.10",
42
- "@backstage/core-plugin-api": "^1.12.6",
43
- "@backstage/plugin-catalog-react": "^3.0.0",
44
- "@backstage/plugin-permission-react": "^0.5.1",
41
+ "@backstage/core-components": "^0.18.11",
42
+ "@backstage/core-plugin-api": "^1.12.7",
43
+ "@backstage/plugin-catalog-react": "^3.1.0",
44
+ "@backstage/plugin-permission-react": "^0.5.2",
45
45
  "@backstage/theme": "^0.7.3",
46
- "@material-ui/core": "^4.12.2",
47
- "@material-ui/icons": "^4.11.3",
48
- "@material-ui/lab": "4.0.0-alpha.61",
46
+ "@backstage/ui": "^0.16.0",
47
+ "@remixicon/react": ">=4.6.0 <4.9.0",
49
48
  "filesize": "^11.0.0",
50
49
  "luxon": "^3.6.1",
51
50
  "react-use": "^17.4.0"
@@ -57,10 +56,9 @@
57
56
  },
58
57
  "devDependencies": {
59
58
  "@axe-core/playwright": "^4.11.0",
60
- "@backstage/cli": "^0.36.2",
61
- "@backstage/dev-utils": "^1.1.23",
62
- "@backstage/test-utils": "^1.7.18",
63
- "@backstage/ui": "^0.15.0",
59
+ "@backstage/cli": "^0.36.3",
60
+ "@backstage/dev-utils": "^1.1.24",
61
+ "@backstage/test-utils": "^1.7.19",
64
62
  "@playwright/test": "1.60.0",
65
63
  "@testing-library/dom": "^10.4.1",
66
64
  "@testing-library/jest-dom": "^6.0.0",