@kuadrant/kuadrant-backstage-plugin-frontend 0.0.2-dev-d2ba42b → 0.0.2-dev-9be93a3
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/dist/api.esm.js +220 -0
- package/dist/api.esm.js.map +1 -0
- package/dist/apis.esm.js +15 -0
- package/dist/apis.esm.js.map +1 -0
- package/dist/components/ApiAccessCard/ApiAccessCard.esm.js +25 -36
- package/dist/components/ApiAccessCard/ApiAccessCard.esm.js.map +1 -1
- package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js +24 -36
- package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js.map +1 -1
- package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js +20 -46
- package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js.map +1 -1
- package/dist/components/ApiProductDetailPage/ApiProductDetailPage.esm.js +9 -43
- package/dist/components/ApiProductDetailPage/ApiProductDetailPage.esm.js.map +1 -1
- package/dist/components/ApiProductInfoCard/ApiProductInfoCard.esm.js +5 -13
- package/dist/components/ApiProductInfoCard/ApiProductInfoCard.esm.js.map +1 -1
- package/dist/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.esm.js +7 -10
- package/dist/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.esm.js.map +1 -1
- package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js +32 -64
- package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js.map +1 -1
- package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js +29 -51
- package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js.map +1 -1
- package/dist/components/EditAPIKeyDialog/EditAPIKeyDialog.esm.js +8 -18
- package/dist/components/EditAPIKeyDialog/EditAPIKeyDialog.esm.js.map +1 -1
- package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js +8 -28
- package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js.map +1 -1
- package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js +9 -25
- package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js.map +1 -1
- package/dist/components/KuadrantPage/ApiProductsPage.esm.js +19 -53
- package/dist/components/KuadrantPage/ApiProductsPage.esm.js.map +1 -1
- package/dist/components/MyApiKeysTable/MyApiKeysTable.esm.js +25 -52
- package/dist/components/MyApiKeysTable/MyApiKeysTable.esm.js.map +1 -1
- package/dist/components/RequestAccessDialog/RequestAccessDialog.esm.js +10 -25
- package/dist/components/RequestAccessDialog/RequestAccessDialog.esm.js.map +1 -1
- package/dist/index.d.ts +459 -1
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/dist-scalprum/internal.plugin-kuadrant.8bf02d5482a5a3ed6337.js +2 -0
- package/dist-scalprum/internal.plugin-kuadrant.8bf02d5482a5a3ed6337.js.map +1 -0
- package/dist-scalprum/plugin-manifest.json +3 -3
- package/dist-scalprum/static/2967.28e7c7f8.chunk.js +2 -0
- package/dist-scalprum/static/2967.28e7c7f8.chunk.js.map +1 -0
- package/dist-scalprum/static/3976.cf3ec7be.chunk.js +2 -0
- package/dist-scalprum/static/3976.cf3ec7be.chunk.js.map +1 -0
- package/dist-scalprum/static/4447.222bb58d.chunk.js +2 -0
- package/dist-scalprum/static/4447.222bb58d.chunk.js.map +1 -0
- package/dist-scalprum/static/5203.e92a3353.chunk.js +2 -0
- package/dist-scalprum/static/5203.e92a3353.chunk.js.map +1 -0
- package/dist-scalprum/static/6371.6ee1f11d.chunk.js +2 -0
- package/dist-scalprum/static/6371.6ee1f11d.chunk.js.map +1 -0
- package/dist-scalprum/static/6800.a7645f4c.chunk.js +2 -0
- package/dist-scalprum/static/6800.a7645f4c.chunk.js.map +1 -0
- package/dist-scalprum/static/69.1decc5e8.chunk.js +2 -0
- package/dist-scalprum/static/69.1decc5e8.chunk.js.map +1 -0
- package/dist-scalprum/static/7005.a9f73153.chunk.js +2 -0
- package/dist-scalprum/static/7005.a9f73153.chunk.js.map +1 -0
- package/dist-scalprum/static/7270.b0e185f1.chunk.js +2 -0
- package/dist-scalprum/static/7270.b0e185f1.chunk.js.map +1 -0
- package/dist-scalprum/static/7791.5c1eea8a.chunk.js +2 -0
- package/dist-scalprum/static/7791.5c1eea8a.chunk.js.map +1 -0
- package/dist-scalprum/static/8789.84963cbc.chunk.js +2 -0
- package/dist-scalprum/static/8789.84963cbc.chunk.js.map +1 -0
- package/dist-scalprum/static/9051.db875198.chunk.js +2 -0
- package/dist-scalprum/static/9051.db875198.chunk.js.map +1 -0
- package/dist-scalprum/static/{2946.a35243f1.chunk.js → 9370.2e9fe34b.chunk.js} +3 -3
- package/dist-scalprum/static/9370.2e9fe34b.chunk.js.map +1 -0
- package/dist-scalprum/static/9838.5df9b1de.chunk.js +2 -0
- package/dist-scalprum/static/9838.5df9b1de.chunk.js.map +1 -0
- package/dist-scalprum/static/exposed-PluginRoot.8a8dd91f.chunk.js +2 -0
- package/dist-scalprum/static/{exposed-PluginRoot.8d8f0b09.chunk.js.map → exposed-PluginRoot.8a8dd91f.chunk.js.map} +1 -1
- package/package.json +3 -1
- package/dist-scalprum/internal.plugin-kuadrant.eacc31ca4d6c1340f8a8.js +0 -2
- package/dist-scalprum/internal.plugin-kuadrant.eacc31ca4d6c1340f8a8.js.map +0 -1
- package/dist-scalprum/static/2946.a35243f1.chunk.js.map +0 -1
- package/dist-scalprum/static/2967.5bade048.chunk.js +0 -2
- package/dist-scalprum/static/2967.5bade048.chunk.js.map +0 -1
- package/dist-scalprum/static/3650.89dfc64c.chunk.js +0 -2
- package/dist-scalprum/static/3650.89dfc64c.chunk.js.map +0 -1
- package/dist-scalprum/static/3976.4cf18515.chunk.js +0 -2
- package/dist-scalprum/static/3976.4cf18515.chunk.js.map +0 -1
- package/dist-scalprum/static/4447.adbf663f.chunk.js +0 -2
- package/dist-scalprum/static/4447.adbf663f.chunk.js.map +0 -1
- package/dist-scalprum/static/5203.fce2a28f.chunk.js +0 -2
- package/dist-scalprum/static/5203.fce2a28f.chunk.js.map +0 -1
- package/dist-scalprum/static/6371.d45f37cc.chunk.js +0 -2
- package/dist-scalprum/static/6371.d45f37cc.chunk.js.map +0 -1
- package/dist-scalprum/static/6800.cd5c7bcb.chunk.js +0 -2
- package/dist-scalprum/static/6800.cd5c7bcb.chunk.js.map +0 -1
- package/dist-scalprum/static/7005.72759857.chunk.js +0 -2
- package/dist-scalprum/static/7005.72759857.chunk.js.map +0 -1
- package/dist-scalprum/static/7270.9473c969.chunk.js +0 -2
- package/dist-scalprum/static/7270.9473c969.chunk.js.map +0 -1
- package/dist-scalprum/static/7791.01371352.chunk.js +0 -2
- package/dist-scalprum/static/7791.01371352.chunk.js.map +0 -1
- package/dist-scalprum/static/8789.30227526.chunk.js +0 -2
- package/dist-scalprum/static/8789.30227526.chunk.js.map +0 -1
- package/dist-scalprum/static/exposed-PluginRoot.8d8f0b09.chunk.js +0 -2
- /package/dist-scalprum/static/{2946.a35243f1.chunk.js.LICENSE.txt → 9370.2e9fe34b.chunk.js.LICENSE.txt} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { useParams, useNavigate } from 'react-router-dom';
|
|
3
|
-
import { useApi,
|
|
3
|
+
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
|
4
|
+
import { kuadrantApiRef } from '../../api.esm.js';
|
|
4
5
|
import { useAsync } from 'react-use';
|
|
5
6
|
import { Progress, ResponseErrorPanel, Page, Header, Link, Content, Breadcrumbs, InfoCard } from '@backstage/core-components';
|
|
6
7
|
import { OpenApiDefinitionWidget } from '@backstage/plugin-api-docs';
|
|
@@ -15,7 +16,6 @@ import { ApiProductDetails } from '../ApiProductDetails/ApiProductDetails.esm.js
|
|
|
15
16
|
import { OidcProviderCard } from '../OidcProviderCard/OidcProviderCard.esm.js';
|
|
16
17
|
import { useKuadrantPermission } from '../../utils/permissions.esm.js';
|
|
17
18
|
import { kuadrantApiProductUpdateAllPermission, kuadrantApiProductDeleteAllPermission } from '../../permissions.esm.js';
|
|
18
|
-
import { handleFetchError } from '../../utils/errors.esm.js';
|
|
19
19
|
|
|
20
20
|
const useStyles = makeStyles((theme) => ({
|
|
21
21
|
label: {
|
|
@@ -46,10 +46,8 @@ const ApiProductDetailPage = () => {
|
|
|
46
46
|
const classes = useStyles();
|
|
47
47
|
const { namespace, name } = useParams();
|
|
48
48
|
const navigate = useNavigate();
|
|
49
|
-
const
|
|
50
|
-
const fetchApi = useApi(fetchApiRef);
|
|
49
|
+
const kuadrantApi = useApi(kuadrantApiRef);
|
|
51
50
|
const alertApi = useApi(alertApiRef);
|
|
52
|
-
const backendUrl = config.getString("backend.baseUrl");
|
|
53
51
|
const [selectedTab, setSelectedTab] = useState(0);
|
|
54
52
|
const [editDialogOpen, setEditDialogOpen] = useState(false);
|
|
55
53
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
@@ -63,30 +61,16 @@ const ApiProductDetailPage = () => {
|
|
|
63
61
|
loading,
|
|
64
62
|
error
|
|
65
63
|
} = useAsync(async () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
69
|
-
if (!response.ok) {
|
|
70
|
-
const err = await handleFetchError(response);
|
|
71
|
-
throw new Error(`Failed to fetch API product. ${err}`);
|
|
72
|
-
}
|
|
73
|
-
return response.json();
|
|
74
|
-
}, [namespace, name, backendUrl, fetchApi, refreshKey]);
|
|
64
|
+
return await kuadrantApi.getApiProduct(namespace, name);
|
|
65
|
+
}, [namespace, name, kuadrantApi, refreshKey]);
|
|
75
66
|
const { value: httpRouteHostnames } = useAsync(async () => {
|
|
76
67
|
if (!product?.spec?.targetRef?.name) {
|
|
77
68
|
return null;
|
|
78
69
|
}
|
|
79
70
|
const routeName = product.spec.targetRef.name;
|
|
80
|
-
const
|
|
81
|
-
`${backendUrl}/api/kuadrant/httproutes/${namespace}/${routeName}`
|
|
82
|
-
);
|
|
83
|
-
if (!response.ok) {
|
|
84
|
-
const err = await handleFetchError(response);
|
|
85
|
-
throw new Error(`Failed to fetch HTTPRoute. ${err}`);
|
|
86
|
-
}
|
|
87
|
-
const route = await response.json();
|
|
71
|
+
const route = await kuadrantApi.getHttpRoute(namespace, routeName);
|
|
88
72
|
return route?.spec?.hostnames || null;
|
|
89
|
-
}, [product, namespace,
|
|
73
|
+
}, [product, namespace, kuadrantApi]);
|
|
90
74
|
const handlePublishToggle = async () => {
|
|
91
75
|
if (!product) return;
|
|
92
76
|
const newStatus = product.spec?.publishStatus === "Published" ? "Draft" : "Published";
|
|
@@ -100,18 +84,7 @@ const ApiProductDetailPage = () => {
|
|
|
100
84
|
return;
|
|
101
85
|
}
|
|
102
86
|
try {
|
|
103
|
-
|
|
104
|
-
`${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`,
|
|
105
|
-
{
|
|
106
|
-
method: "PATCH",
|
|
107
|
-
headers: { "Content-Type": "application/json" },
|
|
108
|
-
body: JSON.stringify({ spec: { publishStatus: newStatus } })
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
|
-
if (!response.ok) {
|
|
112
|
-
const err = await handleFetchError(response);
|
|
113
|
-
throw new Error(err);
|
|
114
|
-
}
|
|
87
|
+
await kuadrantApi.updateApiProduct(namespace, name, { spec: { publishStatus: newStatus } });
|
|
115
88
|
alertApi.post({
|
|
116
89
|
message: `API Product ${newStatus === "Published" ? "published" : "unpublished"} successfully`,
|
|
117
90
|
severity: "success",
|
|
@@ -140,14 +113,7 @@ const ApiProductDetailPage = () => {
|
|
|
140
113
|
if (!product) return;
|
|
141
114
|
setDeleting(true);
|
|
142
115
|
try {
|
|
143
|
-
|
|
144
|
-
`${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`,
|
|
145
|
-
{ method: "DELETE" }
|
|
146
|
-
);
|
|
147
|
-
if (!response.ok) {
|
|
148
|
-
const err = await handleFetchError(response);
|
|
149
|
-
throw new Error(err);
|
|
150
|
-
}
|
|
116
|
+
await kuadrantApi.deleteApiProduct(namespace, name);
|
|
151
117
|
setDeleteDialogOpen(false);
|
|
152
118
|
alertApi.post({
|
|
153
119
|
message: "API Product deleted successfully",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiProductDetailPage.esm.js","sources":["../../../src/components/ApiProductDetailPage/ApiProductDetailPage.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { useParams, useNavigate } from \"react-router-dom\";\nimport {\n useApi,\n configApiRef,\n fetchApiRef,\n alertApiRef,\n} from \"@backstage/core-plugin-api\";\nimport { useAsync } from \"react-use\";\nimport {\n Header,\n Page,\n Content,\n Progress,\n ResponseErrorPanel,\n InfoCard,\n Link,\n Breadcrumbs,\n} from \"@backstage/core-components\";\nimport { OpenApiDefinitionWidget } from \"@backstage/plugin-api-docs\";\nimport {\n Box,\n Typography,\n IconButton,\n Tooltip,\n Tabs,\n Tab,\n Button,\n makeStyles,\n Grid,\n Chip,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n} from \"@material-ui/core\";\nimport ArrowBackIcon from \"@material-ui/icons/ArrowBack\";\nimport EditIcon from \"@material-ui/icons/Edit\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport { Alert } from '@material-ui/lab';\nimport { APIProduct } from \"../../types/api-management\";\nimport { EditAPIProductDialog } from \"../EditAPIProductDialog\";\nimport { ConfirmDeleteDialog } from \"../ConfirmDeleteDialog\";\nimport { ApiProductDetails } from \"../ApiProductDetails\";\nimport { OidcProviderCard } from \"../OidcProviderCard\";\nimport { useKuadrantPermission } from \"../../utils/permissions\";\nimport {\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductDeleteAllPermission,\n} from \"../../permissions\";\nimport {handleFetchError} from \"../../utils/errors.ts\";\n\nconst useStyles = makeStyles((theme) => ({\n label: {\n fontWeight: 600,\n color: theme.palette.text.secondary,\n marginBottom: theme.spacing(0.5),\n fontSize: '0.75rem',\n textTransform: 'uppercase',\n },\n actionButtons: {\n display: \"flex\",\n gap: theme.spacing(1),\n alignItems: \"center\",\n },\n cardHeader: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'flex-start',\n marginBottom: theme.spacing(2),\n },\n cardActions: {\n display: 'flex',\n gap: theme.spacing(1),\n alignItems: 'center',\n },\n}));\n\nexport const ApiProductDetailPage = () => {\n const classes = useStyles();\n const { namespace, name } = useParams<{ namespace: string; name: string }>();\n const navigate = useNavigate();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const alertApi = useApi(alertApiRef);\n const backendUrl = config.getString(\"backend.baseUrl\");\n\n const [selectedTab, setSelectedTab] = useState(0);\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [deleting, setDeleting] = useState(false);\n const [refreshKey, setRefreshKey] = useState(0);\n\n const { allowed: canUpdateApiProduct } = useKuadrantPermission(kuadrantApiProductUpdateAllPermission);\n const { allowed: canDeleteApiProduct } = useKuadrantPermission(kuadrantApiProductDeleteAllPermission);\n const canPublishApiProduct = canUpdateApiProduct;\n\n const {\n value: product,\n loading,\n error,\n } = useAsync(async () => {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`\n );\n\n if (!response.ok) {\n const err = await handleFetchError(response);\n throw new Error(`Failed to fetch API product. ${err}`);\n }\n\n return response.json() as Promise<APIProduct>;\n }, [namespace, name, backendUrl, fetchApi, refreshKey]);\n\n // fetch httproute to get hostnames\n const { value: httpRouteHostnames } = useAsync(async () => {\n if (!product?.spec?.targetRef?.name) {\n return null;\n }\n\n const routeName = product.spec.targetRef.name;\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/httproutes/${namespace}/${routeName}`\n );\n\n if (!response.ok) {\n const err = await handleFetchError(response);\n throw new Error(`Failed to fetch HTTPRoute. ${err}`);\n }\n\n const route = await response.json();\n return route?.spec?.hostnames || null;\n }, [product, namespace, backendUrl, fetchApi]);\n\n const handlePublishToggle = async () => {\n if (!product) return;\n const newStatus = product.spec?.publishStatus === \"Published\" ? \"Draft\" : \"Published\";\n const lifecycle = product.metadata.labels?.lifecycle;\n\n // prevent publishing retired APIs\n if (newStatus === \"Published\" && lifecycle === \"retired\") {\n alertApi.post({\n message: `Cannot publish a retired API product. Please change the lifecycle status first.`,\n severity: \"error\",\n display: \"transient\",\n });\n return;\n }\n\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`,\n {\n method: \"PATCH\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ spec: { publishStatus: newStatus } }),\n }\n );\n if (!response.ok) {\n const err = await handleFetchError(response);\n throw new Error(err);\n }\n alertApi.post({\n message: `API Product ${newStatus === \"Published\" ? \"published\" : \"unpublished\"} successfully`,\n severity: \"success\",\n display: \"transient\",\n });\n setRefreshKey((k) => k + 1);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to update publish status. ${errorMessage}`,\n severity: \"error\",\n display: \"transient\",\n });\n }\n };\n\n const handleEditSuccess = () => {\n setEditDialogOpen(false);\n setRefreshKey((k) => k + 1);\n alertApi.post({\n message: \"API Product updated successfully\",\n severity: \"success\",\n display: \"transient\",\n });\n };\n\n const handleDelete = async () => {\n if (!product) return;\n setDeleting(true);\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`,\n { method: \"DELETE\" }\n );\n if (!response.ok) {\n const err = await handleFetchError(response);\n throw new Error(err);\n }\n setDeleteDialogOpen(false);\n alertApi.post({\n message: \"API Product deleted successfully\",\n severity: \"success\",\n display: \"transient\",\n });\n navigate(\"/kuadrant/api-products\");\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to delete API product. ${errorMessage}`,\n severity: \"error\",\n display: \"transient\",\n });\n } finally {\n setDeleting(false);\n }\n };\n\n if (loading) {\n return <Progress />;\n }\n\n if (error || !product) {\n return (\n <ResponseErrorPanel error={error || new Error(\"API product not found\")} />\n );\n }\n\n const isPublished = product.spec?.publishStatus === \"Published\";\n\n // get policy conditions from status\n const planPolicyCondition = product.status?.conditions?.find(\n (c) => c.type === \"PlanPolicyDiscovered\"\n );\n const authPolicyCondition = product.status?.conditions?.find(\n (c) => c.type === \"AuthPolicyDiscovered\"\n );\n const discoveredPlans = product.status?.discoveredPlans || [];\n\n const authSchemes = product.status?.discoveredAuthScheme?.authentication || {};\n const schemeObjects = Object.values(authSchemes);\n const hasOIDCTab = schemeObjects.some((scheme: any) =>\n scheme.hasOwnProperty(\"jwt\"),\n );\n // Extract JWT issuer from the first JWT scheme\n const jwtScheme = schemeObjects.find((scheme: any) => scheme.hasOwnProperty(\"jwt\"));\n const jwtIssuer = (jwtScheme as any)?.jwt?.issuerUrl || \"unknown\";\n const jwtTokenEndpoint = product.status?.oidcDiscovery?.tokenEndpoint || \"unknown\";\n\n // compute tab indices\n const hasDefinitionTab = !!(product.status?.openapi?.raw || product.spec?.documentation?.openAPISpecURL);\n const hasPoliciesTab = !!(planPolicyCondition || authPolicyCondition || discoveredPlans.length > 0);\n\n let nextIndex = 1; // Overview is always at index 0\n const definitionTabIndex = hasDefinitionTab ? nextIndex++ : -1;\n const policiesTabIndex = hasPoliciesTab ? nextIndex++ : -1;\n const oidcTabIndex = hasOIDCTab ? nextIndex++ : -1;\n\n const formatLimits = (limits: any): string => {\n if (!limits) return \"No limits\";\n const parts: string[] = [];\n if (limits.daily) parts.push(`${limits.daily}/day`);\n if (limits.weekly) parts.push(`${limits.weekly}/week`);\n if (limits.monthly) parts.push(`${limits.monthly}/month`);\n if (limits.yearly) parts.push(`${limits.yearly}/year`);\n return parts.length > 0 ? parts.join(\", \") : \"No limits\";\n };\n\n return (\n <Page themeId=\"tool\">\n <Header\n title={product.spec?.displayName || product.metadata.name}\n subtitle={product.spec?.description || \"\"}\n >\n <Box className={classes.actionButtons}>\n <Link to=\"/kuadrant/api-products\">\n <Button startIcon={<ArrowBackIcon />}>Back</Button>\n </Link>\n {canPublishApiProduct && (\n <Button\n variant=\"outlined\"\n color={isPublished ? \"default\" : \"primary\"}\n onClick={handlePublishToggle}\n >\n {isPublished ? \"Unpublish API product\" : \"Publish API product\"}\n </Button>\n )}\n {canUpdateApiProduct && (\n <Tooltip title=\"Edit\">\n <IconButton onClick={() => setEditDialogOpen(true)} size=\"small\">\n <EditIcon />\n </IconButton>\n </Tooltip>\n )}\n {canDeleteApiProduct && (\n <Tooltip title=\"Delete\">\n <IconButton onClick={() => setDeleteDialogOpen(true)} size=\"small\">\n <DeleteIcon />\n </IconButton>\n </Tooltip>\n )}\n </Box>\n </Header>\n <Content>\n <Box mb={2}>\n <Breadcrumbs aria-label=\"breadcrumb\">\n <Link to=\"/kuadrant/api-products\">API Products</Link>\n <Typography>{product.spec?.displayName || product.metadata.name}</Typography>\n </Breadcrumbs>\n </Box>\n\n\n {product.metadata.labels?.lifecycle === 'deprecated' && (\n <Box mb={2}>\n <Alert severity=\"warning\">\n <strong>This API is deprecated.</strong> Please contact your administrator for more details.\n </Alert>\n </Box>\n )}\n\n {product.metadata.labels?.lifecycle === 'retired' && (\n <Box mb={2}>\n <Alert severity=\"error\">\n <strong>This API has been retired and is no longer available.</strong> Please contact your administrator for alternatives.\n </Alert>\n </Box>\n )}\n\n <Box mb={2}>\n <Tabs\n value={selectedTab}\n onChange={(_, newValue) => setSelectedTab(newValue)}\n indicatorColor=\"primary\"\n textColor=\"primary\"\n >\n <Tab label=\"Overview\" />\n {hasDefinitionTab && <Tab label=\"Definition\" />}\n {hasPoliciesTab && <Tab label=\"Policies\" />}\n {hasOIDCTab && <Tab label=\"OIDC\" />}\n </Tabs>\n </Box>\n\n {selectedTab === 0 && (\n <InfoCard title=\"API Product\">\n <Box className={classes.cardHeader}>\n <Box>\n <Typography variant=\"caption\" className={classes.label}>\n Product Name\n </Typography>\n <Typography variant=\"h6\">\n {product.spec?.displayName || product.metadata.name}\n </Typography>\n </Box>\n <Box className={classes.cardActions}>\n {canPublishApiProduct && (\n <Button\n variant=\"outlined\"\n color={isPublished ? \"default\" : \"primary\"}\n onClick={handlePublishToggle}\n size=\"small\"\n >\n {isPublished ? \"Unpublish API product\" : \"Publish API product\"}\n </Button>\n )}\n {canUpdateApiProduct && (\n <IconButton onClick={() => setEditDialogOpen(true)} size=\"small\">\n <EditIcon fontSize=\"small\" />\n </IconButton>\n )}\n {canDeleteApiProduct && (\n <IconButton onClick={() => setDeleteDialogOpen(true)} size=\"small\">\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n )}\n </Box>\n </Box>\n\n <ApiProductDetails\n product={product}\n showStatus={true}\n showCatalogLink={true}\n httpRouteHostnames={httpRouteHostnames}\n />\n </InfoCard>\n )}\n\n {selectedTab === definitionTabIndex && hasDefinitionTab && (\n <InfoCard title=\"API Definition\">\n {product.status?.openapi?.raw ? (\n <OpenApiDefinitionWidget definition={product.status.openapi.raw} />\n ) : (\n <Typography variant=\"body2\" color=\"textSecondary\">\n {product.spec?.documentation?.openAPISpecURL ? (\n <>\n OpenAPI specification not yet synced. View at:{\" \"}\n <Link to={product.spec.documentation.openAPISpecURL} target=\"_blank\">\n {product.spec.documentation.openAPISpecURL}\n </Link>\n </>\n ) : (\n \"No OpenAPI specification available for this API product.\"\n )}\n </Typography>\n )}\n </InfoCard>\n )}\n\n {selectedTab === policiesTabIndex && hasPoliciesTab && (\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <InfoCard title=\"Discovered Policies\">\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <Typography variant=\"body2\" color=\"textSecondary\" gutterBottom>\n Plan Policy\n </Typography>\n {planPolicyCondition ? (\n <Box>\n <Chip\n label={planPolicyCondition.status === \"True\" ? \"Found\" : \"Not Found\"}\n size=\"small\"\n style={{\n backgroundColor: planPolicyCondition.status === \"True\" ? \"#4caf50\" : \"#ff9800\",\n color: \"#fff\",\n marginBottom: 8,\n }}\n />\n <Typography variant=\"body2\">\n {planPolicyCondition.message || \"No details available\"}\n </Typography>\n </Box>\n ) : (\n <Typography variant=\"body2\">No plan policy information</Typography>\n )}\n </Grid>\n <Grid item xs={12} md={6}>\n <Typography variant=\"body2\" color=\"textSecondary\" gutterBottom>\n Auth Policy\n </Typography>\n {authPolicyCondition ? (\n <Box>\n <Chip\n label={authPolicyCondition.status === \"True\" ? \"Found\" : \"Not Found\"}\n size=\"small\"\n style={{\n backgroundColor: authPolicyCondition.status === \"True\" ? \"#4caf50\" : \"#ff9800\",\n color: \"#fff\",\n marginBottom: 8,\n }}\n />\n <Typography variant=\"body2\">\n {authPolicyCondition.message || \"No details available\"}\n </Typography>\n </Box>\n ) : (\n <Typography variant=\"body2\">No auth policy information</Typography>\n )}\n </Grid>\n </Grid>\n </InfoCard>\n </Grid>\n\n {discoveredPlans.length > 0 && (\n <Grid item xs={12}>\n <InfoCard title=\"Effective Plan Tiers\">\n <Typography variant=\"body2\" color=\"textSecondary\" paragraph>\n These tiers are computed from all attached PlanPolicies (including gateway-level policies).\n </Typography>\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>Tier</TableCell>\n <TableCell>Rate Limits</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {discoveredPlans.map((plan) => (\n <TableRow key={plan.tier}>\n <TableCell>\n <Chip label={plan.tier} size=\"small\" color=\"primary\" />\n </TableCell>\n <TableCell>{formatLimits(plan.limits)}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </InfoCard>\n </Grid>\n )}\n </Grid>\n )}\n\n {selectedTab === oidcTabIndex && hasOIDCTab && (\n <OidcProviderCard\n issuerUrl={jwtIssuer}\n tokenEndpoint={jwtTokenEndpoint}\n />\n )}\n </Content>\n\n <EditAPIProductDialog\n open={editDialogOpen}\n onClose={() => setEditDialogOpen(false)}\n onSuccess={handleEditSuccess}\n namespace={namespace || \"\"}\n name={name || \"\"}\n />\n\n <ConfirmDeleteDialog\n open={deleteDialogOpen}\n title=\"Delete API Product\"\n description={`Are you sure you want to delete \"${product.spec?.displayName || product.metadata.name}\"? This action cannot be undone.`}\n severity=\"high\"\n confirmText={product.metadata.name}\n deleting={deleting}\n onConfirm={handleDelete}\n onCancel={() => setDeleteDialogOpen(false)}\n />\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ApiProductDetailPage.esm.js","sources":["../../../src/components/ApiProductDetailPage/ApiProductDetailPage.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { useParams, useNavigate } from \"react-router-dom\";\nimport {\n useApi,\n alertApiRef,\n} from \"@backstage/core-plugin-api\";\nimport { kuadrantApiRef } from '../../api';\nimport { useAsync } from \"react-use\";\nimport {\n Header,\n Page,\n Content,\n Progress,\n ResponseErrorPanel,\n InfoCard,\n Link,\n Breadcrumbs,\n} from \"@backstage/core-components\";\nimport { OpenApiDefinitionWidget } from \"@backstage/plugin-api-docs\";\nimport {\n Box,\n Typography,\n IconButton,\n Tooltip,\n Tabs,\n Tab,\n Button,\n makeStyles,\n Grid,\n Chip,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n} from \"@material-ui/core\";\nimport ArrowBackIcon from \"@material-ui/icons/ArrowBack\";\nimport EditIcon from \"@material-ui/icons/Edit\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport { Alert } from '@material-ui/lab';\nimport { APIProduct } from \"../../types/api-management\";\nimport { EditAPIProductDialog } from \"../EditAPIProductDialog\";\nimport { ConfirmDeleteDialog } from \"../ConfirmDeleteDialog\";\nimport { ApiProductDetails } from \"../ApiProductDetails\";\nimport { OidcProviderCard } from \"../OidcProviderCard\";\nimport { useKuadrantPermission } from \"../../utils/permissions\";\nimport {\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductDeleteAllPermission,\n} from \"../../permissions\";\n\nconst useStyles = makeStyles((theme) => ({\n label: {\n fontWeight: 600,\n color: theme.palette.text.secondary,\n marginBottom: theme.spacing(0.5),\n fontSize: '0.75rem',\n textTransform: 'uppercase',\n },\n actionButtons: {\n display: \"flex\",\n gap: theme.spacing(1),\n alignItems: \"center\",\n },\n cardHeader: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'flex-start',\n marginBottom: theme.spacing(2),\n },\n cardActions: {\n display: 'flex',\n gap: theme.spacing(1),\n alignItems: 'center',\n },\n}));\n\nexport const ApiProductDetailPage = () => {\n const classes = useStyles();\n const { namespace, name } = useParams<{ namespace: string; name: string }>();\n const navigate = useNavigate();\n const kuadrantApi = useApi(kuadrantApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [selectedTab, setSelectedTab] = useState(0);\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [deleting, setDeleting] = useState(false);\n const [refreshKey, setRefreshKey] = useState(0);\n\n const { allowed: canUpdateApiProduct } = useKuadrantPermission(kuadrantApiProductUpdateAllPermission);\n const { allowed: canDeleteApiProduct } = useKuadrantPermission(kuadrantApiProductDeleteAllPermission);\n const canPublishApiProduct = canUpdateApiProduct;\n\n const {\n value: product,\n loading,\n error,\n } = useAsync(async () => {\n return await kuadrantApi.getApiProduct(namespace!, name!) as APIProduct;\n }, [namespace, name, kuadrantApi, refreshKey]);\n\n // fetch httproute to get hostnames\n const { value: httpRouteHostnames } = useAsync(async () => {\n if (!product?.spec?.targetRef?.name) {\n return null;\n }\n\n const routeName = product.spec.targetRef.name;\n const route = await kuadrantApi.getHttpRoute(namespace!, routeName)\n\n return route?.spec?.hostnames || null;\n }, [product, namespace, kuadrantApi]);\n\n const handlePublishToggle = async () => {\n if (!product) return;\n const newStatus = product.spec?.publishStatus === \"Published\" ? \"Draft\" : \"Published\";\n const lifecycle = product.metadata.labels?.lifecycle;\n\n // prevent publishing retired APIs\n if (newStatus === \"Published\" && lifecycle === \"retired\") {\n alertApi.post({\n message: `Cannot publish a retired API product. Please change the lifecycle status first.`,\n severity: \"error\",\n display: \"transient\",\n });\n return;\n }\n\n try {\n // @ts-ignore since updating partially the obj\n await kuadrantApi.updateApiProduct(namespace!, name!, { spec: { publishStatus: newStatus } });\n alertApi.post({\n message: `API Product ${newStatus === \"Published\" ? \"published\" : \"unpublished\"} successfully`,\n severity: \"success\",\n display: \"transient\",\n });\n setRefreshKey((k) => k + 1);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to update publish status. ${errorMessage}`,\n severity: \"error\",\n display: \"transient\",\n });\n }\n };\n\n const handleEditSuccess = () => {\n setEditDialogOpen(false);\n setRefreshKey((k) => k + 1);\n alertApi.post({\n message: \"API Product updated successfully\",\n severity: \"success\",\n display: \"transient\",\n });\n };\n\n const handleDelete = async () => {\n if (!product) return;\n setDeleting(true);\n try {\n await kuadrantApi.deleteApiProduct(namespace!, name!);\n setDeleteDialogOpen(false);\n alertApi.post({\n message: \"API Product deleted successfully\",\n severity: \"success\",\n display: \"transient\",\n });\n navigate(\"/kuadrant/api-products\");\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to delete API product. ${errorMessage}`,\n severity: \"error\",\n display: \"transient\",\n });\n } finally {\n setDeleting(false);\n }\n };\n\n if (loading) {\n return <Progress />;\n }\n\n if (error || !product) {\n return (\n <ResponseErrorPanel error={error || new Error(\"API product not found\")} />\n );\n }\n\n const isPublished = product.spec?.publishStatus === \"Published\";\n\n // get policy conditions from status\n const planPolicyCondition = product.status?.conditions?.find(\n (c) => c.type === \"PlanPolicyDiscovered\"\n );\n const authPolicyCondition = product.status?.conditions?.find(\n (c) => c.type === \"AuthPolicyDiscovered\"\n );\n const discoveredPlans = product.status?.discoveredPlans || [];\n\n const authSchemes = product.status?.discoveredAuthScheme?.authentication || {};\n const schemeObjects = Object.values(authSchemes);\n const hasOIDCTab = schemeObjects.some((scheme: any) =>\n scheme.hasOwnProperty(\"jwt\"),\n );\n // Extract JWT issuer from the first JWT scheme\n const jwtScheme = schemeObjects.find((scheme: any) => scheme.hasOwnProperty(\"jwt\"));\n const jwtIssuer = (jwtScheme as any)?.jwt?.issuerUrl || \"unknown\";\n const jwtTokenEndpoint = product.status?.oidcDiscovery?.tokenEndpoint || \"unknown\";\n\n // compute tab indices\n const hasDefinitionTab = !!(product.status?.openapi?.raw || product.spec?.documentation?.openAPISpecURL);\n const hasPoliciesTab = !!(planPolicyCondition || authPolicyCondition || discoveredPlans.length > 0);\n\n let nextIndex = 1; // Overview is always at index 0\n const definitionTabIndex = hasDefinitionTab ? nextIndex++ : -1;\n const policiesTabIndex = hasPoliciesTab ? nextIndex++ : -1;\n const oidcTabIndex = hasOIDCTab ? nextIndex++ : -1;\n\n const formatLimits = (limits: any): string => {\n if (!limits) return \"No limits\";\n const parts: string[] = [];\n if (limits.daily) parts.push(`${limits.daily}/day`);\n if (limits.weekly) parts.push(`${limits.weekly}/week`);\n if (limits.monthly) parts.push(`${limits.monthly}/month`);\n if (limits.yearly) parts.push(`${limits.yearly}/year`);\n return parts.length > 0 ? parts.join(\", \") : \"No limits\";\n };\n\n return (\n <Page themeId=\"tool\">\n <Header\n title={product.spec?.displayName || product.metadata.name}\n subtitle={product.spec?.description || \"\"}\n >\n <Box className={classes.actionButtons}>\n <Link to=\"/kuadrant/api-products\">\n <Button startIcon={<ArrowBackIcon />}>Back</Button>\n </Link>\n {canPublishApiProduct && (\n <Button\n variant=\"outlined\"\n color={isPublished ? \"default\" : \"primary\"}\n onClick={handlePublishToggle}\n >\n {isPublished ? \"Unpublish API product\" : \"Publish API product\"}\n </Button>\n )}\n {canUpdateApiProduct && (\n <Tooltip title=\"Edit\">\n <IconButton onClick={() => setEditDialogOpen(true)} size=\"small\">\n <EditIcon />\n </IconButton>\n </Tooltip>\n )}\n {canDeleteApiProduct && (\n <Tooltip title=\"Delete\">\n <IconButton onClick={() => setDeleteDialogOpen(true)} size=\"small\">\n <DeleteIcon />\n </IconButton>\n </Tooltip>\n )}\n </Box>\n </Header>\n <Content>\n <Box mb={2}>\n <Breadcrumbs aria-label=\"breadcrumb\">\n <Link to=\"/kuadrant/api-products\">API Products</Link>\n <Typography>{product.spec?.displayName || product.metadata.name}</Typography>\n </Breadcrumbs>\n </Box>\n\n\n {product.metadata.labels?.lifecycle === 'deprecated' && (\n <Box mb={2}>\n <Alert severity=\"warning\">\n <strong>This API is deprecated.</strong> Please contact your administrator for more details.\n </Alert>\n </Box>\n )}\n\n {product.metadata.labels?.lifecycle === 'retired' && (\n <Box mb={2}>\n <Alert severity=\"error\">\n <strong>This API has been retired and is no longer available.</strong> Please contact your administrator for alternatives.\n </Alert>\n </Box>\n )}\n\n <Box mb={2}>\n <Tabs\n value={selectedTab}\n onChange={(_, newValue) => setSelectedTab(newValue)}\n indicatorColor=\"primary\"\n textColor=\"primary\"\n >\n <Tab label=\"Overview\" />\n {hasDefinitionTab && <Tab label=\"Definition\" />}\n {hasPoliciesTab && <Tab label=\"Policies\" />}\n {hasOIDCTab && <Tab label=\"OIDC\" />}\n </Tabs>\n </Box>\n\n {selectedTab === 0 && (\n <InfoCard title=\"API Product\">\n <Box className={classes.cardHeader}>\n <Box>\n <Typography variant=\"caption\" className={classes.label}>\n Product Name\n </Typography>\n <Typography variant=\"h6\">\n {product.spec?.displayName || product.metadata.name}\n </Typography>\n </Box>\n <Box className={classes.cardActions}>\n {canPublishApiProduct && (\n <Button\n variant=\"outlined\"\n color={isPublished ? \"default\" : \"primary\"}\n onClick={handlePublishToggle}\n size=\"small\"\n >\n {isPublished ? \"Unpublish API product\" : \"Publish API product\"}\n </Button>\n )}\n {canUpdateApiProduct && (\n <IconButton onClick={() => setEditDialogOpen(true)} size=\"small\">\n <EditIcon fontSize=\"small\" />\n </IconButton>\n )}\n {canDeleteApiProduct && (\n <IconButton onClick={() => setDeleteDialogOpen(true)} size=\"small\">\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n )}\n </Box>\n </Box>\n\n <ApiProductDetails\n product={product}\n showStatus={true}\n showCatalogLink={true}\n httpRouteHostnames={httpRouteHostnames}\n />\n </InfoCard>\n )}\n\n {selectedTab === definitionTabIndex && hasDefinitionTab && (\n <InfoCard title=\"API Definition\">\n {product.status?.openapi?.raw ? (\n <OpenApiDefinitionWidget definition={product.status.openapi.raw} />\n ) : (\n <Typography variant=\"body2\" color=\"textSecondary\">\n {product.spec?.documentation?.openAPISpecURL ? (\n <>\n OpenAPI specification not yet synced. View at:{\" \"}\n <Link to={product.spec.documentation.openAPISpecURL} target=\"_blank\">\n {product.spec.documentation.openAPISpecURL}\n </Link>\n </>\n ) : (\n \"No OpenAPI specification available for this API product.\"\n )}\n </Typography>\n )}\n </InfoCard>\n )}\n\n {selectedTab === policiesTabIndex && hasPoliciesTab && (\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <InfoCard title=\"Discovered Policies\">\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <Typography variant=\"body2\" color=\"textSecondary\" gutterBottom>\n Plan Policy\n </Typography>\n {planPolicyCondition ? (\n <Box>\n <Chip\n label={planPolicyCondition.status === \"True\" ? \"Found\" : \"Not Found\"}\n size=\"small\"\n style={{\n backgroundColor: planPolicyCondition.status === \"True\" ? \"#4caf50\" : \"#ff9800\",\n color: \"#fff\",\n marginBottom: 8,\n }}\n />\n <Typography variant=\"body2\">\n {planPolicyCondition.message || \"No details available\"}\n </Typography>\n </Box>\n ) : (\n <Typography variant=\"body2\">No plan policy information</Typography>\n )}\n </Grid>\n <Grid item xs={12} md={6}>\n <Typography variant=\"body2\" color=\"textSecondary\" gutterBottom>\n Auth Policy\n </Typography>\n {authPolicyCondition ? (\n <Box>\n <Chip\n label={authPolicyCondition.status === \"True\" ? \"Found\" : \"Not Found\"}\n size=\"small\"\n style={{\n backgroundColor: authPolicyCondition.status === \"True\" ? \"#4caf50\" : \"#ff9800\",\n color: \"#fff\",\n marginBottom: 8,\n }}\n />\n <Typography variant=\"body2\">\n {authPolicyCondition.message || \"No details available\"}\n </Typography>\n </Box>\n ) : (\n <Typography variant=\"body2\">No auth policy information</Typography>\n )}\n </Grid>\n </Grid>\n </InfoCard>\n </Grid>\n\n {discoveredPlans.length > 0 && (\n <Grid item xs={12}>\n <InfoCard title=\"Effective Plan Tiers\">\n <Typography variant=\"body2\" color=\"textSecondary\" paragraph>\n These tiers are computed from all attached PlanPolicies (including gateway-level policies).\n </Typography>\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>Tier</TableCell>\n <TableCell>Rate Limits</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {discoveredPlans.map((plan) => (\n <TableRow key={plan.tier}>\n <TableCell>\n <Chip label={plan.tier} size=\"small\" color=\"primary\" />\n </TableCell>\n <TableCell>{formatLimits(plan.limits)}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </InfoCard>\n </Grid>\n )}\n </Grid>\n )}\n\n {selectedTab === oidcTabIndex && hasOIDCTab && (\n <OidcProviderCard\n issuerUrl={jwtIssuer}\n tokenEndpoint={jwtTokenEndpoint}\n />\n )}\n </Content>\n\n <EditAPIProductDialog\n open={editDialogOpen}\n onClose={() => setEditDialogOpen(false)}\n onSuccess={handleEditSuccess}\n namespace={namespace || \"\"}\n name={name || \"\"}\n />\n\n <ConfirmDeleteDialog\n open={deleteDialogOpen}\n title=\"Delete API Product\"\n description={`Are you sure you want to delete \"${product.spec?.displayName || product.metadata.name}\"? This action cannot be undone.`}\n severity=\"high\"\n confirmText={product.metadata.name}\n deleting={deleting}\n onConfirm={handleDelete}\n onCancel={() => setDeleteDialogOpen(false)}\n />\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useEntity } from '@backstage/plugin-catalog-react';
|
|
3
|
-
import { useApi,
|
|
3
|
+
import { useApi, identityApiRef } from '@backstage/core-plugin-api';
|
|
4
4
|
import { InfoCard, Progress, ResponseErrorPanel } from '@backstage/core-components';
|
|
5
5
|
import { makeStyles, Typography, Box } from '@material-ui/core';
|
|
6
6
|
import useAsync from 'react-use/lib/useAsync';
|
|
@@ -8,6 +8,7 @@ import { useKuadrantPermission } from '../../utils/permissions.esm.js';
|
|
|
8
8
|
import { kuadrantApiProductReadAllPermission } from '../../permissions.esm.js';
|
|
9
9
|
import { ApiProductDetails } from '../ApiProductDetails/ApiProductDetails.esm.js';
|
|
10
10
|
import { OidcProviderCard } from '../OidcProviderCard/OidcProviderCard.esm.js';
|
|
11
|
+
import { kuadrantApiRef } from '../../api.esm.js';
|
|
11
12
|
|
|
12
13
|
const useStyles = makeStyles((theme) => ({
|
|
13
14
|
label: {
|
|
@@ -21,10 +22,8 @@ const useStyles = makeStyles((theme) => ({
|
|
|
21
22
|
const ApiProductInfoCard = () => {
|
|
22
23
|
const classes = useStyles();
|
|
23
24
|
const { entity } = useEntity();
|
|
24
|
-
const
|
|
25
|
-
const fetchApi = useApi(fetchApiRef);
|
|
25
|
+
const kuadrantApi = useApi(kuadrantApiRef);
|
|
26
26
|
const identityApi = useApi(identityApiRef);
|
|
27
|
-
const backendUrl = config.getString("backend.baseUrl");
|
|
28
27
|
const { allowed: canReadAll, loading: permLoading } = useKuadrantPermission(
|
|
29
28
|
kuadrantApiProductReadAllPermission
|
|
30
29
|
);
|
|
@@ -38,15 +37,8 @@ const ApiProductInfoCard = () => {
|
|
|
38
37
|
if (!namespace || !apiProductName) {
|
|
39
38
|
return null;
|
|
40
39
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
);
|
|
44
|
-
if (!productResponse.ok) {
|
|
45
|
-
const errorData = await productResponse.json();
|
|
46
|
-
throw new Error(errorData.error || `Failed to fetch API product: ${productResponse.status}`);
|
|
47
|
-
}
|
|
48
|
-
return productResponse.json();
|
|
49
|
-
}, [backendUrl, fetchApi, namespace, apiProductName]);
|
|
40
|
+
return kuadrantApi.getApiProduct(namespace, apiProductName);
|
|
41
|
+
}, [kuadrantApi, namespace, apiProductName]);
|
|
50
42
|
const owner = apiProduct?.metadata?.annotations?.["backstage.io/owner"];
|
|
51
43
|
const ownerUserId = owner?.split("/")[1];
|
|
52
44
|
const canView = canReadAll || currentUserId && ownerUserId === currentUserId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiProductInfoCard.esm.js","sources":["../../../src/components/ApiProductInfoCard/ApiProductInfoCard.tsx"],"sourcesContent":["import React from 'react';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { useApi,
|
|
1
|
+
{"version":3,"file":"ApiProductInfoCard.esm.js","sources":["../../../src/components/ApiProductInfoCard/ApiProductInfoCard.tsx"],"sourcesContent":["import React from 'react';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { useApi, identityApiRef } from '@backstage/core-plugin-api';\nimport { InfoCard, Progress, ResponseErrorPanel } from '@backstage/core-components';\nimport { Typography, Box, makeStyles } from '@material-ui/core';\nimport useAsync from 'react-use/lib/useAsync';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { kuadrantApiProductReadAllPermission } from '../../permissions';\nimport { ApiProductDetails } from '../ApiProductDetails';\nimport { OidcProviderCard } from '../OidcProviderCard';\nimport { kuadrantApiRef } from '../../api';\n\nconst useStyles = makeStyles((theme) => ({\n label: {\n fontWeight: 600,\n color: theme.palette.text.secondary,\n marginBottom: theme.spacing(0.5),\n fontSize: '0.75rem',\n textTransform: 'uppercase',\n },\n}));\n\nexport const ApiProductInfoCard = () => {\n const classes = useStyles();\n const { entity } = useEntity();\n const kuadrantApi = useApi(kuadrantApiRef);\n const identityApi = useApi(identityApiRef);\n\n const { allowed: canReadAll, loading: permLoading } = useKuadrantPermission(\n kuadrantApiProductReadAllPermission\n );\n\n const namespace = entity.metadata.annotations?.['kuadrant.io/namespace'];\n const apiProductName = entity.metadata.annotations?.['kuadrant.io/apiproduct'];\n\n const { value: currentUserId } = useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n return identity.userEntityRef.split('/')[1] || 'guest';\n }, [identityApi]);\n\n const { value: apiProduct, loading, error } = useAsync(async () => {\n if (!namespace || !apiProductName) {\n return null;\n }\n\n return kuadrantApi.getApiProduct(namespace, apiProductName);\n }, [kuadrantApi, namespace, apiProductName]);\n\n // check if user has permission to view this api product\n const owner = apiProduct?.metadata?.annotations?.['backstage.io/owner'];\n const ownerUserId = owner?.split('/')[1];\n const canView = canReadAll || (currentUserId && ownerUserId === currentUserId);\n\n if (!namespace || !apiProductName) {\n return (\n <InfoCard title=\"API Product Information\">\n <Typography>No APIProduct linked to this API entity</Typography>\n </InfoCard>\n );\n }\n\n if (loading || permLoading) {\n return (\n <InfoCard title=\"API Product Information\">\n <Progress />\n </InfoCard>\n );\n }\n\n // show permission message if user doesn't have permission\n if (apiProduct && !canView) {\n return (\n <InfoCard title=\"API Product Information\">\n <Box p={2}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n You don't have permission to view this API product's details. Only the API owner or users with admin permissions can view this information.\n </Typography>\n </Box>\n </InfoCard>\n );\n }\n\n // also show permission message if we got a permission error from the backend\n if (error && error.message.includes('you can only read your own')) {\n return (\n <InfoCard title=\"API Product Information\">\n <Box p={2}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n You don't have permission to view this API product's details. Only the API owner or users with admin permissions can view this information.\n </Typography>\n </Box>\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title=\"API Product Information\">\n <ResponseErrorPanel error={error} />\n </InfoCard>\n );\n }\n\n if (!apiProduct) {\n return (\n <InfoCard title=\"API Product Information\">\n <Typography>APIProduct not found</Typography>\n </InfoCard>\n );\n }\n\n // check for OIDC auth scheme\n const authSchemes = apiProduct.status?.discoveredAuthScheme?.authentication || {};\n const schemeObjects = Object.values(authSchemes);\n const jwtScheme = schemeObjects.find((scheme: any) => scheme.hasOwnProperty('jwt'));\n const hasOidc = Boolean(jwtScheme);\n const jwtIssuer = (jwtScheme as any)?.jwt?.issuerUrl;\n const jwtTokenEndpoint = apiProduct.status?.oidcDiscovery?.tokenEndpoint;\n\n return (\n <>\n <InfoCard title=\"API Product Details\">\n <Box mb={2}>\n <Typography variant=\"caption\" className={classes.label}>\n Product Name\n </Typography>\n <Typography variant=\"h6\">\n {apiProduct.spec?.displayName || apiProductName}\n </Typography>\n </Box>\n <ApiProductDetails\n product={apiProduct}\n showStatus={false}\n showCatalogLink={false}\n />\n </InfoCard>\n {hasOidc && jwtIssuer && (\n <Box mt={2}>\n <OidcProviderCard\n issuerUrl={jwtIssuer}\n tokenEndpoint={jwtTokenEndpoint}\n />\n </Box>\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useEntity } from '@backstage/plugin-catalog-react';
|
|
3
|
-
import { useApi
|
|
3
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
4
4
|
import { Link } from '@backstage/core-components';
|
|
5
5
|
import { Box, Typography } from '@material-ui/core';
|
|
6
6
|
import { Alert } from '@material-ui/lab';
|
|
7
7
|
import useAsync from 'react-use/lib/useAsync';
|
|
8
|
+
import { kuadrantApiRef } from '../../api.esm.js';
|
|
8
9
|
|
|
9
10
|
const ApiProductOpenApiAlert = () => {
|
|
10
11
|
const { entity } = useEntity();
|
|
11
|
-
const
|
|
12
|
-
const fetchApi = useApi(fetchApiRef);
|
|
13
|
-
const backendUrl = config.getString("backend.baseUrl");
|
|
12
|
+
const kuadrantApi = useApi(kuadrantApiRef);
|
|
14
13
|
const namespace = entity.metadata.annotations?.["kuadrant.io/namespace"];
|
|
15
14
|
const apiProductName = entity.metadata.annotations?.["kuadrant.io/apiproduct"];
|
|
16
15
|
const { value: apiProduct, loading, error } = useAsync(async () => {
|
|
17
16
|
if (!namespace || !apiProductName) {
|
|
18
17
|
return null;
|
|
19
18
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (!response.ok) {
|
|
19
|
+
try {
|
|
20
|
+
return await kuadrantApi.getApiProduct(namespace, apiProductName);
|
|
21
|
+
} catch {
|
|
24
22
|
return null;
|
|
25
23
|
}
|
|
26
|
-
|
|
27
|
-
}, [backendUrl, fetchApi, namespace, apiProductName]);
|
|
24
|
+
}, [kuadrantApi, namespace, apiProductName]);
|
|
28
25
|
if (!namespace || !apiProductName || loading || error || !apiProduct) {
|
|
29
26
|
return null;
|
|
30
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiProductOpenApiAlert.esm.js","sources":["../../../src/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.tsx"],"sourcesContent":["import React from \"react\";\nimport { useEntity } from \"@backstage/plugin-catalog-react\";\nimport { useApi
|
|
1
|
+
{"version":3,"file":"ApiProductOpenApiAlert.esm.js","sources":["../../../src/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.tsx"],"sourcesContent":["import React from \"react\";\nimport { useEntity } from \"@backstage/plugin-catalog-react\";\nimport { useApi } from \"@backstage/core-plugin-api\";\nimport { Link } from \"@backstage/core-components\";\nimport { Box, Typography } from \"@material-ui/core\";\nimport { Alert } from \"@material-ui/lab\";\nimport useAsync from \"react-use/lib/useAsync\";\nimport { kuadrantApiRef } from \"../../api\";\n\n// Displays alerts for OpenAPI spec issues.\nexport const ApiProductOpenApiAlert = () => {\n const { entity } = useEntity();\n const kuadrantApi = useApi(kuadrantApiRef);\n\n // Get APIProduct reference from entity annotations\n const namespace = entity.metadata.annotations?.[\"kuadrant.io/namespace\"];\n const apiProductName =\n entity.metadata.annotations?.[\"kuadrant.io/apiproduct\"];\n\n // Fetch the full APIProduct resource to check status conditions\n const { value: apiProduct, loading, error } = useAsync(async () => {\n if (!namespace || !apiProductName) {\n return null;\n }\n\n try {\n return await kuadrantApi.getApiProduct(namespace, apiProductName);\n } catch {\n return null;\n }\n }, [kuadrantApi, namespace, apiProductName]);\n\n // Don't render anything if data is missing or still loading\n if (!namespace || !apiProductName || loading || error || !apiProduct) {\n return null;\n }\n\n const { spec, status } = apiProduct;\n\n const openAPICondition = status?.conditions?.find(\n (c: any) => c.type === \"OpenAPISpecReady\" && c.status === \"False\",\n );\n\n if (!openAPICondition) {\n return null;\n }\n\n return (\n <Box mb={2}>\n <Alert severity=\"warning\">\n <Typography variant=\"body2\" gutterBottom>\n <strong>OpenAPI Spec Issue</strong>\n </Typography>\n <Typography variant=\"body2\" gutterBottom>\n {openAPICondition.message}\n </Typography>\n {spec.documentation?.openAPISpecURL && (\n <Typography variant=\"body2\">\n Spec URL:{\" \"}\n <Link to={spec.documentation.openAPISpecURL} target=\"_blank\">\n {spec.documentation.openAPISpecURL}\n </Link>\n </Typography>\n )}\n </Alert>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAUO,MAAM,yBAAyB,MAAM;AAC1C,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,SAAU,EAAA;AAC7B,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AAGzC,EAAA,MAAM,SAAY,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,uBAAuB,CAAA;AACvE,EAAA,MAAM,cACJ,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,wBAAwB,CAAA;AAGxD,EAAA,MAAM,EAAE,KAAO,EAAA,UAAA,EAAY,SAAS,KAAM,EAAA,GAAI,SAAS,YAAY;AACjE,IAAI,IAAA,CAAC,SAAa,IAAA,CAAC,cAAgB,EAAA;AACjC,MAAO,OAAA,IAAA;AAAA;AAGT,IAAI,IAAA;AACF,MAAA,OAAO,MAAM,WAAA,CAAY,aAAc,CAAA,SAAA,EAAW,cAAc,CAAA;AAAA,KAC1D,CAAA,MAAA;AACN,MAAO,OAAA,IAAA;AAAA;AACT,GACC,EAAA,CAAC,WAAa,EAAA,SAAA,EAAW,cAAc,CAAC,CAAA;AAG3C,EAAA,IAAI,CAAC,SAAa,IAAA,CAAC,kBAAkB,OAAW,IAAA,KAAA,IAAS,CAAC,UAAY,EAAA;AACpE,IAAO,OAAA,IAAA;AAAA;AAGT,EAAM,MAAA,EAAE,IAAM,EAAA,MAAA,EAAW,GAAA,UAAA;AAEzB,EAAM,MAAA,gBAAA,GAAmB,QAAQ,UAAY,EAAA,IAAA;AAAA,IAC3C,CAAC,CAAW,KAAA,CAAA,CAAE,IAAS,KAAA,kBAAA,IAAsB,EAAE,MAAW,KAAA;AAAA,GAC5D;AAEA,EAAA,IAAI,CAAC,gBAAkB,EAAA;AACrB,IAAO,OAAA,IAAA;AAAA;AAGT,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAA,sCACN,KAAM,EAAA,EAAA,QAAA,EAAS,SACd,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,YAAY,EAAA,IAAA,EAAA,kBACrC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAA,EAAO,oBAAkB,CAC5B,mBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,YAAY,EAAA,IAAA,EAAA,EACrC,iBAAiB,OACpB,CAAA,EACC,KAAK,aAAe,EAAA,cAAA,wCAClB,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,EAAA,WAAA,EAChB,GACV,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,EAAI,EAAA,IAAA,CAAK,aAAc,CAAA,cAAA,EAAgB,MAAO,EAAA,QAAA,EAAA,EACjD,KAAK,aAAc,CAAA,cACtB,CACF,CAEJ,CACF,CAAA;AAEJ;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useState, useMemo } from 'react';
|
|
2
|
-
import { useApi,
|
|
2
|
+
import { useApi, identityApiRef, alertApiRef } from '@backstage/core-plugin-api';
|
|
3
|
+
import { kuadrantApiRef } from '../../api.esm.js';
|
|
3
4
|
import { useAsync } from 'react-use';
|
|
4
5
|
import { Progress, ResponseErrorPanel, Table, Link } from '@backstage/core-components';
|
|
5
6
|
import { kuadrantApiKeyUpdateAllPermission, kuadrantApiKeyUpdateOwnPermission } from '../../permissions.esm.js';
|
|
@@ -9,7 +10,6 @@ import CheckCircleIcon from '@material-ui/icons/CheckCircle';
|
|
|
9
10
|
import CancelIcon from '@material-ui/icons/Cancel';
|
|
10
11
|
import { FilterPanel } from '../FilterPanel/FilterPanel.esm.js';
|
|
11
12
|
import { getApprovalQueueStatusChipStyle } from '../../utils/styles.esm.js';
|
|
12
|
-
import { handleFetchError } from '../../utils/errors.esm.js';
|
|
13
13
|
|
|
14
14
|
const useStyles = makeStyles((theme) => ({
|
|
15
15
|
container: {
|
|
@@ -249,11 +249,9 @@ const BulkAlertDialog = ({
|
|
|
249
249
|
};
|
|
250
250
|
const ApprovalQueueTable = () => {
|
|
251
251
|
const classes = useStyles();
|
|
252
|
-
const config = useApi(configApiRef);
|
|
253
|
-
const fetchApi = useApi(fetchApiRef);
|
|
254
252
|
const identityApi = useApi(identityApiRef);
|
|
255
253
|
const alertApi = useApi(alertApiRef);
|
|
256
|
-
const
|
|
254
|
+
const kuadrantApi = useApi(kuadrantApiRef);
|
|
257
255
|
const [refresh, setRefresh] = useState(0);
|
|
258
256
|
const [selectedRequests, setSelectedRequests] = useState([]);
|
|
259
257
|
const [dialogState, setDialogState] = useState({
|
|
@@ -293,23 +291,28 @@ const ApprovalQueueTable = () => {
|
|
|
293
291
|
const { value, loading, error } = useAsync(async () => {
|
|
294
292
|
const identity = await identityApi.getBackstageIdentity();
|
|
295
293
|
const reviewedBy = identity.userEntityRef;
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
294
|
+
try {
|
|
295
|
+
const [apiKeyRequests, apiProducts] = await Promise.all([
|
|
296
|
+
kuadrantApi.getAllRequests(),
|
|
297
|
+
kuadrantApi.getApiProducts()
|
|
298
|
+
]);
|
|
299
|
+
const allRequests = apiKeyRequests.items || [];
|
|
300
|
+
const ownedApiProducts = /* @__PURE__ */ new Set();
|
|
301
|
+
for (const product of apiProducts.items || []) {
|
|
302
|
+
const owner = product.metadata?.annotations?.["backstage.io/owner"];
|
|
303
|
+
if (owner === reviewedBy) {
|
|
304
|
+
ownedApiProducts.add(
|
|
305
|
+
`${product.metadata.namespace}/${product.metadata.name}`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return { allRequests, reviewedBy, ownedApiProducts };
|
|
310
|
+
} catch (err) {
|
|
311
|
+
const errorMessage = err instanceof Error ? err.message : "unknown error occurred";
|
|
309
312
|
alertApi.post({
|
|
310
|
-
message:
|
|
313
|
+
message: `Failed to get resources. ${errorMessage}`,
|
|
311
314
|
display: "transient",
|
|
312
|
-
severity: "
|
|
315
|
+
severity: "error"
|
|
313
316
|
});
|
|
314
317
|
return {
|
|
315
318
|
allRequests: [],
|
|
@@ -317,22 +320,7 @@ const ApprovalQueueTable = () => {
|
|
|
317
320
|
ownedApiProducts: /* @__PURE__ */ new Set()
|
|
318
321
|
};
|
|
319
322
|
}
|
|
320
|
-
|
|
321
|
-
const allRequests = data.items || [];
|
|
322
|
-
const ownedApiProducts = /* @__PURE__ */ new Set();
|
|
323
|
-
if (apiProductsResponse.ok) {
|
|
324
|
-
const apiProductsData = await apiProductsResponse.json();
|
|
325
|
-
for (const product of apiProductsData.items || []) {
|
|
326
|
-
const owner = product.metadata?.annotations?.["backstage.io/owner"];
|
|
327
|
-
if (owner === reviewedBy) {
|
|
328
|
-
ownedApiProducts.add(
|
|
329
|
-
`${product.metadata.namespace}/${product.metadata.name}`
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
return { allRequests, reviewedBy, ownedApiProducts };
|
|
335
|
-
}, [backendUrl, fetchApi, identityApi, refresh]);
|
|
323
|
+
}, [kuadrantApi, identityApi, refresh]);
|
|
336
324
|
const filterSections = useMemo(() => {
|
|
337
325
|
if (!value?.allRequests) return [];
|
|
338
326
|
const statusCounts = { Approved: 0, Pending: 0, Rejected: 0 };
|
|
@@ -427,17 +415,9 @@ const ApprovalQueueTable = () => {
|
|
|
427
415
|
const handleConfirm = async () => {
|
|
428
416
|
if (!dialogState.request || !value) return;
|
|
429
417
|
setDialogState((prev) => ({ ...prev, processing: true }));
|
|
430
|
-
const
|
|
418
|
+
const apikeyRequestFn = dialogState.action === "approve" ? (ns, n, r) => kuadrantApi.approveRequest(ns, n, r) : (ns, n, r) => kuadrantApi.rejectRequest(ns, n, r);
|
|
431
419
|
try {
|
|
432
|
-
|
|
433
|
-
method: "POST",
|
|
434
|
-
headers: { "Content-Type": "application/json" },
|
|
435
|
-
body: JSON.stringify({ reviewedBy: value.reviewedBy })
|
|
436
|
-
});
|
|
437
|
-
if (!response.ok) {
|
|
438
|
-
const err = await handleFetchError(response);
|
|
439
|
-
throw new Error(err);
|
|
440
|
-
}
|
|
420
|
+
await apikeyRequestFn(dialogState.request.metadata.namespace, dialogState.request.metadata.name, value.reviewedBy);
|
|
441
421
|
setDialogState({
|
|
442
422
|
open: false,
|
|
443
423
|
request: null,
|
|
@@ -490,25 +470,13 @@ const ApprovalQueueTable = () => {
|
|
|
490
470
|
setBulkDialogState((prev) => ({ ...prev, processing: true }));
|
|
491
471
|
setBulkAlertDialogState({ open: false, results: [], isApprove: true });
|
|
492
472
|
const isApprove = bulkDialogState.action === "approve";
|
|
493
|
-
const
|
|
473
|
+
const apiKeyRequestsFn = isApprove ? (req, rb) => kuadrantApi.bulkApproveRequests(req, rb) : (req, rb) => kuadrantApi.bulkRejectRequests(req, rb);
|
|
494
474
|
try {
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
namespace: r.metadata.namespace,
|
|
501
|
-
name: r.metadata.name
|
|
502
|
-
})),
|
|
503
|
-
reviewedBy: value.reviewedBy
|
|
504
|
-
})
|
|
505
|
-
});
|
|
506
|
-
if (!response.ok) {
|
|
507
|
-
const err = await handleFetchError(response);
|
|
508
|
-
throw new Error(err);
|
|
509
|
-
}
|
|
510
|
-
const bulkResponseRaw = await response.json();
|
|
511
|
-
const bulkResponse = bulkResponseRaw.results || [];
|
|
475
|
+
const requests = bulkDialogState.requests.map((r) => ({
|
|
476
|
+
namespace: r.metadata.namespace,
|
|
477
|
+
name: r.metadata.name
|
|
478
|
+
}));
|
|
479
|
+
const bulkResponse = await apiKeyRequestsFn(requests, value.reviewedBy) || [];
|
|
512
480
|
const successfulItems = bulkResponse.filter((res) => res.success);
|
|
513
481
|
const failedItems = bulkResponse.filter((res) => !res.success);
|
|
514
482
|
const totalSuccess = failedItems.length === 0;
|