@backstage-community/plugin-quay 1.32.1 → 1.33.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 +11 -0
- package/dist/api/index.esm.js +1 -1
- package/dist/api/index.esm.js.map +1 -1
- package/dist/components/PermissionAlert/PermissionAlert.esm.js.map +1 -1
- package/dist/components/QuayRepository/QuayRepository.esm.js.map +1 -1
- package/dist/components/QuayRepository/tableHeading.esm.js.map +1 -1
- package/dist/components/QuayTagDetails/component.esm.js +2 -2
- package/dist/components/QuayTagDetails/component.esm.js.map +1 -1
- package/dist/components/QuayTagPage/component.esm.js +1 -1
- package/dist/components/QuayTagPage/component.esm.js.map +1 -1
- package/dist/components/Router.esm.js.map +1 -1
- package/dist/doc-links.esm.js.map +1 -1
- package/dist/hooks/quay.esm.js +2 -2
- package/dist/hooks/quay.esm.js.map +1 -1
- package/dist/hooks/useQuayViewPermission.esm.js.map +1 -1
- package/dist/lib/utils.esm.js +1 -1
- package/dist/lib/utils.esm.js.map +1 -1
- package/dist/plugin.esm.js +1 -1
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js.map +1 -1
- package/dist/types.esm.js.map +1 -1
- package/dist/utils.esm.js.map +1 -1
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @backstage-community/plugin-quay
|
|
2
2
|
|
|
3
|
+
## 1.33.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 07b8314: Backstage version bump to v1.50.4
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [07b8314]
|
|
12
|
+
- @backstage-community/plugin-quay-common@1.20.0
|
|
13
|
+
|
|
3
14
|
## 1.32.1
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/dist/api/index.esm.js
CHANGED
|
@@ -66,7 +66,7 @@ class QuayApiClient {
|
|
|
66
66
|
}
|
|
67
67
|
async getBaseUrl(instanceName) {
|
|
68
68
|
const instance = this.getQuayInstance(instanceName);
|
|
69
|
-
if (instance ===
|
|
69
|
+
if (instance === void 0) {
|
|
70
70
|
throw new Error(
|
|
71
71
|
`Quay instance "${instanceName}" not found in configuration.`
|
|
72
72
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../../src/api/index.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 {\n ConfigApi,\n createApiRef,\n DiscoveryApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\n\nimport { QUAY_SINGLE_INSTANCE_NAME } from '@backstage-community/plugin-quay-common';\n\nimport {\n LabelsResponse,\n ManifestByDigestResponse,\n SecurityDetailsResponse,\n TagsResponse,\n} from '../types';\n\nconst DEFAULT_PROXY_PATH = '/quay/api';\n\nexport interface QuayApiV1 {\n getQuayInstance(instanceName?: string): QuayInstanceConfig | undefined;\n getTags(\n instanceName: string | undefined,\n org: string,\n repo: string,\n page?: number,\n limit?: number,\n ): Promise<TagsResponse>;\n getLabels(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ): Promise<LabelsResponse>;\n getManifestByDigest(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ): Promise<ManifestByDigestResponse>;\n getSecurityDetails(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ): Promise<SecurityDetailsResponse>;\n}\n\nexport const quayApiRef = createApiRef<QuayApiV1>({\n id: 'plugin.quay.service',\n});\n\nexport type Options = {\n discoveryApi: DiscoveryApi;\n configApi: ConfigApi;\n identityApi: IdentityApi;\n};\n\nexport type QuayInstanceConfig = {\n name: string;\n apiUrl?: string;\n uiUrl?: string;\n proxyPath?: string;\n};\n\nexport class QuayApiClient implements QuayApiV1 {\n // @ts-ignore\n private readonly discoveryApi: DiscoveryApi;\n\n private readonly identityApi: IdentityApi;\n\n private readonly instances: Map<string, QuayInstanceConfig>;\n\n private readonly defaultInstanceName: string;\n\n static fromConfig(options: Options): QuayApiClient {\n const { configApi } = options;\n\n const instancesArray = configApi.getOptionalConfigArray('quay.instances');\n const singleApiUrl = configApi.getOptionalString('quay.apiUrl');\n const singleProxyPath = configApi.getOptionalString('quay.proxyPath');\n const singleUiUrl = configApi.getOptionalString('quay.uiUrl');\n\n // Validate that single-instance and multi-instance configs are not mixed\n if (instancesArray && (singleApiUrl || singleProxyPath || singleUiUrl)) {\n throw new Error(\n 'Invalid Quay configuration: Cannot use both \"quay.instances\" (multi-instance) and \"quay.apiUrl\", \"quay.proxyPath\", \"quay.uiUrl\" (single-instance) at the same time.',\n );\n }\n\n const instances: QuayInstanceConfig[] = [];\n if (instancesArray && instancesArray.length > 0) {\n // Multi-instance configuration\n for (const instance of instancesArray) {\n instances.push({\n name: instance.getString('name'),\n uiUrl: instance.getOptionalString('uiUrl'),\n apiUrl: instance.getOptionalString('apiUrl'),\n proxyPath: instance.getOptionalString('proxyPath'),\n });\n }\n } else if (singleApiUrl) {\n // Single-instance configuration\n instances.push({\n name: QUAY_SINGLE_INSTANCE_NAME,\n apiUrl: singleApiUrl,\n });\n } else {\n // Single-instance proxy configuration\n instances.push({\n name: QUAY_SINGLE_INSTANCE_NAME,\n uiUrl: singleUiUrl,\n proxyPath: singleProxyPath,\n });\n }\n\n return new QuayApiClient(\n options.discoveryApi,\n options.identityApi,\n instances,\n );\n }\n\n private constructor(\n discoveryApi: DiscoveryApi,\n identityApi: IdentityApi,\n instances: QuayInstanceConfig[],\n ) {\n if (instances.length === 0) {\n throw new Error('At least one Quay instance must be configured');\n }\n\n this.discoveryApi = discoveryApi;\n this.identityApi = identityApi;\n this.instances = new Map(\n instances.map(instance => [instance.name, instance]),\n );\n this.defaultInstanceName = instances[0].name;\n }\n\n getQuayInstance(instanceName?: string): QuayInstanceConfig | undefined {\n return instanceName\n ? this.instances.get(instanceName)\n : this.instances.get(this.defaultInstanceName);\n }\n\n private async getBaseUrl(instanceName?: string) {\n const instance = this.getQuayInstance(instanceName);\n if (instance === undefined) {\n throw new Error(\n `Quay instance \"${instanceName}\" not found in configuration.`,\n );\n }\n\n const baseUrl = await this.discoveryApi.getBaseUrl(\n instance.apiUrl ? 'quay' : 'proxy',\n );\n return instance.apiUrl\n ? `${baseUrl}/${instance.name}`\n : `${baseUrl}${instance.proxyPath ?? DEFAULT_PROXY_PATH}/api/v1`;\n }\n\n private async fetcher(url: string) {\n const { token: idToken } = await this.identityApi.getCredentials();\n const response = await fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n ...(idToken && { Authorization: `Bearer ${idToken}` }),\n },\n });\n if (!response.ok) {\n throw new Error(\n `failed to fetch data, status ${response.status}: ${response.statusText}`,\n );\n }\n return await response.json();\n }\n\n private encodeGetParams(params: Record<string, any>) {\n return Object.keys(params)\n .filter(key => typeof params[key] !== 'undefined')\n .map(\n k =>\n `${encodeURIComponent(k)}=${encodeURIComponent(params[k] as string)}`,\n )\n .join('&');\n }\n\n async getTags(\n instanceName: string | undefined,\n org: string,\n repo: string,\n page?: number,\n limit?: number,\n specificTag?: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n const params = this.encodeGetParams({\n limit,\n page,\n onlyActiveTags: true,\n specificTag,\n });\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/tag/?${params}`,\n )) as TagsResponse;\n }\n\n async getLabels(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/manifest/${digest}/labels`,\n )) as LabelsResponse;\n }\n\n async getManifestByDigest(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/manifest/${digest}`,\n )) as ManifestByDigestResponse;\n }\n\n async getSecurityDetails(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/manifest/${digest}/security`,\n )) as SecurityDetailsResponse;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../src/api/index.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 {\n ConfigApi,\n createApiRef,\n DiscoveryApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\n\nimport { QUAY_SINGLE_INSTANCE_NAME } from '@backstage-community/plugin-quay-common';\n\nimport {\n LabelsResponse,\n ManifestByDigestResponse,\n SecurityDetailsResponse,\n TagsResponse,\n} from '../types';\n\nconst DEFAULT_PROXY_PATH = '/quay/api';\n\nexport interface QuayApiV1 {\n getQuayInstance(instanceName?: string): QuayInstanceConfig | undefined;\n getTags(\n instanceName: string | undefined,\n org: string,\n repo: string,\n page?: number,\n limit?: number,\n ): Promise<TagsResponse>;\n getLabels(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ): Promise<LabelsResponse>;\n getManifestByDigest(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ): Promise<ManifestByDigestResponse>;\n getSecurityDetails(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ): Promise<SecurityDetailsResponse>;\n}\n\nexport const quayApiRef = createApiRef<QuayApiV1>({\n id: 'plugin.quay.service',\n});\n\nexport type Options = {\n discoveryApi: DiscoveryApi;\n configApi: ConfigApi;\n identityApi: IdentityApi;\n};\n\nexport type QuayInstanceConfig = {\n name: string;\n apiUrl?: string;\n uiUrl?: string;\n proxyPath?: string;\n};\n\nexport class QuayApiClient implements QuayApiV1 {\n // @ts-ignore\n private readonly discoveryApi: DiscoveryApi;\n\n private readonly identityApi: IdentityApi;\n\n private readonly instances: Map<string, QuayInstanceConfig>;\n\n private readonly defaultInstanceName: string;\n\n static fromConfig(options: Options): QuayApiClient {\n const { configApi } = options;\n\n const instancesArray = configApi.getOptionalConfigArray('quay.instances');\n const singleApiUrl = configApi.getOptionalString('quay.apiUrl');\n const singleProxyPath = configApi.getOptionalString('quay.proxyPath');\n const singleUiUrl = configApi.getOptionalString('quay.uiUrl');\n\n // Validate that single-instance and multi-instance configs are not mixed\n if (instancesArray && (singleApiUrl || singleProxyPath || singleUiUrl)) {\n throw new Error(\n 'Invalid Quay configuration: Cannot use both \"quay.instances\" (multi-instance) and \"quay.apiUrl\", \"quay.proxyPath\", \"quay.uiUrl\" (single-instance) at the same time.',\n );\n }\n\n const instances: QuayInstanceConfig[] = [];\n if (instancesArray && instancesArray.length > 0) {\n // Multi-instance configuration\n for (const instance of instancesArray) {\n instances.push({\n name: instance.getString('name'),\n uiUrl: instance.getOptionalString('uiUrl'),\n apiUrl: instance.getOptionalString('apiUrl'),\n proxyPath: instance.getOptionalString('proxyPath'),\n });\n }\n } else if (singleApiUrl) {\n // Single-instance configuration\n instances.push({\n name: QUAY_SINGLE_INSTANCE_NAME,\n apiUrl: singleApiUrl,\n });\n } else {\n // Single-instance proxy configuration\n instances.push({\n name: QUAY_SINGLE_INSTANCE_NAME,\n uiUrl: singleUiUrl,\n proxyPath: singleProxyPath,\n });\n }\n\n return new QuayApiClient(\n options.discoveryApi,\n options.identityApi,\n instances,\n );\n }\n\n private constructor(\n discoveryApi: DiscoveryApi,\n identityApi: IdentityApi,\n instances: QuayInstanceConfig[],\n ) {\n if (instances.length === 0) {\n throw new Error('At least one Quay instance must be configured');\n }\n\n this.discoveryApi = discoveryApi;\n this.identityApi = identityApi;\n this.instances = new Map(\n instances.map(instance => [instance.name, instance]),\n );\n this.defaultInstanceName = instances[0].name;\n }\n\n getQuayInstance(instanceName?: string): QuayInstanceConfig | undefined {\n return instanceName\n ? this.instances.get(instanceName)\n : this.instances.get(this.defaultInstanceName);\n }\n\n private async getBaseUrl(instanceName?: string) {\n const instance = this.getQuayInstance(instanceName);\n if (instance === undefined) {\n throw new Error(\n `Quay instance \"${instanceName}\" not found in configuration.`,\n );\n }\n\n const baseUrl = await this.discoveryApi.getBaseUrl(\n instance.apiUrl ? 'quay' : 'proxy',\n );\n return instance.apiUrl\n ? `${baseUrl}/${instance.name}`\n : `${baseUrl}${instance.proxyPath ?? DEFAULT_PROXY_PATH}/api/v1`;\n }\n\n private async fetcher(url: string) {\n const { token: idToken } = await this.identityApi.getCredentials();\n const response = await fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n ...(idToken && { Authorization: `Bearer ${idToken}` }),\n },\n });\n if (!response.ok) {\n throw new Error(\n `failed to fetch data, status ${response.status}: ${response.statusText}`,\n );\n }\n return await response.json();\n }\n\n private encodeGetParams(params: Record<string, any>) {\n return Object.keys(params)\n .filter(key => typeof params[key] !== 'undefined')\n .map(\n k =>\n `${encodeURIComponent(k)}=${encodeURIComponent(params[k] as string)}`,\n )\n .join('&');\n }\n\n async getTags(\n instanceName: string | undefined,\n org: string,\n repo: string,\n page?: number,\n limit?: number,\n specificTag?: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n const params = this.encodeGetParams({\n limit,\n page,\n onlyActiveTags: true,\n specificTag,\n });\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/tag/?${params}`,\n )) as TagsResponse;\n }\n\n async getLabels(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/manifest/${digest}/labels`,\n )) as LabelsResponse;\n }\n\n async getManifestByDigest(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/manifest/${digest}`,\n )) as ManifestByDigestResponse;\n }\n\n async getSecurityDetails(\n instanceName: string | undefined,\n org: string,\n repo: string,\n digest: string,\n ) {\n const baseUrl = await this.getBaseUrl(instanceName);\n\n return (await this.fetcher(\n `${baseUrl}/repository/${org}/${repo}/manifest/${digest}/security`,\n )) as SecurityDetailsResponse;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -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,
|
|
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 +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":";;;;;;;;;;;AA6BO,SAAS,eAAe,
|
|
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":";;;;;;;;;;;AA6BO,SAAS,eAAe,MAAA,EAA6B;AAC1D,EAAA,MAAM,EAAE,YAAA,EAAc,UAAA,EAAY,YAAA,KAAiB,aAAA,EAAc;AACjE,EAAA,MAAM,OAAA,GAAU,OAAO,UAAU,CAAA;AAEjC,EAAA,MAAM,cAAA,GAAiB,OAAA,CAAQ,eAAA,CAAgB,YAAY,CAAA;AAC3D,EAAA,MAAM,SAAA,GAAY,cAAA,EAAgB,MAAA,IAAU,cAAA,EAAgB,KAAA;AAE5D,EAAA,MAAM,oBAAoB,qBAAA,EAAsB;AAEhD,EAAA,MAAM,KAAA,GAAQ,4BACZ,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,CAAA,iBAAA,CAAA;AAAA,oBACD,GAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,IAAI,CAAA,EAAG,SAAS,CAAA,YAAA,EAAe,YAAY,IAAI,UAAU,CAAA,CAAA;AAAA,QACzD,QAAA,EAAA,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,UAAU,CAAA;AAAA;AAAA;AAAG,GAAA,EACpC,CAAA,GAEA,CAAA,iBAAA,EAAoB,YAAY,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAEhD,EAAA,MAAM,EAAE,OAAA,EAAS,IAAA,KAAS,OAAA,CAAQ,YAAA,EAAc,cAAc,UAAU,CAAA;AAExE,EAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,IAAA,2BAAQ,eAAA,EAAA,EAAgB,CAAA;AAAA,EAC1B;AAEA,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,2BACG,KAAA,EAAA,EAAI,aAAA,EAAY,oBAAA,EACf,QAAA,kBAAA,GAAA,CAAC,YAAS,CAAA,EACZ,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,aAAA,EAAY,iBAAA,EACf,QAAA,kBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA;AAAA,MACA,SAAS,EAAE,OAAA,EAAS,MAAM,MAAA,EAAQ,IAAA,EAAM,SAAS,OAAA,EAAQ;AAAA,MACzD,IAAA;AAAA,MACA,OAAA;AAAA,MACA,8BACE,IAAA,CAAC,GAAA,EAAA,EAAI,aAAA,EAAY,uBAAA,EAAwB,SAAS,CAAA,EAChD,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,WAAU,IAAA,EAAK,KAAA,EAAM,UAAS,OAAA,EAAQ,IAAA,EAAK,YAAA,EAAY,IAAA,EAAC,QAAA,EAAA,2BAAA,EAEpE,CAAA;AAAA,wBACA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,GAAA;AAAA,YACV,KAAA,EAAM,QAAA;AAAA,YACN,OAAA,EAAQ,OAAA;AAAA,YACR,KAAA,EAAM,eAAA;AAAA,YACN,YAAA,EAAY,IAAA;AAAA,YACb,QAAA,EAAA;AAAA;AAAA,SAGD;AAAA,wBACA,IAAA,CAAC,GAAA,EAAA,EAAI,EAAA,EAAI,CAAA,EACP,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,GAAA;AAAA,cACV,KAAA,EAAM,QAAA;AAAA,cACN,OAAA,EAAQ,OAAA;AAAA,cACR,YAAA,EAAY,IAAA;AAAA,cAEZ,QAAA,kBAAA,GAAA,CAAC,YAAO,QAAA,EAAA,qBAAA,EAAmB;AAAA;AAAA,WAC7B;AAAA,0BACA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,GAAA;AAAA,cACV,KAAA,EAAM,QAAA;AAAA,cACN,OAAA,EAAQ,OAAA;AAAA,cACR,YAAA,EAAY,IAAA;AAAA,cACb,QAAA,EAAA;AAAA;AAAA,WAED;AAAA,0BACA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,GAAA;AAAA,cACV,KAAA,EAAM,QAAA;AAAA,cACN,OAAA,EAAQ,OAAA;AAAA,cACR,YAAA,EAAY,IAAA;AAAA,cACb,QAAA,EAAA;AAAA;AAAA,WAED;AAAA,0BACA,IAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,GAAA;AAAA,cACV,KAAA,EAAM,QAAA;AAAA,cACN,OAAA,EAAQ,OAAA;AAAA,cACR,YAAA,EAAY,IAAA;AAAA,cACb,QAAA,EAAA;AAAA,gBAAA,uCAAA;AAAA,gBACuC,GAAA;AAAA,gCACtC,GAAA,CAAC,IAAA,EAAA,EAAK,EAAA,EAAI,SAAA,CAAU,2BAA2B,QAAA,EAAA,sBAAA,EAE/C;AAAA;AAAA;AAAA,WACF;AAAA,+BACC,UAAA,EAAA,EAAW,SAAA,EAAU,KAAI,KAAA,EAAM,QAAA,EAAS,SAAQ,OAAA,EAAQ,QAAA,EAAA;AAAA,YAAA,gBAAA;AAAA,YACxC,GAAA;AAAA,4BACf,GAAA,CAAC,IAAA,EAAA,EAAK,EAAA,EAAI,SAAA,CAAU,kBAAkB,QAAA,EAAA,oBAAA,EAAkB,CAAA;AAAA,YAAQ,GAAA;AAAA,YAAI,KAAA;AAAA,YAChE,GAAA;AAAA,4BACJ,GAAA,CAAC,IAAA,EAAA,EAAK,EAAA,EAAI,SAAA,CAAU,6BAA6B,QAAA,EAAA,sBAAA,EAEjD;AAAA,WAAA,EACF;AAAA,SAAA,EACF;AAAA,OAAA,EACF;AAAA;AAAA,GAEJ,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -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,
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { Link, Table } from '@backstage/core-components';
|
|
3
|
-
import {
|
|
3
|
+
import { TableContainer, TableHead, makeStyles } from '@material-ui/core';
|
|
4
4
|
import KeyboardBackspaceIcon from '@material-ui/icons/KeyboardBackspace';
|
|
5
5
|
import LinkIcon from '@material-ui/icons/Link';
|
|
6
6
|
import WarningIcon from '@material-ui/icons/Warning';
|
|
@@ -115,5 +115,5 @@ const QuayTagDetails = ({
|
|
|
115
115
|
] });
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
export { QuayTagDetails
|
|
118
|
+
export { QuayTagDetails };
|
|
119
119
|
//# sourceMappingURL=component.esm.js.map
|
|
@@ -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":";;;;;;;;;AAwCA,MAAM,uBAAuB,CAAC,IAAA,KAAiB,KAAK,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.esm.js","sources":["../../../src/components/QuayTagPage/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 { useParams } from 'react-router-dom';\n\nimport { ErrorPanel, Progress } from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\n\nimport { useRepository, useTagDetails } from '../../hooks';\nimport { useQuayViewPermission } from '../../hooks/useQuayViewPermission';\nimport { rootRouteRef } from '../../routes';\nimport PermissionAlert from '../PermissionAlert/PermissionAlert';\nimport { QuayTagDetails } from '../QuayTagDetails';\n\nexport const QuayTagPage = () => {\n const rootLink = useRouteRef(rootRouteRef);\n const { instanceName, repository, organization } = useRepository();\n const { digest } = useParams();\n const hasViewPermission = useQuayViewPermission();\n if (!digest) {\n throw new Error('digest is not defined');\n }\n const { loading, value } = useTagDetails(\n instanceName,\n organization,\n repository,\n digest,\n );\n\n if (!hasViewPermission) {\n return <PermissionAlert />;\n }\n\n if (loading) {\n return (\n <div data-testid=\"quay-tag-page-progress\">\n <Progress variant=\"query\" />\n </div>\n );\n }\n if (!value?.data) {\n return <ErrorPanel error={new Error('no digest')} />;\n }\n\n return (\n <QuayTagDetails\n rootLink={rootLink}\n layer={value.data.Layer}\n digest={digest}\n />\n );\n};\n\nexport default QuayTagPage;\n"],"names":[],"mappings":";;;;;;;;;;AA0BO,MAAM,cAAc,MAAM;AAC/B,
|
|
1
|
+
{"version":3,"file":"component.esm.js","sources":["../../../src/components/QuayTagPage/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 { useParams } from 'react-router-dom';\n\nimport { ErrorPanel, Progress } from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\n\nimport { useRepository, useTagDetails } from '../../hooks';\nimport { useQuayViewPermission } from '../../hooks/useQuayViewPermission';\nimport { rootRouteRef } from '../../routes';\nimport PermissionAlert from '../PermissionAlert/PermissionAlert';\nimport { QuayTagDetails } from '../QuayTagDetails';\n\nexport const QuayTagPage = () => {\n const rootLink = useRouteRef(rootRouteRef);\n const { instanceName, repository, organization } = useRepository();\n const { digest } = useParams();\n const hasViewPermission = useQuayViewPermission();\n if (!digest) {\n throw new Error('digest is not defined');\n }\n const { loading, value } = useTagDetails(\n instanceName,\n organization,\n repository,\n digest,\n );\n\n if (!hasViewPermission) {\n return <PermissionAlert />;\n }\n\n if (loading) {\n return (\n <div data-testid=\"quay-tag-page-progress\">\n <Progress variant=\"query\" />\n </div>\n );\n }\n if (!value?.data) {\n return <ErrorPanel error={new Error('no digest')} />;\n }\n\n return (\n <QuayTagDetails\n rootLink={rootLink}\n layer={value.data.Layer}\n digest={digest}\n />\n );\n};\n\nexport default QuayTagPage;\n"],"names":[],"mappings":";;;;;;;;;;AA0BO,MAAM,cAAc,MAAM;AAC/B,EAAA,MAAM,QAAA,GAAW,YAAY,YAAY,CAAA;AACzC,EAAA,MAAM,EAAE,YAAA,EAAc,UAAA,EAAY,YAAA,KAAiB,aAAA,EAAc;AACjE,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,oBAAoB,qBAAA,EAAsB;AAChD,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EACzC;AACA,EAAA,MAAM,EAAE,OAAA,EAAS,KAAA,EAAM,GAAI,aAAA;AAAA,IACzB,YAAA;AAAA,IACA,YAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,IAAA,2BAAQ,eAAA,EAAA,EAAgB,CAAA;AAAA,EAC1B;AAEA,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,uBACE,GAAA,CAAC,SAAI,aAAA,EAAY,wBAAA,EACf,8BAAC,QAAA,EAAA,EAAS,OAAA,EAAQ,SAAQ,CAAA,EAC5B,CAAA;AAAA,EAEJ;AACA,EAAA,IAAI,CAAC,OAAO,IAAA,EAAM;AAChB,IAAA,2BAAQ,UAAA,EAAA,EAAW,KAAA,EAAO,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG,CAAA;AAAA,EACpD;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,QAAA;AAAA,MACA,KAAA,EAAO,MAAM,IAAA,CAAK,KAAA;AAAA,MAClB;AAAA;AAAA,GACF;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.esm.js","sources":["../../src/components/Router.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 { Route, Routes } from 'react-router-dom';\n\nimport { Entity } from '@backstage/catalog-model';\n\nimport { QUAY_ANNOTATION_REPOSITORY } from '../hooks';\nimport { tagRouteRef } from '../routes';\nimport { QuayRepository } from './QuayRepository';\nimport { QuayTagPage } from './QuayTagPage';\n\n/** *\n * @public\n */\nexport const isQuayAvailable = (entity: Entity) =>\n Boolean(entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY]);\n/**\n *\n * @public\n */\nexport const Router = () => (\n <Routes>\n <Route path=\"/\" element={<QuayRepository />} />\n <Route path={tagRouteRef.path} element={<QuayTagPage />} />\n </Routes>\n);\n"],"names":[],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"Router.esm.js","sources":["../../src/components/Router.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 { Route, Routes } from 'react-router-dom';\n\nimport { Entity } from '@backstage/catalog-model';\n\nimport { QUAY_ANNOTATION_REPOSITORY } from '../hooks';\nimport { tagRouteRef } from '../routes';\nimport { QuayRepository } from './QuayRepository';\nimport { QuayTagPage } from './QuayTagPage';\n\n/** *\n * @public\n */\nexport const isQuayAvailable = (entity: Entity) =>\n Boolean(entity?.metadata.annotations?.[QUAY_ANNOTATION_REPOSITORY]);\n/**\n *\n * @public\n */\nexport const Router = () => (\n <Routes>\n <Route path=\"/\" element={<QuayRepository />} />\n <Route path={tagRouteRef.path} element={<QuayTagPage />} />\n </Routes>\n);\n"],"names":[],"mappings":";;;;;;;AA2BO,MAAM,eAAA,GAAkB,CAAC,MAAA,KAC9B,OAAA,CAAQ,QAAQ,QAAA,CAAS,WAAA,GAAc,0BAA0B,CAAC;AAK7D,MAAM,MAAA,GAAS,sBACpB,IAAA,CAAC,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,kBAAA,GAAA,CAAC,SAAM,IAAA,EAAK,GAAA,EAAI,OAAA,kBAAS,GAAA,CAAC,kBAAe,CAAA,EAAI,CAAA;AAAA,kBAC7C,GAAA,CAAC,SAAM,IAAA,EAAM,WAAA,CAAY,MAAM,OAAA,kBAAS,GAAA,CAAC,eAAY,CAAA,EAAI;AAAA,CAAA,EAC3D;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doc-links.esm.js","sources":["../src/doc-links.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 */\n\nexport const DOC_LINKS = {\n AUTH_TOKEN_GUIDE:\n 'https://docs.redhat.com/en/documentation/red_hat_quay/3/html-single/red_hat_quay_api_guide/index#creating-oauth-access-token',\n BACKEND_CONFIGURATION_GUIDE:\n 'https://github.com/backstage/community-plugins/tree/main/workspaces/quay/plugins/quay-backend#app-config',\n BACKEND_ANNOTATIONS_GUIDE:\n 'https://github.com/backstage/community-plugins/tree/main/workspaces/quay/plugins/quay-backend#catalog',\n} as const;\n"],"names":[],"mappings":"AAgBO,MAAM,
|
|
1
|
+
{"version":3,"file":"doc-links.esm.js","sources":["../src/doc-links.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 */\n\nexport const DOC_LINKS = {\n AUTH_TOKEN_GUIDE:\n 'https://docs.redhat.com/en/documentation/red_hat_quay/3/html-single/red_hat_quay_api_guide/index#creating-oauth-access-token',\n BACKEND_CONFIGURATION_GUIDE:\n 'https://github.com/backstage/community-plugins/tree/main/workspaces/quay/plugins/quay-backend#app-config',\n BACKEND_ANNOTATIONS_GUIDE:\n 'https://github.com/backstage/community-plugins/tree/main/workspaces/quay/plugins/quay-backend#catalog',\n} as const;\n"],"names":[],"mappings":"AAgBO,MAAM,SAAA,GAAY;AAAA,EACvB,gBAAA,EACE,8HAAA;AAAA,EACF,2BAAA,EACE,0GAAA;AAAA,EACF,yBAAA,EACE;AACJ;;;;"}
|
package/dist/hooks/quay.esm.js
CHANGED
|
@@ -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":";;;;;;;;;AA4BA,MAAM,iBAAiB,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQuayViewPermission.esm.js","sources":["../../src/hooks/useQuayViewPermission.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 { usePermission } from '@backstage/plugin-permission-react';\n\nimport { quayViewPermission } from '@backstage-community/plugin-quay-common';\n\nexport const useQuayViewPermission = () => {\n const quayViewPermissionResult = usePermission({\n permission: quayViewPermission,\n });\n\n return quayViewPermissionResult.allowed;\n};\n"],"names":[],"mappings":";;;AAmBO,MAAM,wBAAwB,MAAM;AACzC,EAAA,MAAM,2BAA2B,
|
|
1
|
+
{"version":3,"file":"useQuayViewPermission.esm.js","sources":["../../src/hooks/useQuayViewPermission.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 { usePermission } from '@backstage/plugin-permission-react';\n\nimport { quayViewPermission } from '@backstage-community/plugin-quay-common';\n\nexport const useQuayViewPermission = () => {\n const quayViewPermissionResult = usePermission({\n permission: quayViewPermission,\n });\n\n return quayViewPermissionResult.allowed;\n};\n"],"names":[],"mappings":";;;AAmBO,MAAM,wBAAwB,MAAM;AACzC,EAAA,MAAM,2BAA2B,aAAA,CAAc;AAAA,IAC7C,UAAA,EAAY;AAAA,GACb,CAAA;AAED,EAAA,OAAO,wBAAA,CAAyB,OAAA;AAClC;;;;"}
|
package/dist/lib/utils.esm.js
CHANGED
|
@@ -54,7 +54,7 @@ const securityScanComparator = (ar, br, order = "desc") => {
|
|
|
54
54
|
};
|
|
55
55
|
scan.split(", ").forEach((part) => {
|
|
56
56
|
const [key, value] = part.split(": ");
|
|
57
|
-
if (values[key] !==
|
|
57
|
+
if (values[key] !== void 0) {
|
|
58
58
|
values[key] = parseInt(value, 10);
|
|
59
59
|
}
|
|
60
60
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.esm.js","sources":["../../src/lib/utils.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 {\n Layer,\n QuayTagData,\n VulnerabilityOrder,\n VulnerabilitySeverity,\n} from '../types';\n\nexport const SEVERITY_COLORS = new Proxy(\n new Map([\n [VulnerabilitySeverity.Critical, '#7D1007'],\n [VulnerabilitySeverity.High, '#C9190B'],\n [VulnerabilitySeverity.Medium, '#EC7A08'],\n [VulnerabilitySeverity.Low, '#F0AB00'],\n [VulnerabilitySeverity.None, '#3E8635'],\n ]) as any,\n {\n get: (o: Map<VulnerabilitySeverity, string>, k: VulnerabilitySeverity) =>\n o.has(k) ? o.get(k) : '#8A8D90',\n },\n);\n\nexport const vulnerabilitySummary = (layer: Layer): string => {\n const summary: Record<string, number> = {};\n\n layer?.Features.forEach(feature => {\n feature.Vulnerabilities?.forEach(vulnerability => {\n const { Severity } = vulnerability;\n if (!summary[Severity]) {\n summary[Severity] = 0;\n }\n summary[Severity]++;\n });\n });\n\n const scanResults = Object.entries(summary)\n .sort((a, b) => {\n const severityA = VulnerabilityOrder[a[0] as VulnerabilitySeverity];\n const severityB = VulnerabilityOrder[b[0] as VulnerabilitySeverity];\n\n return severityA - severityB;\n })\n .map(([severity, count]) => `${severity}: ${count}`)\n .join(', ');\n return scanResults.trim() !== '' ? scanResults : 'Passed';\n};\n\nconst securityScanOrder = [\n 'High',\n 'Medium',\n 'Low',\n 'Passed',\n 'Scanning',\n 'Queued',\n 'Unscanned',\n 'Unsupported',\n];\n\nexport const capitalizeFirstLetter = (s: string): string => {\n return s.charAt(0).toLocaleUpperCase('en-US') + s.slice(1);\n};\n\nexport const securityScanComparator = (\n ar: QuayTagData,\n br: QuayTagData,\n order: 'asc' | 'desc' = 'desc',\n) => {\n const a = vulnerabilitySummary(ar.securityDetails);\n const b = vulnerabilitySummary(br.securityDetails);\n\n const parseScan = (scan: string) => {\n const values: { [key: string]: number } = {\n High: 0,\n Medium: 0,\n Low: 0,\n };\n scan.split(', ').forEach((part: string) => {\n const [key, value] = part.split(': ');\n if (values[key] !== undefined) {\n values[key] = parseInt(value, 10);\n }\n });\n return values;\n };\n\n const aParts = a.split(', ');\n const bParts = b.split(', ');\n\n const multiplier = order === 'asc' ? 1 : -1;\n\n if (\n aParts.length >= 1 &&\n bParts.length >= 1 &&\n aParts[0] !== 'Passed' &&\n bParts[0] !== 'Passed'\n ) {\n const aParsed = parseScan(a);\n const bParsed = parseScan(b);\n\n if (aParsed.High !== bParsed.High) {\n return (bParsed.High - aParsed.High) * multiplier;\n }\n if (aParsed.Medium !== bParsed.Medium) {\n return (bParsed.Medium - aParsed.Medium) * multiplier;\n }\n if (aParsed.Low !== bParsed.Low) {\n return (bParsed.Low - aParsed.Low) * multiplier;\n }\n }\n\n const finalAValue = capitalizeFirstLetter(\n ar.securityStatus === 'scanned'\n ? aParts[0].split(':')[0]\n : ar.securityStatus ?? 'scanning',\n );\n\n const finalBValue = capitalizeFirstLetter(\n br.securityStatus === 'scanned'\n ? bParts[0].split(':')[0]\n : br.securityStatus ?? 'scanning',\n );\n\n if (finalAValue === 'Scanning' || finalBValue === 'Scanning') return 1;\n\n return (\n (securityScanOrder.indexOf(finalAValue) -\n securityScanOrder.indexOf(finalBValue)) *\n multiplier\n );\n};\n"],"names":[],"mappings":";;AAsBO,MAAM,kBAAkB,IAAI,KAAA;AAAA,sBAC7B,
|
|
1
|
+
{"version":3,"file":"utils.esm.js","sources":["../../src/lib/utils.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 {\n Layer,\n QuayTagData,\n VulnerabilityOrder,\n VulnerabilitySeverity,\n} from '../types';\n\nexport const SEVERITY_COLORS = new Proxy(\n new Map([\n [VulnerabilitySeverity.Critical, '#7D1007'],\n [VulnerabilitySeverity.High, '#C9190B'],\n [VulnerabilitySeverity.Medium, '#EC7A08'],\n [VulnerabilitySeverity.Low, '#F0AB00'],\n [VulnerabilitySeverity.None, '#3E8635'],\n ]) as any,\n {\n get: (o: Map<VulnerabilitySeverity, string>, k: VulnerabilitySeverity) =>\n o.has(k) ? o.get(k) : '#8A8D90',\n },\n);\n\nexport const vulnerabilitySummary = (layer: Layer): string => {\n const summary: Record<string, number> = {};\n\n layer?.Features.forEach(feature => {\n feature.Vulnerabilities?.forEach(vulnerability => {\n const { Severity } = vulnerability;\n if (!summary[Severity]) {\n summary[Severity] = 0;\n }\n summary[Severity]++;\n });\n });\n\n const scanResults = Object.entries(summary)\n .sort((a, b) => {\n const severityA = VulnerabilityOrder[a[0] as VulnerabilitySeverity];\n const severityB = VulnerabilityOrder[b[0] as VulnerabilitySeverity];\n\n return severityA - severityB;\n })\n .map(([severity, count]) => `${severity}: ${count}`)\n .join(', ');\n return scanResults.trim() !== '' ? scanResults : 'Passed';\n};\n\nconst securityScanOrder = [\n 'High',\n 'Medium',\n 'Low',\n 'Passed',\n 'Scanning',\n 'Queued',\n 'Unscanned',\n 'Unsupported',\n];\n\nexport const capitalizeFirstLetter = (s: string): string => {\n return s.charAt(0).toLocaleUpperCase('en-US') + s.slice(1);\n};\n\nexport const securityScanComparator = (\n ar: QuayTagData,\n br: QuayTagData,\n order: 'asc' | 'desc' = 'desc',\n) => {\n const a = vulnerabilitySummary(ar.securityDetails);\n const b = vulnerabilitySummary(br.securityDetails);\n\n const parseScan = (scan: string) => {\n const values: { [key: string]: number } = {\n High: 0,\n Medium: 0,\n Low: 0,\n };\n scan.split(', ').forEach((part: string) => {\n const [key, value] = part.split(': ');\n if (values[key] !== undefined) {\n values[key] = parseInt(value, 10);\n }\n });\n return values;\n };\n\n const aParts = a.split(', ');\n const bParts = b.split(', ');\n\n const multiplier = order === 'asc' ? 1 : -1;\n\n if (\n aParts.length >= 1 &&\n bParts.length >= 1 &&\n aParts[0] !== 'Passed' &&\n bParts[0] !== 'Passed'\n ) {\n const aParsed = parseScan(a);\n const bParsed = parseScan(b);\n\n if (aParsed.High !== bParsed.High) {\n return (bParsed.High - aParsed.High) * multiplier;\n }\n if (aParsed.Medium !== bParsed.Medium) {\n return (bParsed.Medium - aParsed.Medium) * multiplier;\n }\n if (aParsed.Low !== bParsed.Low) {\n return (bParsed.Low - aParsed.Low) * multiplier;\n }\n }\n\n const finalAValue = capitalizeFirstLetter(\n ar.securityStatus === 'scanned'\n ? aParts[0].split(':')[0]\n : ar.securityStatus ?? 'scanning',\n );\n\n const finalBValue = capitalizeFirstLetter(\n br.securityStatus === 'scanned'\n ? bParts[0].split(':')[0]\n : br.securityStatus ?? 'scanning',\n );\n\n if (finalAValue === 'Scanning' || finalBValue === 'Scanning') return 1;\n\n return (\n (securityScanOrder.indexOf(finalAValue) -\n securityScanOrder.indexOf(finalBValue)) *\n multiplier\n );\n};\n"],"names":[],"mappings":"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"}
|
package/dist/plugin.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createPlugin, createApiFactory, identityApiRef, configApiRef, discoveryApiRef, createRoutableExtension } from '@backstage/core-plugin-api';
|
|
2
|
-
import {
|
|
2
|
+
import { quayApiRef, QuayApiClient } from './api/index.esm.js';
|
|
3
3
|
import './hooks/quay.esm.js';
|
|
4
4
|
import { tagRouteRef, rootRouteRef } from './routes.esm.js';
|
|
5
5
|
|
package/dist/plugin.esm.js.map
CHANGED
|
@@ -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,
|
|
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/dist/routes.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.esm.js","sources":["../src/routes.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 { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'quay',\n});\n\nexport const tagRouteRef = createSubRouteRef({\n id: 'quay-tag',\n parent: rootRouteRef,\n path: '/tag/:digest',\n});\n"],"names":[],"mappings":";;AAiBO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"routes.esm.js","sources":["../src/routes.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 { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'quay',\n});\n\nexport const tagRouteRef = createSubRouteRef({\n id: 'quay-tag',\n parent: rootRouteRef,\n path: '/tag/:digest',\n});\n"],"names":[],"mappings":";;AAiBO,MAAM,eAAe,cAAA,CAAe;AAAA,EACzC,EAAA,EAAI;AACN,CAAC;AAEM,MAAM,cAAc,iBAAA,CAAkB;AAAA,EAC3C,EAAA,EAAI,UAAA;AAAA,EACJ,MAAA,EAAQ,YAAA;AAAA,EACR,IAAA,EAAM;AACR,CAAC;;;;"}
|
package/dist/types.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.esm.js","sources":["../src/types.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 */\nexport interface TagsResponse {\n page: number;\n has_additional: boolean;\n tags: Tag[];\n}\n\nexport interface Tag {\n name: string;\n is_manifest_list: boolean;\n last_modified: string;\n manifest_digest: string;\n reversion: boolean;\n size: number;\n start_ts?: number;\n end_ts?: number;\n manifest_list?: ManifestList;\n expiration?: string;\n}\n\nexport interface LabelsResponse {\n labels: Label[];\n}\nexport interface QuayTagData {\n id: string;\n name: string;\n last_modified: string;\n size: string;\n rawSize: number;\n manifest_digest: React.JSX.Element;\n expiration?: string;\n securityDetails: Layer;\n securityStatus: string;\n manifest_digest_raw: string;\n}\nexport interface Label {\n id: string;\n key: string;\n value: string;\n source_type: string;\n media_type: string;\n}\n\nexport interface ManifestList {\n schemaVersion: number;\n mediaType: string;\n manifests: Manifest[];\n}\n\nexport interface Manifest {\n mediaType: string;\n size: number;\n digest: string;\n platform: Platform;\n security: SecurityDetailsResponse;\n layers: Layer[];\n}\n\nexport interface Platform {\n architecture: string;\n os: string;\n features?: string[];\n variant?: string;\n 'os.version'?: string;\n}\n\nexport interface SecurityDetailsResponse {\n status: 'unsupported' | 'unscanned' | 'scanning' | 'scanned' | 'queued';\n data: Data | null;\n}\nexport interface Data {\n Layer: Layer;\n}\nexport interface Layer {\n Name: string;\n ParentName: string;\n NamespaceName: string;\n IndexedByVersion: number;\n Features: Feature[];\n}\nexport interface Feature {\n Name: string;\n VersionFormat: string;\n NamespaceName: string;\n AddedBy: string;\n Version: string;\n Vulnerabilities?: Vulnerability[];\n BaseScores?: number[];\n CVEIds?: string[];\n}\n\nexport interface Vulnerability {\n Severity: VulnerabilitySeverity;\n NamespaceName: string;\n Link: string;\n FixedBy: string;\n Description: string;\n Name: string;\n Metadata: VulnerabilityMetadata;\n}\n\nexport interface VulnerabilityMetadata {\n UpdatedBy: string;\n RepoName: string | null;\n RepoLink: string | null;\n DistroName: string;\n DistroVersion: string;\n NVD: {\n CVSSv3: {\n Vectors: string;\n Score: number | string;\n };\n };\n}\n\nexport enum VulnerabilitySeverity {\n Critical = 'Critical',\n High = 'High',\n Medium = 'Medium',\n Low = 'Low',\n Negligible = 'Negligible',\n None = 'None',\n Unknown = 'Unknown',\n}\n\nexport const VulnerabilityOrder = {\n [VulnerabilitySeverity.Critical]: 0,\n [VulnerabilitySeverity.High]: 1,\n [VulnerabilitySeverity.Medium]: 2,\n [VulnerabilitySeverity.Low]: 3,\n [VulnerabilitySeverity.Negligible]: 4,\n [VulnerabilitySeverity.None]: 5,\n [VulnerabilitySeverity.Unknown]: 6,\n};\n\nexport interface ManifestByDigestResponse {\n digest: string;\n is_manifest_list: boolean;\n manifest_data: string;\n config_media_type: string;\n layers: LayerByDigest[];\n layers_compressed_size: number;\n}\n\nexport interface LayerByDigest {\n index: number;\n compressed_size: number;\n is_remote: boolean;\n urls: string[] | null;\n command: string[] | null;\n comment: string | null;\n author: string | null;\n blob_digest: string;\n created_datetime: string;\n}\n\nexport interface VulnerabilityListItem extends Vulnerability {\n PackageName: string;\n CurrentVersion: string;\n}\n"],"names":["VulnerabilitySeverity"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.esm.js","sources":["../src/types.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 */\nexport interface TagsResponse {\n page: number;\n has_additional: boolean;\n tags: Tag[];\n}\n\nexport interface Tag {\n name: string;\n is_manifest_list: boolean;\n last_modified: string;\n manifest_digest: string;\n reversion: boolean;\n size: number;\n start_ts?: number;\n end_ts?: number;\n manifest_list?: ManifestList;\n expiration?: string;\n}\n\nexport interface LabelsResponse {\n labels: Label[];\n}\nexport interface QuayTagData {\n id: string;\n name: string;\n last_modified: string;\n size: string;\n rawSize: number;\n manifest_digest: React.JSX.Element;\n expiration?: string;\n securityDetails: Layer;\n securityStatus: string;\n manifest_digest_raw: string;\n}\nexport interface Label {\n id: string;\n key: string;\n value: string;\n source_type: string;\n media_type: string;\n}\n\nexport interface ManifestList {\n schemaVersion: number;\n mediaType: string;\n manifests: Manifest[];\n}\n\nexport interface Manifest {\n mediaType: string;\n size: number;\n digest: string;\n platform: Platform;\n security: SecurityDetailsResponse;\n layers: Layer[];\n}\n\nexport interface Platform {\n architecture: string;\n os: string;\n features?: string[];\n variant?: string;\n 'os.version'?: string;\n}\n\nexport interface SecurityDetailsResponse {\n status: 'unsupported' | 'unscanned' | 'scanning' | 'scanned' | 'queued';\n data: Data | null;\n}\nexport interface Data {\n Layer: Layer;\n}\nexport interface Layer {\n Name: string;\n ParentName: string;\n NamespaceName: string;\n IndexedByVersion: number;\n Features: Feature[];\n}\nexport interface Feature {\n Name: string;\n VersionFormat: string;\n NamespaceName: string;\n AddedBy: string;\n Version: string;\n Vulnerabilities?: Vulnerability[];\n BaseScores?: number[];\n CVEIds?: string[];\n}\n\nexport interface Vulnerability {\n Severity: VulnerabilitySeverity;\n NamespaceName: string;\n Link: string;\n FixedBy: string;\n Description: string;\n Name: string;\n Metadata: VulnerabilityMetadata;\n}\n\nexport interface VulnerabilityMetadata {\n UpdatedBy: string;\n RepoName: string | null;\n RepoLink: string | null;\n DistroName: string;\n DistroVersion: string;\n NVD: {\n CVSSv3: {\n Vectors: string;\n Score: number | string;\n };\n };\n}\n\nexport enum VulnerabilitySeverity {\n Critical = 'Critical',\n High = 'High',\n Medium = 'Medium',\n Low = 'Low',\n Negligible = 'Negligible',\n None = 'None',\n Unknown = 'Unknown',\n}\n\nexport const VulnerabilityOrder = {\n [VulnerabilitySeverity.Critical]: 0,\n [VulnerabilitySeverity.High]: 1,\n [VulnerabilitySeverity.Medium]: 2,\n [VulnerabilitySeverity.Low]: 3,\n [VulnerabilitySeverity.Negligible]: 4,\n [VulnerabilitySeverity.None]: 5,\n [VulnerabilitySeverity.Unknown]: 6,\n};\n\nexport interface ManifestByDigestResponse {\n digest: string;\n is_manifest_list: boolean;\n manifest_data: string;\n config_media_type: string;\n layers: LayerByDigest[];\n layers_compressed_size: number;\n}\n\nexport interface LayerByDigest {\n index: number;\n compressed_size: number;\n is_remote: boolean;\n urls: string[] | null;\n command: string[] | null;\n comment: string | null;\n author: string | null;\n blob_digest: string;\n created_datetime: string;\n}\n\nexport interface VulnerabilityListItem extends Vulnerability {\n PackageName: string;\n CurrentVersion: string;\n}\n"],"names":["VulnerabilitySeverity"],"mappings":"AAiIO,IAAK,qBAAA,qBAAAA,sBAAAA,KAAL;AACL,EAAAA,uBAAA,UAAA,CAAA,GAAW,UAAA;AACX,EAAAA,uBAAA,MAAA,CAAA,GAAO,MAAA;AACP,EAAAA,uBAAA,QAAA,CAAA,GAAS,QAAA;AACT,EAAAA,uBAAA,KAAA,CAAA,GAAM,KAAA;AACN,EAAAA,uBAAA,YAAA,CAAA,GAAa,YAAA;AACb,EAAAA,uBAAA,MAAA,CAAA,GAAO,MAAA;AACP,EAAAA,uBAAA,SAAA,CAAA,GAAU,SAAA;AAPA,EAAA,OAAAA,sBAAAA;AAAA,CAAA,EAAA,qBAAA,IAAA,EAAA;AAUL,MAAM,kBAAA,GAAqB;AAAA,EAChC,CAAC,4BAAiC,CAAA;AAAA,EAClC,CAAC,oBAA6B,CAAA;AAAA,EAC9B,CAAC,wBAA+B,CAAA;AAAA,EAChC,CAAC,kBAA4B,CAAA;AAAA,EAC7B,CAAC,gCAAmC,CAAA;AAAA,EACpC,CAAC,oBAA6B,CAAA;AAAA,EAC9B,CAAC,0BAAgC;AACnC;;;;"}
|
package/dist/utils.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.esm.js","sources":["../src/utils.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 */\n\nimport { filesize } from 'filesize';\nimport { DateTime } from 'luxon';\n\nexport function formatByteSize(sizeInBytes: number | undefined): string {\n if (!sizeInBytes) return 'N/A';\n\n return filesize(sizeInBytes);\n}\n\n/**\n * Formats a date using the Backstage-standard Luxon library.\n *\n * @param date - The date to format, can be a string, number (Unix timestamp), or Date object.\n * @returns A formatted date string (e.g., \"Jun 9, 2025, 6:15 PM\") or 'N/A'.\n */\nexport function formatDate(date: string | number | Date | undefined): string {\n if (!date || date === -1) {\n return 'N/A';\n }\n\n let dt: DateTime;\n\n if (typeof date === 'number') {\n dt = DateTime.fromSeconds(date);\n } else if (date instanceof Date) {\n dt = DateTime.fromJSDate(date);\n } else if (/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),/.test(date)) {\n // Check if it's RFC 2822 format (starts with day name)\n dt = DateTime.fromRFC2822(date);\n } else {\n dt = DateTime.fromISO(date);\n }\n\n if (!dt.isValid) {\n return 'N/A';\n }\n return dt.toLocaleString(DateTime.DATETIME_MED);\n}\n"],"names":[],"mappings":";;;AAmBO,SAAS,eAAe,
|
|
1
|
+
{"version":3,"file":"utils.esm.js","sources":["../src/utils.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 */\n\nimport { filesize } from 'filesize';\nimport { DateTime } from 'luxon';\n\nexport function formatByteSize(sizeInBytes: number | undefined): string {\n if (!sizeInBytes) return 'N/A';\n\n return filesize(sizeInBytes);\n}\n\n/**\n * Formats a date using the Backstage-standard Luxon library.\n *\n * @param date - The date to format, can be a string, number (Unix timestamp), or Date object.\n * @returns A formatted date string (e.g., \"Jun 9, 2025, 6:15 PM\") or 'N/A'.\n */\nexport function formatDate(date: string | number | Date | undefined): string {\n if (!date || date === -1) {\n return 'N/A';\n }\n\n let dt: DateTime;\n\n if (typeof date === 'number') {\n dt = DateTime.fromSeconds(date);\n } else if (date instanceof Date) {\n dt = DateTime.fromJSDate(date);\n } else if (/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),/.test(date)) {\n // Check if it's RFC 2822 format (starts with day name)\n dt = DateTime.fromRFC2822(date);\n } else {\n dt = DateTime.fromISO(date);\n }\n\n if (!dt.isValid) {\n return 'N/A';\n }\n return dt.toLocaleString(DateTime.DATETIME_MED);\n}\n"],"names":[],"mappings":";;;AAmBO,SAAS,eAAe,WAAA,EAAyC;AACtE,EAAA,IAAI,CAAC,aAAa,OAAO,KAAA;AAEzB,EAAA,OAAO,SAAS,WAAW,CAAA;AAC7B;AAQO,SAAS,WAAW,IAAA,EAAkD;AAC3E,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,KAAS,EAAA,EAAI;AACxB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,EAAA;AAEJ,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,EAAA,GAAK,QAAA,CAAS,YAAY,IAAI,CAAA;AAAA,EAChC,CAAA,MAAA,IAAW,gBAAgB,IAAA,EAAM;AAC/B,IAAA,EAAA,GAAK,QAAA,CAAS,WAAW,IAAI,CAAA;AAAA,EAC/B,CAAA,MAAA,IAAW,iCAAA,CAAkC,IAAA,CAAK,IAAI,CAAA,EAAG;AAEvD,IAAA,EAAA,GAAK,QAAA,CAAS,YAAY,IAAI,CAAA;AAAA,EAChC,CAAA,MAAO;AACL,IAAA,EAAA,GAAK,QAAA,CAAS,QAAQ,IAAI,CAAA;AAAA,EAC5B;AAEA,EAAA,IAAI,CAAC,GAAG,OAAA,EAAS;AACf,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,EAAA,CAAG,cAAA,CAAe,QAAA,CAAS,YAAY,CAAA;AAChD;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-quay",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"main": "dist/index.esm.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -36,13 +36,13 @@
|
|
|
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.
|
|
40
|
-
"@backstage/catalog-model": "^1.
|
|
41
|
-
"@backstage/core-components": "^0.18.
|
|
42
|
-
"@backstage/core-plugin-api": "^1.12.
|
|
43
|
-
"@backstage/plugin-catalog-react": "^2.1.
|
|
44
|
-
"@backstage/plugin-permission-react": "^0.
|
|
45
|
-
"@backstage/theme": "^0.7.
|
|
39
|
+
"@backstage-community/plugin-quay-common": "^1.20.0",
|
|
40
|
+
"@backstage/catalog-model": "^1.8.0",
|
|
41
|
+
"@backstage/core-components": "^0.18.9",
|
|
42
|
+
"@backstage/core-plugin-api": "^1.12.5",
|
|
43
|
+
"@backstage/plugin-catalog-react": "^2.1.4",
|
|
44
|
+
"@backstage/plugin-permission-react": "^0.5.0",
|
|
45
|
+
"@backstage/theme": "^0.7.3",
|
|
46
46
|
"@material-ui/core": "^4.12.2",
|
|
47
47
|
"@material-ui/icons": "^4.11.3",
|
|
48
48
|
"@material-ui/lab": "4.0.0-alpha.61",
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@axe-core/playwright": "^4.11.0",
|
|
60
|
-
"@backstage/cli": "^0.36.
|
|
61
|
-
"@backstage/dev-utils": "^1.1.
|
|
62
|
-
"@backstage/test-utils": "^1.7.
|
|
63
|
-
"@backstage/ui": "^0.
|
|
60
|
+
"@backstage/cli": "^0.36.1",
|
|
61
|
+
"@backstage/dev-utils": "^1.1.22",
|
|
62
|
+
"@backstage/test-utils": "^1.7.17",
|
|
63
|
+
"@backstage/ui": "^0.14.3",
|
|
64
64
|
"@playwright/test": "^1.56.1",
|
|
65
65
|
"@testing-library/dom": "^10.4.1",
|
|
66
66
|
"@testing-library/jest-dom": "^6.0.0",
|