@kuadrant/kuadrant-backstage-plugin-frontend 0.0.2-dev-844db4d → 0.0.2-dev-19b0e56
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/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js +67 -20
- package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js.map +1 -1
- package/dist/components/ApprovalQueueCard/ApprovalQueueCard.esm.js +50 -26
- package/dist/components/ApprovalQueueCard/ApprovalQueueCard.esm.js.map +1 -1
- package/dist/components/ConfirmDeleteDialog/ConfirmDeleteDialog.esm.js +65 -0
- package/dist/components/ConfirmDeleteDialog/ConfirmDeleteDialog.esm.js.map +1 -0
- package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js +28 -15
- package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js.map +1 -1
- package/dist/components/EditAPIKeyRequestDialog/EditAPIKeyRequestDialog.esm.js +4 -2
- package/dist/components/EditAPIKeyRequestDialog/EditAPIKeyRequestDialog.esm.js.map +1 -1
- package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js +26 -14
- package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js.map +1 -1
- package/dist/components/KuadrantPage/KuadrantPage.esm.js +21 -3
- package/dist/components/KuadrantPage/KuadrantPage.esm.js.map +1 -1
- package/dist/components/MyApiKeysCard/MyApiKeysCard.esm.js +49 -11
- package/dist/components/MyApiKeysCard/MyApiKeysCard.esm.js.map +1 -1
- package/dist-scalprum/{internal.plugin-kuadrant.58f9452dd6d088d4816c.js → internal.plugin-kuadrant.41278d0bcfa31baa5fae.js} +2 -2
- package/dist-scalprum/{internal.plugin-kuadrant.58f9452dd6d088d4816c.js.map → internal.plugin-kuadrant.41278d0bcfa31baa5fae.js.map} +1 -1
- package/dist-scalprum/plugin-manifest.json +2 -2
- package/dist-scalprum/static/4306.7eedfb3a.chunk.js +2 -0
- package/dist-scalprum/static/4306.7eedfb3a.chunk.js.map +1 -0
- package/dist-scalprum/static/6281.5f4d856e.chunk.js +2 -0
- package/dist-scalprum/static/6281.5f4d856e.chunk.js.map +1 -0
- package/dist-scalprum/static/7632.af7b3369.chunk.js +2 -0
- package/dist-scalprum/static/7632.af7b3369.chunk.js.map +1 -0
- package/dist-scalprum/static/8441.62394cfd.chunk.js +2 -0
- package/dist-scalprum/static/8441.62394cfd.chunk.js.map +1 -0
- package/dist-scalprum/static/{exposed-PluginRoot.9522bcfa.chunk.js → exposed-PluginRoot.0ac7fe4b.chunk.js} +2 -2
- package/dist-scalprum/static/{exposed-PluginRoot.9522bcfa.chunk.js.map → exposed-PluginRoot.0ac7fe4b.chunk.js.map} +1 -1
- package/package.json +1 -1
- package/dist-scalprum/static/4306.bc289e67.chunk.js +0 -2
- package/dist-scalprum/static/4306.bc289e67.chunk.js.map +0 -1
- package/dist-scalprum/static/6281.e7e36f6a.chunk.js +0 -2
- package/dist-scalprum/static/6281.e7e36f6a.chunk.js.map +0 -1
- package/dist-scalprum/static/7632.4bb9bd69.chunk.js +0 -2
- package/dist-scalprum/static/7632.4bb9bd69.chunk.js.map +0 -1
- package/dist-scalprum/static/9555.59e77806.chunk.js +0 -2
- package/dist-scalprum/static/9555.59e77806.chunk.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { Box, Typography, Grid, Button,
|
|
2
|
+
import { Box, Typography, Grid, Button, Chip, IconButton } from '@material-ui/core';
|
|
3
3
|
import AddIcon from '@material-ui/icons/Add';
|
|
4
4
|
import DeleteIcon from '@material-ui/icons/Delete';
|
|
5
5
|
import EditIcon from '@material-ui/icons/Edit';
|
|
6
6
|
import { Page, Header, SupportButton, Content, Progress, ResponseErrorPanel, InfoCard, Table, Link } from '@backstage/core-components';
|
|
7
7
|
import useAsync from 'react-use/lib/useAsync';
|
|
8
|
-
import { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';
|
|
8
|
+
import { useApi, configApiRef, fetchApiRef, alertApiRef } from '@backstage/core-plugin-api';
|
|
9
9
|
import { ApprovalQueueCard } from '../ApprovalQueueCard/ApprovalQueueCard.esm.js';
|
|
10
10
|
import { MyApiKeysCard } from '../MyApiKeysCard/MyApiKeysCard.esm.js';
|
|
11
11
|
import { PermissionGate } from '../PermissionGate/PermissionGate.esm.js';
|
|
@@ -13,10 +13,12 @@ import { CreateAPIProductDialog } from '../CreateAPIProductDialog/CreateAPIProdu
|
|
|
13
13
|
import { kuadrantApiProductListPermission, kuadrantApiProductCreatePermission, kuadrantApiKeyRequestReadAllPermission, kuadrantApiKeyRequestReadOwnPermission, kuadrantApiProductDeleteOwnPermission, kuadrantApiProductDeleteAllPermission, kuadrantApiProductUpdateOwnPermission, kuadrantApiProductUpdateAllPermission, kuadrantPlanPolicyListPermission } from '../../permissions.esm.js';
|
|
14
14
|
import { useKuadrantPermission } from '../../utils/permissions.esm.js';
|
|
15
15
|
import { EditAPIProductDialog } from '../EditAPIProductDialog/EditAPIProductDialog.esm.js';
|
|
16
|
+
import { ConfirmDeleteDialog } from '../ConfirmDeleteDialog/ConfirmDeleteDialog.esm.js';
|
|
16
17
|
|
|
17
18
|
const ResourceList = () => {
|
|
18
19
|
const config = useApi(configApiRef);
|
|
19
20
|
const fetchApi = useApi(fetchApiRef);
|
|
21
|
+
const alertApi = useApi(alertApiRef);
|
|
20
22
|
const backendUrl = config.getString("backend.baseUrl");
|
|
21
23
|
const [createDialogOpen, setCreateDialogOpen] = useState(false);
|
|
22
24
|
const [editDialogOpen, setEditDialogOpen] = useState(false);
|
|
@@ -77,6 +79,7 @@ const ResourceList = () => {
|
|
|
77
79
|
const permissionError = createPermissionError || approvalQueuePermissionError || deletePermissionError || planPolicyPermissionError;
|
|
78
80
|
const handleCreateSuccess = () => {
|
|
79
81
|
setRefreshTrigger((prev) => prev + 1);
|
|
82
|
+
alertApi.post({ message: "API Product created", severity: "success", display: "transient" });
|
|
80
83
|
};
|
|
81
84
|
const handleEditClick = (namespace, name) => {
|
|
82
85
|
setApiProductToEdit({ namespace, name });
|
|
@@ -84,6 +87,7 @@ const ResourceList = () => {
|
|
|
84
87
|
};
|
|
85
88
|
const handleEditSuccess = () => {
|
|
86
89
|
setRefreshTrigger((prev) => prev + 1);
|
|
90
|
+
alertApi.post({ message: "API Product updated", severity: "success", display: "transient" });
|
|
87
91
|
};
|
|
88
92
|
const handleDeleteClick = (namespace, name) => {
|
|
89
93
|
setApiProductToDelete({ namespace, name });
|
|
@@ -101,8 +105,10 @@ const ResourceList = () => {
|
|
|
101
105
|
throw new Error("failed to delete apiproduct");
|
|
102
106
|
}
|
|
103
107
|
setRefreshTrigger((prev) => prev + 1);
|
|
108
|
+
alertApi.post({ message: "API Product deleted", severity: "success", display: "transient" });
|
|
104
109
|
} catch (err) {
|
|
105
110
|
console.error("error deleting apiproduct:", err);
|
|
111
|
+
alertApi.post({ message: "Failed to delete API Product", severity: "error", display: "transient" });
|
|
106
112
|
} finally {
|
|
107
113
|
setDeleting(false);
|
|
108
114
|
setDeleteDialogOpen(false);
|
|
@@ -293,7 +299,19 @@ const ResourceList = () => {
|
|
|
293
299
|
namespace: apiProductToEdit?.namespace || "",
|
|
294
300
|
name: apiProductToEdit?.name || ""
|
|
295
301
|
}
|
|
296
|
-
), /* @__PURE__ */ React.createElement(
|
|
302
|
+
), /* @__PURE__ */ React.createElement(
|
|
303
|
+
ConfirmDeleteDialog,
|
|
304
|
+
{
|
|
305
|
+
open: deleteDialogOpen,
|
|
306
|
+
title: "Delete API Product",
|
|
307
|
+
description: `This will permanently delete "${apiProductToDelete?.name}" from namespace "${apiProductToDelete?.namespace}" and remove it from Kubernetes. Any associated API keys will stop working.`,
|
|
308
|
+
confirmText: apiProductToDelete?.name,
|
|
309
|
+
severity: "high",
|
|
310
|
+
deleting,
|
|
311
|
+
onConfirm: handleDeleteConfirm,
|
|
312
|
+
onCancel: handleDeleteCancel
|
|
313
|
+
}
|
|
314
|
+
)));
|
|
297
315
|
};
|
|
298
316
|
const KuadrantPage = () => {
|
|
299
317
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KuadrantPage.esm.js","sources":["../../../src/components/KuadrantPage/KuadrantPage.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { Typography, Grid, Box, Chip, Button, IconButton, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@material-ui/core';\nimport AddIcon from '@material-ui/icons/Add';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport {\n InfoCard,\n Header,\n Page,\n Content,\n SupportButton,\n Progress,\n ResponseErrorPanel,\n Link,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport useAsync from 'react-use/lib/useAsync';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { ApprovalQueueCard } from '../ApprovalQueueCard';\nimport { MyApiKeysCard } from '../MyApiKeysCard';\nimport { PermissionGate } from '../PermissionGate';\nimport { CreateAPIProductDialog } from '../CreateAPIProductDialog';\nimport {\n kuadrantApiProductCreatePermission,\n kuadrantApiProductDeleteOwnPermission,\n kuadrantApiProductDeleteAllPermission,\n kuadrantApiProductUpdateOwnPermission,\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductListPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantApiKeyRequestReadOwnPermission,\n kuadrantPlanPolicyListPermission,\n} from '../../permissions';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { EditAPIProductDialog } from '../EditAPIProductDialog';\n\ntype KuadrantResource = {\n metadata: {\n name: string;\n namespace: string;\n creationTimestamp: string;\n };\n spec?: any;\n};\n\ntype KuadrantList = {\n items: KuadrantResource[];\n};\n\nexport const ResourceList = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [createDialogOpen, setCreateDialogOpen] = useState(false);\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const [refreshTrigger, setRefreshTrigger] = useState(0);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [apiProductToDelete, setApiProductToDelete] = useState<{ namespace: string; name: string } | null>(null);\n const [apiProductToEdit, setApiProductToEdit] = useState<{ namespace: string; name: string } | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n const {\n allowed: canCreateApiProduct,\n loading: createPermissionLoading,\n error: createPermissionError,\n } = useKuadrantPermission(kuadrantApiProductCreatePermission);\n\n const {\n allowed: canViewAllRequests,\n loading: approvalQueueAllPermissionLoading,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadAllPermission);\n\n const {\n allowed: canViewOwnRequests,\n loading: approvalQueueOwnPermissionLoading,\n error: approvalQueuePermissionError,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadOwnPermission);\n\n const canViewApprovalQueue = canViewAllRequests || canViewOwnRequests;\n const approvalQueuePermissionLoading = approvalQueueAllPermissionLoading || approvalQueueOwnPermissionLoading;\n\n const {\n allowed: canDeleteOwnApiProduct,\n loading: deleteOwnPermissionLoading,\n } = useKuadrantPermission(kuadrantApiProductDeleteOwnPermission);\n\n const {\n allowed: canDeleteAllApiProducts,\n loading: deleteAllPermissionLoading,\n error: deletePermissionError,\n } = useKuadrantPermission(kuadrantApiProductDeleteAllPermission);\n\n const {\n allowed: canUpdateOwnApiProduct,\n } = useKuadrantPermission(kuadrantApiProductUpdateOwnPermission);\n\n const {\n allowed: canUpdateAllApiProducts,\n } = useKuadrantPermission(kuadrantApiProductUpdateAllPermission);\n\n const canDeleteApiProduct = canDeleteOwnApiProduct || canDeleteAllApiProducts;\n const canUpdateApiProduct = canUpdateOwnApiProduct || canUpdateAllApiProducts;\n const deletePermissionLoading = deleteOwnPermissionLoading || deleteAllPermissionLoading;\n\n const {\n allowed: canListPlanPolicies,\n loading: planPolicyPermissionLoading,\n error: planPolicyPermissionError,\n } = useKuadrantPermission(kuadrantPlanPolicyListPermission);\n\n const { value: apiProducts, loading: apiProductsLoading, error: apiProductsError } = useAsync(async (): Promise<KuadrantList> => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`);\n return await response.json();\n }, [backendUrl, fetchApi, refreshTrigger]);\n\n const { value: planPolicies, loading: planPoliciesLoading, error: planPoliciesError } = useAsync(async (): Promise<KuadrantList> => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, refreshTrigger]);\n\n const loading = apiProductsLoading || planPoliciesLoading || createPermissionLoading || approvalQueuePermissionLoading || deletePermissionLoading || planPolicyPermissionLoading;\n const error = apiProductsError || planPoliciesError;\n const permissionError = createPermissionError || approvalQueuePermissionError || deletePermissionError || planPolicyPermissionError;\n\n const handleCreateSuccess = () => {\n setRefreshTrigger(prev => prev + 1);\n };\n\n const handleEditClick = (namespace: string, name: string) => {\n setApiProductToEdit({ namespace, name });\n setEditDialogOpen(true);\n };\n\n const handleEditSuccess = () => {\n setRefreshTrigger(prev => prev + 1);\n };\n\n const handleDeleteClick = (namespace: string, name: string) => {\n setApiProductToDelete({ namespace, name });\n setDeleteDialogOpen(true);\n };\n\n const handleDeleteConfirm = async () => {\n if (!apiProductToDelete) return;\n\n setDeleting(true);\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${apiProductToDelete.namespace}/${apiProductToDelete.name}`,\n { method: 'DELETE' }\n );\n\n if (!response.ok) {\n throw new Error('failed to delete apiproduct');\n }\n\n setRefreshTrigger(prev => prev + 1);\n } catch (err) {\n console.error('error deleting apiproduct:', err);\n } finally {\n setDeleting(false);\n setDeleteDialogOpen(false);\n setApiProductToDelete(null);\n }\n };\n\n const handleDeleteCancel = () => {\n setDeleteDialogOpen(false);\n setApiProductToDelete(null);\n };\n\n const formatDate = (dateString: string) => {\n const date = new Date(dateString);\n return date.toLocaleDateString('en-GB', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n };\n\n const columns: TableColumn[] = [\n {\n title: 'Name',\n field: 'spec.displayName',\n render: (row: any) => {\n const publishStatus = row.spec?.publishStatus;\n const isPublished = publishStatus === 'Published';\n const displayName = row.spec?.displayName ?? row.metadata.name;\n\n if (isPublished) {\n return (\n <Link to={`/catalog/default/api/${row.metadata.name}/api-product`}>\n <strong>{displayName}</strong>\n </Link>\n );\n }\n\n return (\n <span className=\"text-muted\">\n <strong>{displayName}</strong>\n </span>\n );\n },\n customFilterAndSearch: (term, row: any) => {\n const displayName = row.spec?.displayName || row.metadata.name || '';\n return displayName.toLowerCase().includes(term.toLowerCase());\n },\n },\n {\n title: 'Resource Name',\n field: 'metadata.name',\n },\n {\n title: 'Version',\n field: 'spec.version',\n render: (row: any) => row.spec?.version || '-',\n },\n {\n title: 'HTTPRoute',\n field: 'spec.targetRef.name',\n render: (row: any) => row.spec?.targetRef?.name || '-',\n },\n {\n title: 'Publish Status',\n field: 'spec.publishStatus',\n render: (row: any) => {\n const status = row.spec?.publishStatus || 'Draft';\n return (\n <Chip\n label={status}\n size=\"small\"\n color={status === 'Published' ? 'primary' : 'default'}\n />\n );\n },\n },\n {\n title: 'Approval Mode',\n field: 'spec.approvalMode',\n render: (row: any) => {\n const mode = row.spec?.approvalMode || 'manual';\n return (\n <Chip\n label={mode}\n size=\"small\"\n color={mode === 'automatic' ? 'secondary' : 'default'}\n />\n );\n },\n },\n {\n title: 'Namespace',\n field: 'metadata.namespace',\n },\n {\n title: 'Created',\n field: 'metadata.creationTimestamp',\n render: (row: any) => formatDate(row.metadata.creationTimestamp),\n },\n {\n title: 'Actions',\n field: 'actions',\n filtering: false,\n render: (row: any) => (\n <Box display=\"flex\" style={{ gap: 4 }}>\n {canUpdateApiProduct && (\n <IconButton\n size=\"small\"\n onClick={() => handleEditClick(row.metadata.namespace, row.metadata.name)}\n title=\"Edit API Product\"\n >\n <EditIcon fontSize=\"small\" />\n </IconButton>\n )}\n\n {canDeleteApiProduct && (\n <IconButton\n size=\"small\"\n onClick={() => handleDeleteClick(row.metadata.namespace, row.metadata.name)}\n title=\"Delete API Product\"\n >\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n )}\n </Box>\n ),\n },\n ];\n\n const planPolicyColumns: TableColumn[] = [\n {\n title: 'Name',\n field: 'metadata.name',\n render: (row: any) => (\n <Link to={`/kuadrant/planpolicy/${row.metadata.namespace}/${row.metadata.name}`}>\n <strong>{row.metadata.name}</strong>\n </Link>\n ),\n },\n {\n title: 'Namespace',\n field: 'metadata.namespace',\n },\n ];\n\n const renderResources = (resources: KuadrantResource[] | undefined) => {\n if (!resources || resources.length === 0) {\n return <Typography variant=\"body2\" color=\"textSecondary\">No API products found</Typography>;\n }\n return (\n <Table\n options={{\n paging: resources.length > 5,\n pageSize: 20,\n search: true,\n filtering: true,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={columns}\n data={resources}\n />\n );\n };\n\n const renderPlanPolicies = (resources: KuadrantResource[] | undefined) => {\n if (!resources || resources.length === 0) {\n return <Typography variant=\"body2\" color=\"textSecondary\">No plan policies found</Typography>;\n }\n return (\n <Table\n options={{ paging: false, search: false, toolbar: false }}\n columns={planPolicyColumns}\n data={resources}\n />\n );\n };\n\n return (\n <Page themeId=\"tool\">\n <Header title=\"Kuadrant\" subtitle=\"API management for Kubernetes\">\n <SupportButton>Manage API products and access requests</SupportButton>\n </Header>\n <Content>\n {loading && <Progress />}\n {error && <ResponseErrorPanel error={error} />}\n {permissionError && (\n <Box p={2}>\n <Typography color=\"error\">\n unable to check permissions: {permissionError.message}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n permission: {createPermissionError ? 'kuadrant.apiproduct.create' :\n deletePermissionError ? 'kuadrant.apiproduct.delete' :\n approvalQueuePermissionError ? 'kuadrant.apikeyrequest.read.all' :\n planPolicyPermissionError ? 'kuadrant.planpolicy.list' : 'unknown'}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n please try again or contact your administrator\n </Typography>\n </Box>\n )}\n {!loading && !error && !permissionError && (\n <Grid container spacing={3} direction=\"column\">\n <Grid item>\n <MyApiKeysCard />\n </Grid>\n\n <Grid item>\n <InfoCard\n title=\"API Products\"\n action={\n canCreateApiProduct ? (\n <Box display=\"flex\" alignItems=\"center\" height=\"100%\" mt={1}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"small\"\n startIcon={<AddIcon />}\n onClick={() => setCreateDialogOpen(true)}\n >\n Create API Product\n </Button>\n </Box>\n ) : undefined\n }\n >\n {renderResources(apiProducts?.items)}\n </InfoCard>\n </Grid>\n\n {canListPlanPolicies && (\n <Grid item>\n <InfoCard title=\"Plan Policies\">\n {renderPlanPolicies(planPolicies?.items)}\n </InfoCard>\n </Grid>\n )}\n\n {canViewApprovalQueue && (\n <Grid item>\n <ApprovalQueueCard />\n </Grid>\n )}\n </Grid>\n )}\n <CreateAPIProductDialog\n open={createDialogOpen}\n onClose={() => setCreateDialogOpen(false)}\n onSuccess={handleCreateSuccess}\n />\n <EditAPIProductDialog\n open={editDialogOpen}\n onClose={() => setEditDialogOpen(false)}\n onSuccess={handleEditSuccess}\n namespace={apiProductToEdit?.namespace || ''}\n name={apiProductToEdit?.name || ''}\n />\n <Dialog open={deleteDialogOpen} onClose={handleDeleteCancel}>\n <DialogTitle>Delete API Product</DialogTitle>\n <DialogContent>\n <DialogContentText>\n Are you sure you want to delete {apiProductToDelete?.name} from namespace {apiProductToDelete?.namespace}?\n This will permanently remove the API Product from Kubernetes.\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleDeleteCancel} color=\"primary\">\n Cancel\n </Button>\n <Button onClick={handleDeleteConfirm} color=\"secondary\" disabled={deleting}>\n {deleting ? 'Deleting...' : 'Delete'}\n </Button>\n </DialogActions>\n </Dialog>\n </Content>\n </Page>\n );\n};\n\nexport const KuadrantPage = () => {\n return (\n <PermissionGate\n permission={kuadrantApiProductListPermission}\n errorMessage=\"you don't have permission to view the Kuadrant page\"\n >\n <ResourceList />\n </PermissionGate>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KuadrantPage.esm.js","sources":["../../../src/components/KuadrantPage/KuadrantPage.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { Typography, Grid, Box, Chip, Button, IconButton } from '@material-ui/core';\nimport AddIcon from '@material-ui/icons/Add';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport {\n InfoCard,\n Header,\n Page,\n Content,\n SupportButton,\n Progress,\n ResponseErrorPanel,\n Link,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport useAsync from 'react-use/lib/useAsync';\nimport { useApi, configApiRef, fetchApiRef, alertApiRef } from '@backstage/core-plugin-api';\nimport { ApprovalQueueCard } from '../ApprovalQueueCard';\nimport { MyApiKeysCard } from '../MyApiKeysCard';\nimport { PermissionGate } from '../PermissionGate';\nimport { CreateAPIProductDialog } from '../CreateAPIProductDialog';\nimport {\n kuadrantApiProductCreatePermission,\n kuadrantApiProductDeleteOwnPermission,\n kuadrantApiProductDeleteAllPermission,\n kuadrantApiProductUpdateOwnPermission,\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductListPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantApiKeyRequestReadOwnPermission,\n kuadrantPlanPolicyListPermission,\n} from '../../permissions';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { EditAPIProductDialog } from '../EditAPIProductDialog';\nimport { ConfirmDeleteDialog } from '../ConfirmDeleteDialog';\n\ntype KuadrantResource = {\n metadata: {\n name: string;\n namespace: string;\n creationTimestamp: string;\n };\n spec?: any;\n};\n\ntype KuadrantList = {\n items: KuadrantResource[];\n};\n\nexport const ResourceList = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const alertApi = useApi(alertApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [createDialogOpen, setCreateDialogOpen] = useState(false);\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const [refreshTrigger, setRefreshTrigger] = useState(0);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [apiProductToDelete, setApiProductToDelete] = useState<{ namespace: string; name: string } | null>(null);\n const [apiProductToEdit, setApiProductToEdit] = useState<{ namespace: string; name: string } | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n const {\n allowed: canCreateApiProduct,\n loading: createPermissionLoading,\n error: createPermissionError,\n } = useKuadrantPermission(kuadrantApiProductCreatePermission);\n\n const {\n allowed: canViewAllRequests,\n loading: approvalQueueAllPermissionLoading,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadAllPermission);\n\n const {\n allowed: canViewOwnRequests,\n loading: approvalQueueOwnPermissionLoading,\n error: approvalQueuePermissionError,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadOwnPermission);\n\n const canViewApprovalQueue = canViewAllRequests || canViewOwnRequests;\n const approvalQueuePermissionLoading = approvalQueueAllPermissionLoading || approvalQueueOwnPermissionLoading;\n\n const {\n allowed: canDeleteOwnApiProduct,\n loading: deleteOwnPermissionLoading,\n } = useKuadrantPermission(kuadrantApiProductDeleteOwnPermission);\n\n const {\n allowed: canDeleteAllApiProducts,\n loading: deleteAllPermissionLoading,\n error: deletePermissionError,\n } = useKuadrantPermission(kuadrantApiProductDeleteAllPermission);\n\n const {\n allowed: canUpdateOwnApiProduct,\n } = useKuadrantPermission(kuadrantApiProductUpdateOwnPermission);\n\n const {\n allowed: canUpdateAllApiProducts,\n } = useKuadrantPermission(kuadrantApiProductUpdateAllPermission);\n\n const canDeleteApiProduct = canDeleteOwnApiProduct || canDeleteAllApiProducts;\n const canUpdateApiProduct = canUpdateOwnApiProduct || canUpdateAllApiProducts;\n const deletePermissionLoading = deleteOwnPermissionLoading || deleteAllPermissionLoading;\n\n const {\n allowed: canListPlanPolicies,\n loading: planPolicyPermissionLoading,\n error: planPolicyPermissionError,\n } = useKuadrantPermission(kuadrantPlanPolicyListPermission);\n\n const { value: apiProducts, loading: apiProductsLoading, error: apiProductsError } = useAsync(async (): Promise<KuadrantList> => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`);\n return await response.json();\n }, [backendUrl, fetchApi, refreshTrigger]);\n\n const { value: planPolicies, loading: planPoliciesLoading, error: planPoliciesError } = useAsync(async (): Promise<KuadrantList> => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, refreshTrigger]);\n\n const loading = apiProductsLoading || planPoliciesLoading || createPermissionLoading || approvalQueuePermissionLoading || deletePermissionLoading || planPolicyPermissionLoading;\n const error = apiProductsError || planPoliciesError;\n const permissionError = createPermissionError || approvalQueuePermissionError || deletePermissionError || planPolicyPermissionError;\n\n const handleCreateSuccess = () => {\n setRefreshTrigger(prev => prev + 1);\n alertApi.post({ message: 'API Product created', severity: 'success', display: 'transient' });\n };\n\n const handleEditClick = (namespace: string, name: string) => {\n setApiProductToEdit({ namespace, name });\n setEditDialogOpen(true);\n };\n\n const handleEditSuccess = () => {\n setRefreshTrigger(prev => prev + 1);\n alertApi.post({ message: 'API Product updated', severity: 'success', display: 'transient' });\n };\n\n const handleDeleteClick = (namespace: string, name: string) => {\n setApiProductToDelete({ namespace, name });\n setDeleteDialogOpen(true);\n };\n\n const handleDeleteConfirm = async () => {\n if (!apiProductToDelete) return;\n\n setDeleting(true);\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${apiProductToDelete.namespace}/${apiProductToDelete.name}`,\n { method: 'DELETE' }\n );\n\n if (!response.ok) {\n throw new Error('failed to delete apiproduct');\n }\n\n setRefreshTrigger(prev => prev + 1);\n alertApi.post({ message: 'API Product deleted', severity: 'success', display: 'transient' });\n } catch (err) {\n console.error('error deleting apiproduct:', err);\n alertApi.post({ message: 'Failed to delete API Product', severity: 'error', display: 'transient' });\n } finally {\n setDeleting(false);\n setDeleteDialogOpen(false);\n setApiProductToDelete(null);\n }\n };\n\n const handleDeleteCancel = () => {\n setDeleteDialogOpen(false);\n setApiProductToDelete(null);\n };\n\n const formatDate = (dateString: string) => {\n const date = new Date(dateString);\n return date.toLocaleDateString('en-GB', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n };\n\n const columns: TableColumn[] = [\n {\n title: 'Name',\n field: 'spec.displayName',\n render: (row: any) => {\n const publishStatus = row.spec?.publishStatus;\n const isPublished = publishStatus === 'Published';\n const displayName = row.spec?.displayName ?? row.metadata.name;\n\n if (isPublished) {\n return (\n <Link to={`/catalog/default/api/${row.metadata.name}/api-product`}>\n <strong>{displayName}</strong>\n </Link>\n );\n }\n\n return (\n <span className=\"text-muted\">\n <strong>{displayName}</strong>\n </span>\n );\n },\n customFilterAndSearch: (term, row: any) => {\n const displayName = row.spec?.displayName || row.metadata.name || '';\n return displayName.toLowerCase().includes(term.toLowerCase());\n },\n },\n {\n title: 'Resource Name',\n field: 'metadata.name',\n },\n {\n title: 'Version',\n field: 'spec.version',\n render: (row: any) => row.spec?.version || '-',\n },\n {\n title: 'HTTPRoute',\n field: 'spec.targetRef.name',\n render: (row: any) => row.spec?.targetRef?.name || '-',\n },\n {\n title: 'Publish Status',\n field: 'spec.publishStatus',\n render: (row: any) => {\n const status = row.spec?.publishStatus || 'Draft';\n return (\n <Chip\n label={status}\n size=\"small\"\n color={status === 'Published' ? 'primary' : 'default'}\n />\n );\n },\n },\n {\n title: 'Approval Mode',\n field: 'spec.approvalMode',\n render: (row: any) => {\n const mode = row.spec?.approvalMode || 'manual';\n return (\n <Chip\n label={mode}\n size=\"small\"\n color={mode === 'automatic' ? 'secondary' : 'default'}\n />\n );\n },\n },\n {\n title: 'Namespace',\n field: 'metadata.namespace',\n },\n {\n title: 'Created',\n field: 'metadata.creationTimestamp',\n render: (row: any) => formatDate(row.metadata.creationTimestamp),\n },\n {\n title: 'Actions',\n field: 'actions',\n filtering: false,\n render: (row: any) => (\n <Box display=\"flex\" style={{ gap: 4 }}>\n {canUpdateApiProduct && (\n <IconButton\n size=\"small\"\n onClick={() => handleEditClick(row.metadata.namespace, row.metadata.name)}\n title=\"Edit API Product\"\n >\n <EditIcon fontSize=\"small\" />\n </IconButton>\n )}\n\n {canDeleteApiProduct && (\n <IconButton\n size=\"small\"\n onClick={() => handleDeleteClick(row.metadata.namespace, row.metadata.name)}\n title=\"Delete API Product\"\n >\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n )}\n </Box>\n ),\n },\n ];\n\n const planPolicyColumns: TableColumn[] = [\n {\n title: 'Name',\n field: 'metadata.name',\n render: (row: any) => (\n <Link to={`/kuadrant/planpolicy/${row.metadata.namespace}/${row.metadata.name}`}>\n <strong>{row.metadata.name}</strong>\n </Link>\n ),\n },\n {\n title: 'Namespace',\n field: 'metadata.namespace',\n },\n ];\n\n const renderResources = (resources: KuadrantResource[] | undefined) => {\n if (!resources || resources.length === 0) {\n return <Typography variant=\"body2\" color=\"textSecondary\">No API products found</Typography>;\n }\n return (\n <Table\n options={{\n paging: resources.length > 5,\n pageSize: 20,\n search: true,\n filtering: true,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={columns}\n data={resources}\n />\n );\n };\n\n const renderPlanPolicies = (resources: KuadrantResource[] | undefined) => {\n if (!resources || resources.length === 0) {\n return <Typography variant=\"body2\" color=\"textSecondary\">No plan policies found</Typography>;\n }\n return (\n <Table\n options={{ paging: false, search: false, toolbar: false }}\n columns={planPolicyColumns}\n data={resources}\n />\n );\n };\n\n return (\n <Page themeId=\"tool\">\n <Header title=\"Kuadrant\" subtitle=\"API management for Kubernetes\">\n <SupportButton>Manage API products and access requests</SupportButton>\n </Header>\n <Content>\n {loading && <Progress />}\n {error && <ResponseErrorPanel error={error} />}\n {permissionError && (\n <Box p={2}>\n <Typography color=\"error\">\n unable to check permissions: {permissionError.message}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n permission: {createPermissionError ? 'kuadrant.apiproduct.create' :\n deletePermissionError ? 'kuadrant.apiproduct.delete' :\n approvalQueuePermissionError ? 'kuadrant.apikeyrequest.read.all' :\n planPolicyPermissionError ? 'kuadrant.planpolicy.list' : 'unknown'}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n please try again or contact your administrator\n </Typography>\n </Box>\n )}\n {!loading && !error && !permissionError && (\n <Grid container spacing={3} direction=\"column\">\n <Grid item>\n <MyApiKeysCard />\n </Grid>\n\n <Grid item>\n <InfoCard\n title=\"API Products\"\n action={\n canCreateApiProduct ? (\n <Box display=\"flex\" alignItems=\"center\" height=\"100%\" mt={1}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"small\"\n startIcon={<AddIcon />}\n onClick={() => setCreateDialogOpen(true)}\n >\n Create API Product\n </Button>\n </Box>\n ) : undefined\n }\n >\n {renderResources(apiProducts?.items)}\n </InfoCard>\n </Grid>\n\n {canListPlanPolicies && (\n <Grid item>\n <InfoCard title=\"Plan Policies\">\n {renderPlanPolicies(planPolicies?.items)}\n </InfoCard>\n </Grid>\n )}\n\n {canViewApprovalQueue && (\n <Grid item>\n <ApprovalQueueCard />\n </Grid>\n )}\n </Grid>\n )}\n <CreateAPIProductDialog\n open={createDialogOpen}\n onClose={() => setCreateDialogOpen(false)}\n onSuccess={handleCreateSuccess}\n />\n <EditAPIProductDialog\n open={editDialogOpen}\n onClose={() => setEditDialogOpen(false)}\n onSuccess={handleEditSuccess}\n namespace={apiProductToEdit?.namespace || ''}\n name={apiProductToEdit?.name || ''}\n />\n <ConfirmDeleteDialog\n open={deleteDialogOpen}\n title=\"Delete API Product\"\n description={`This will permanently delete \"${apiProductToDelete?.name}\" from namespace \"${apiProductToDelete?.namespace}\" and remove it from Kubernetes. Any associated API keys will stop working.`}\n confirmText={apiProductToDelete?.name}\n severity=\"high\"\n deleting={deleting}\n onConfirm={handleDeleteConfirm}\n onCancel={handleDeleteCancel}\n />\n </Content>\n </Page>\n );\n};\n\nexport const KuadrantPage = () => {\n return (\n <PermissionGate\n permission={kuadrantApiProductListPermission}\n errorMessage=\"you don't have permission to view the Kuadrant page\"\n >\n <ResourceList />\n </PermissionGate>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { InfoCard, Table, Link } from '@backstage/core-components';
|
|
3
|
-
import { useApi, configApiRef, fetchApiRef, identityApiRef } from '@backstage/core-plugin-api';
|
|
2
|
+
import { InfoCard, Progress, Table, Link } from '@backstage/core-components';
|
|
3
|
+
import { useApi, configApiRef, fetchApiRef, identityApiRef, alertApiRef } from '@backstage/core-plugin-api';
|
|
4
4
|
import useAsync from 'react-use/lib/useAsync';
|
|
5
|
-
import { Typography, Box, Tabs, Tab, Menu, MenuItem, Chip, Tooltip, IconButton } from '@material-ui/core';
|
|
5
|
+
import { Typography, Box, Tabs, Tab, Menu, MenuItem, Chip, Tooltip, IconButton, CircularProgress } from '@material-ui/core';
|
|
6
6
|
import VisibilityIcon from '@material-ui/icons/Visibility';
|
|
7
7
|
import VisibilityOffIcon from '@material-ui/icons/VisibilityOff';
|
|
8
8
|
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
|
9
9
|
import { EditAPIKeyRequestDialog } from '../EditAPIKeyRequestDialog/EditAPIKeyRequestDialog.esm.js';
|
|
10
|
+
import { ConfirmDeleteDialog } from '../ConfirmDeleteDialog/ConfirmDeleteDialog.esm.js';
|
|
10
11
|
|
|
11
12
|
const MyApiKeysCard = () => {
|
|
12
13
|
const config = useApi(configApiRef);
|
|
13
14
|
const fetchApi = useApi(fetchApiRef);
|
|
14
15
|
const identityApi = useApi(identityApiRef);
|
|
16
|
+
const alertApi = useApi(alertApiRef);
|
|
15
17
|
const backendUrl = config.getString("backend.baseUrl");
|
|
16
18
|
const [selectedTab, setSelectedTab] = useState(0);
|
|
17
19
|
const [, setUserId] = useState("");
|
|
@@ -24,12 +26,15 @@ const MyApiKeysCard = () => {
|
|
|
24
26
|
plans: []
|
|
25
27
|
});
|
|
26
28
|
const [refresh, setRefresh] = useState(0);
|
|
29
|
+
const [deleting, setDeleting] = useState(null);
|
|
30
|
+
const [deleteDialogState, setDeleteDialogState] = useState({ open: false, request: null });
|
|
27
31
|
useAsync(async () => {
|
|
28
32
|
const identity = await identityApi.getBackstageIdentity();
|
|
29
33
|
const extractedUserId = identity.userEntityRef.split("/")[1] || "guest";
|
|
30
34
|
console.log(`MyApiKeysCard: setting userId from userEntityRef: ${identity.userEntityRef} -> "${extractedUserId}"`);
|
|
31
35
|
setUserId(extractedUserId);
|
|
32
36
|
}, [identityApi]);
|
|
37
|
+
const [optimisticallyDeleted, setOptimisticallyDeleted] = useState(/* @__PURE__ */ new Set());
|
|
33
38
|
const { value: requests, loading, error } = useAsync(async () => {
|
|
34
39
|
const response = await fetchApi.fetch(
|
|
35
40
|
`${backendUrl}/api/kuadrant/requests/my`
|
|
@@ -41,12 +46,14 @@ const MyApiKeysCard = () => {
|
|
|
41
46
|
return data.items || [];
|
|
42
47
|
}, [backendUrl, fetchApi, refresh]);
|
|
43
48
|
if (loading) {
|
|
44
|
-
return /* @__PURE__ */ React.createElement(InfoCard, { title: "My API Keys" }, /* @__PURE__ */ React.createElement(
|
|
49
|
+
return /* @__PURE__ */ React.createElement(InfoCard, { title: "My API Keys" }, /* @__PURE__ */ React.createElement(Progress, null));
|
|
45
50
|
}
|
|
46
51
|
if (error) {
|
|
47
52
|
return /* @__PURE__ */ React.createElement(InfoCard, { title: "My API Keys" }, /* @__PURE__ */ React.createElement(Typography, { color: "error" }, "Error loading API keys: ", error.message));
|
|
48
53
|
}
|
|
49
|
-
const allRequests = requests || []
|
|
54
|
+
const allRequests = (requests || []).filter(
|
|
55
|
+
(r) => !optimisticallyDeleted.has(r.metadata.name)
|
|
56
|
+
);
|
|
50
57
|
const approvedRequests = allRequests.filter((r) => r.status?.phase === "Approved");
|
|
51
58
|
const pendingRequests = allRequests.filter((r) => !r.status?.phase || r.status.phase === "Pending");
|
|
52
59
|
const rejectedRequests = allRequests.filter((r) => r.status?.phase === "Rejected");
|
|
@@ -86,13 +93,18 @@ const MyApiKeysCard = () => {
|
|
|
86
93
|
setEditDialogState({ open: true, request, plans: [] });
|
|
87
94
|
}
|
|
88
95
|
};
|
|
89
|
-
const
|
|
96
|
+
const handleDeleteClick = () => {
|
|
90
97
|
if (!menuRequest) return;
|
|
91
98
|
const request = menuRequest;
|
|
92
99
|
handleMenuClose();
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
setDeleteDialogState({ open: true, request });
|
|
101
|
+
};
|
|
102
|
+
const handleDeleteConfirm = async () => {
|
|
103
|
+
if (!deleteDialogState.request) return;
|
|
104
|
+
const request = deleteDialogState.request;
|
|
105
|
+
const requestName = request.metadata.name;
|
|
106
|
+
setOptimisticallyDeleted((prev) => new Set(prev).add(requestName));
|
|
107
|
+
setDeleting(requestName);
|
|
96
108
|
try {
|
|
97
109
|
const response = await fetchApi.fetch(
|
|
98
110
|
`${backendUrl}/api/kuadrant/requests/${request.metadata.namespace}/${request.metadata.name}`,
|
|
@@ -102,11 +114,23 @@ const MyApiKeysCard = () => {
|
|
|
102
114
|
throw new Error("Failed to delete request");
|
|
103
115
|
}
|
|
104
116
|
setRefresh((r) => r + 1);
|
|
117
|
+
alertApi.post({ message: "Request deleted", severity: "success", display: "transient" });
|
|
118
|
+
setDeleteDialogState({ open: false, request: null });
|
|
105
119
|
} catch (err) {
|
|
106
120
|
console.error("Error deleting request:", err);
|
|
107
|
-
|
|
121
|
+
setOptimisticallyDeleted((prev) => {
|
|
122
|
+
const next = new Set(prev);
|
|
123
|
+
next.delete(requestName);
|
|
124
|
+
return next;
|
|
125
|
+
});
|
|
126
|
+
alertApi.post({ message: "Failed to delete request", severity: "error", display: "transient" });
|
|
127
|
+
} finally {
|
|
128
|
+
setDeleting(null);
|
|
108
129
|
}
|
|
109
130
|
};
|
|
131
|
+
const handleDeleteCancel = () => {
|
|
132
|
+
setDeleteDialogState({ open: false, request: null });
|
|
133
|
+
};
|
|
110
134
|
const columns = [
|
|
111
135
|
{
|
|
112
136
|
title: "API Product",
|
|
@@ -221,6 +245,10 @@ const MyApiKeysCard = () => {
|
|
|
221
245
|
title: "",
|
|
222
246
|
filtering: false,
|
|
223
247
|
render: (row) => {
|
|
248
|
+
const isDeleting = deleting === row.metadata.name;
|
|
249
|
+
if (isDeleting) {
|
|
250
|
+
return /* @__PURE__ */ React.createElement(CircularProgress, { size: 20 });
|
|
251
|
+
}
|
|
224
252
|
return /* @__PURE__ */ React.createElement(
|
|
225
253
|
IconButton,
|
|
226
254
|
{
|
|
@@ -319,7 +347,7 @@ const MyApiKeysCard = () => {
|
|
|
319
347
|
if (isPending(menuRequest)) {
|
|
320
348
|
items.push(/* @__PURE__ */ React.createElement(MenuItem, { key: "edit", onClick: handleEdit }, "Edit"));
|
|
321
349
|
}
|
|
322
|
-
items.push(/* @__PURE__ */ React.createElement(MenuItem, { key: "delete", onClick:
|
|
350
|
+
items.push(/* @__PURE__ */ React.createElement(MenuItem, { key: "delete", onClick: handleDeleteClick }, "Delete"));
|
|
323
351
|
return items;
|
|
324
352
|
})()
|
|
325
353
|
), editDialogState.request && /* @__PURE__ */ React.createElement(
|
|
@@ -334,6 +362,16 @@ const MyApiKeysCard = () => {
|
|
|
334
362
|
setRefresh((r) => r + 1);
|
|
335
363
|
}
|
|
336
364
|
}
|
|
365
|
+
), /* @__PURE__ */ React.createElement(
|
|
366
|
+
ConfirmDeleteDialog,
|
|
367
|
+
{
|
|
368
|
+
open: deleteDialogState.open,
|
|
369
|
+
title: "Delete API Key Request",
|
|
370
|
+
description: `Are you sure you want to delete the API key request for ${deleteDialogState.request?.spec.apiName || "this API"}?`,
|
|
371
|
+
deleting: deleting !== null,
|
|
372
|
+
onConfirm: handleDeleteConfirm,
|
|
373
|
+
onCancel: handleDeleteCancel
|
|
374
|
+
}
|
|
337
375
|
));
|
|
338
376
|
};
|
|
339
377
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MyApiKeysCard.esm.js","sources":["../../../src/components/MyApiKeysCard/MyApiKeysCard.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { InfoCard, Table, TableColumn, Link } from '@backstage/core-components';\nimport { useApi, configApiRef, fetchApiRef, identityApiRef } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\nimport { Box, Chip, Typography, Tabs, Tab, IconButton, Tooltip, Menu, MenuItem } from '@material-ui/core';\nimport VisibilityIcon from '@material-ui/icons/Visibility';\nimport VisibilityOffIcon from '@material-ui/icons/VisibilityOff';\nimport MoreVertIcon from '@material-ui/icons/MoreVert';\nimport { EditAPIKeyRequestDialog } from '../EditAPIKeyRequestDialog';\nimport { APIKeyRequest } from '../../types/api-management';\n\nexport const MyApiKeysCard = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const identityApi = useApi(identityApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [selectedTab, setSelectedTab] = useState(0);\n const [, setUserId] = useState<string>('');\n const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());\n const [menuAnchor, setMenuAnchor] = useState<{ top: number; left: number } | null>(null);\n const [menuRequest, setMenuRequest] = useState<APIKeyRequest | null>(null);\n const [editDialogState, setEditDialogState] = useState<{ open: boolean; request: APIKeyRequest | null; plans: any[] }>({\n open: false,\n request: null,\n plans: [],\n });\n const [refresh, setRefresh] = useState(0);\n\n useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n const extractedUserId = identity.userEntityRef.split('/')[1] || 'guest';\n console.log(`MyApiKeysCard: setting userId from userEntityRef: ${identity.userEntityRef} -> \"${extractedUserId}\"`);\n setUserId(extractedUserId);\n }, [identityApi]);\n\n const { value: requests, loading, error } = useAsync(async () => {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/my`\n );\n if (!response.ok) {\n throw new Error('failed to fetch requests');\n }\n const data = await response.json();\n return data.items || [];\n }, [backendUrl, fetchApi, refresh]);\n\n if (loading) {\n return (\n <InfoCard title=\"My API Keys\">\n <Typography>Loading...</Typography>\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title=\"My API Keys\">\n <Typography color=\"error\">Error loading API keys: {error.message}</Typography>\n </InfoCard>\n );\n }\n\n const allRequests = requests || [];\n const approvedRequests = allRequests.filter((r: APIKeyRequest) => r.status?.phase === 'Approved');\n const pendingRequests = allRequests.filter((r: APIKeyRequest) => !r.status?.phase || r.status.phase === 'Pending');\n const rejectedRequests = allRequests.filter((r: APIKeyRequest) => r.status?.phase === 'Rejected');\n\n const toggleKeyVisibility = (keyName: string) => {\n setVisibleKeys(prev => {\n const newSet = new Set(prev);\n if (newSet.has(keyName)) {\n newSet.delete(keyName);\n } else {\n newSet.add(keyName);\n }\n return newSet;\n });\n };\n\n const handleMenuClose = () => {\n setMenuAnchor(null);\n setMenuRequest(null);\n };\n\n const handleEdit = async () => {\n if (!menuRequest) return;\n\n const request = menuRequest;\n handleMenuClose();\n\n // Fetch available plans for this API\n try {\n const apiProductResponse = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${request.spec.apiNamespace}/${request.spec.apiName}`\n );\n\n if (apiProductResponse.ok) {\n const apiProduct = await apiProductResponse.json();\n const plans = apiProduct.spec?.plans || [];\n setEditDialogState({ open: true, request, plans });\n } else {\n console.error('Failed to fetch API product');\n setEditDialogState({ open: true, request, plans: [] });\n }\n } catch (err) {\n console.error('Error fetching plans:', err);\n setEditDialogState({ open: true, request, plans: [] });\n }\n };\n\n const handleDelete = async () => {\n if (!menuRequest) return;\n\n const request = menuRequest;\n handleMenuClose();\n\n if (!window.confirm('Are you sure you want to delete this request?')) {\n return;\n }\n\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/${request.metadata.namespace}/${request.metadata.name}`,\n { method: 'DELETE' }\n );\n\n if (!response.ok) {\n throw new Error('Failed to delete request');\n }\n\n setRefresh(r => r + 1);\n } catch (err) {\n console.error('Error deleting request:', err);\n alert('Failed to delete request');\n }\n };\n\n const columns: TableColumn<APIKeyRequest>[] = [\n {\n title: 'API Product',\n field: 'spec.apiName',\n render: (row: APIKeyRequest) => (\n <Link to={`/catalog/default/api/${row.spec.apiName}/api-keys`}>\n <strong>{row.spec.apiName}</strong>\n </Link>\n ),\n },\n {\n title: 'Plan',\n field: 'spec.planTier',\n render: (row: APIKeyRequest) => {\n const color = row.spec.planTier === 'gold' ? 'primary' :\n row.spec.planTier === 'silver' ? 'default' : 'secondary';\n return <Chip label={row.spec.planTier} color={color} size=\"small\" />;\n },\n },\n {\n title: 'Use Case',\n field: 'spec.useCase',\n render: (row: APIKeyRequest) => {\n if (!row.spec.useCase) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n return (\n <Tooltip title={row.spec.useCase} placement=\"top\">\n <Typography\n variant=\"body2\"\n style={{\n maxWidth: '200px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {row.spec.useCase}\n </Typography>\n </Tooltip>\n );\n },\n },\n {\n title: 'Status',\n field: 'status.phase',\n render: (row: APIKeyRequest) => {\n const phase = row.status?.phase || 'Pending';\n const color = phase === 'Approved' ? 'primary' :\n phase === 'Rejected' ? 'secondary' : 'default';\n return <Chip label={phase} color={color} size=\"small\" />;\n },\n },\n {\n title: 'Reason',\n field: 'status.reason',\n render: (row: APIKeyRequest) => {\n if (row.status?.reason) {\n const color = row.status.phase === 'Rejected' ? 'error' : 'textPrimary';\n return (\n <Tooltip title={row.status.reason} placement=\"top\">\n <Typography\n variant=\"body2\"\n color={color}\n style={{\n maxWidth: '200px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {row.status.reason}\n </Typography>\n </Tooltip>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Reviewed By',\n field: 'status.reviewedBy',\n render: (row: APIKeyRequest) => {\n if ((row.status?.phase === 'Approved' || row.status?.phase === 'Rejected') && row.status.reviewedBy) {\n const reviewedDate = row.status.reviewedAt ? new Date(row.status.reviewedAt).toLocaleDateString() : '';\n return (\n <Box>\n <Typography variant=\"body2\">{row.status.reviewedBy}</Typography>\n {reviewedDate && (\n <Typography variant=\"caption\" color=\"textSecondary\">\n {reviewedDate}\n </Typography>\n )}\n </Box>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'API Key',\n field: 'status.apiKey',\n filtering: false,\n render: (row: APIKeyRequest) => {\n if (row.status?.phase === 'Approved' && row.status.apiKey) {\n const isVisible = visibleKeys.has(row.metadata.name);\n return (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <Box fontFamily=\"monospace\" fontSize=\"0.875rem\">\n {isVisible ? row.status.apiKey : '•'.repeat(20) + '...'}\n </Box>\n <Tooltip title={isVisible ? 'hide key' : 'show key'}>\n <IconButton\n size=\"small\"\n onClick={() => toggleKeyVisibility(row.metadata.name)}\n >\n {isVisible ? <VisibilityOffIcon fontSize=\"small\" /> : <VisibilityIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </Box>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Requested',\n field: 'metadata.creationTimestamp',\n render: (row: APIKeyRequest) => {\n if (!row.metadata.creationTimestamp) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n const date = new Date(row.metadata.creationTimestamp);\n return <Typography variant=\"body2\">{date.toLocaleDateString()}</Typography>;\n },\n },\n {\n title: '',\n filtering: false,\n render: (row: APIKeyRequest) => {\n return (\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n setMenuAnchor({ top: rect.bottom, left: rect.left });\n setMenuRequest(row);\n }}\n aria-controls={menuAnchor ? 'myapikeys-menu' : undefined}\n aria-haspopup=\"true\"\n >\n <MoreVertIcon />\n </IconButton>\n );\n },\n },\n ];\n\n const getTabData = () => {\n switch (selectedTab) {\n case 0:\n return approvedRequests;\n case 1:\n return pendingRequests;\n case 2:\n return rejectedRequests;\n default:\n return allRequests;\n }\n };\n\n const getTabColumns = () => {\n switch (selectedTab) {\n case 0: // Active - no Reason\n return columns.filter(col => col.title !== 'Reason');\n case 1: // Pending - no Reason, Reviewed By, API Key\n return columns.filter(col =>\n col.title !== 'Reason' &&\n col.title !== 'Reviewed By' &&\n col.title !== 'API Key'\n );\n case 2: // Rejected - no API Key\n return columns.filter(col => col.title !== 'API Key');\n default:\n return columns;\n }\n };\n\n const tabData = getTabData();\n const tabColumns = getTabColumns();\n const isPending = (row: APIKeyRequest) => !row.status || row.status.phase === 'Pending';\n\n return (\n <>\n <InfoCard\n title=\"My API Keys\"\n subheader={`${approvedRequests.length} active, ${pendingRequests.length} pending`}\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={`Active (${approvedRequests.length})`} />\n <Tab label={`Pending (${pendingRequests.length})`} />\n <Tab label={`Rejected (${rejectedRequests.length})`} />\n </Tabs>\n </Box>\n {tabData.length === 0 ? (\n <Box p={3} textAlign=\"center\">\n <Typography variant=\"body1\" color=\"textSecondary\">\n {selectedTab === 0 && 'No active API keys. Request access to an API to get started.'}\n {selectedTab === 1 && 'No pending requests.'}\n {selectedTab === 2 && 'No rejected requests.'}\n </Typography>\n </Box>\n ) : (\n <Table\n options={{\n paging: tabData.length > 5,\n pageSize: 20,\n search: true,\n filtering: true,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={tabColumns}\n data={tabData.map((item: APIKeyRequest) => ({\n ...item,\n id: item.metadata.name,\n }))}\n />\n )}\n </InfoCard>\n\n <Menu\n id=\"myapikeys-menu\"\n open={Boolean(menuAnchor)}\n onClose={handleMenuClose}\n anchorReference=\"anchorPosition\"\n anchorPosition={menuAnchor || { top: 0, left: 0 }}\n >\n {menuRequest && (() => {\n const items = [];\n if (isPending(menuRequest)) {\n items.push(<MenuItem key=\"edit\" onClick={handleEdit}>Edit</MenuItem>);\n }\n items.push(<MenuItem key=\"delete\" onClick={handleDelete}>Delete</MenuItem>);\n return items;\n })()}\n </Menu>\n\n {editDialogState.request && (\n <EditAPIKeyRequestDialog\n open={editDialogState.open}\n request={editDialogState.request}\n availablePlans={editDialogState.plans}\n onClose={() => setEditDialogState({ open: false, request: null, plans: [] })}\n onSuccess={() => {\n setEditDialogState({ open: false, request: null, plans: [] });\n setRefresh(r => r + 1);\n }}\n />\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MyApiKeysCard.esm.js","sources":["../../../src/components/MyApiKeysCard/MyApiKeysCard.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { InfoCard, Table, TableColumn, Link, Progress } from '@backstage/core-components';\nimport { useApi, configApiRef, fetchApiRef, identityApiRef, alertApiRef } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\nimport { Box, Chip, Typography, Tabs, Tab, IconButton, Tooltip, Menu, MenuItem, CircularProgress } from '@material-ui/core';\nimport VisibilityIcon from '@material-ui/icons/Visibility';\nimport VisibilityOffIcon from '@material-ui/icons/VisibilityOff';\nimport MoreVertIcon from '@material-ui/icons/MoreVert';\nimport { EditAPIKeyRequestDialog } from '../EditAPIKeyRequestDialog';\nimport { ConfirmDeleteDialog } from '../ConfirmDeleteDialog';\nimport { APIKeyRequest } from '../../types/api-management';\n\nexport const MyApiKeysCard = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const identityApi = useApi(identityApiRef);\n const alertApi = useApi(alertApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [selectedTab, setSelectedTab] = useState(0);\n const [, setUserId] = useState<string>('');\n const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());\n const [menuAnchor, setMenuAnchor] = useState<{ top: number; left: number } | null>(null);\n const [menuRequest, setMenuRequest] = useState<APIKeyRequest | null>(null);\n const [editDialogState, setEditDialogState] = useState<{ open: boolean; request: APIKeyRequest | null; plans: any[] }>({\n open: false,\n request: null,\n plans: [],\n });\n const [refresh, setRefresh] = useState(0);\n const [deleting, setDeleting] = useState<string | null>(null);\n const [deleteDialogState, setDeleteDialogState] = useState<{\n open: boolean;\n request: APIKeyRequest | null;\n }>({ open: false, request: null });\n\n useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n const extractedUserId = identity.userEntityRef.split('/')[1] || 'guest';\n console.log(`MyApiKeysCard: setting userId from userEntityRef: ${identity.userEntityRef} -> \"${extractedUserId}\"`);\n setUserId(extractedUserId);\n }, [identityApi]);\n\n const [optimisticallyDeleted, setOptimisticallyDeleted] = useState<Set<string>>(new Set());\n\n const { value: requests, loading, error } = useAsync(async () => {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/my`\n );\n if (!response.ok) {\n throw new Error('failed to fetch requests');\n }\n const data = await response.json();\n return data.items || [];\n }, [backendUrl, fetchApi, refresh]);\n\n if (loading) {\n return (\n <InfoCard title=\"My API Keys\">\n <Progress />\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title=\"My API Keys\">\n <Typography color=\"error\">Error loading API keys: {error.message}</Typography>\n </InfoCard>\n );\n }\n\n const allRequests = (requests || []).filter(\n (r: APIKeyRequest) => !optimisticallyDeleted.has(r.metadata.name)\n );\n const approvedRequests = allRequests.filter((r: APIKeyRequest) => r.status?.phase === 'Approved');\n const pendingRequests = allRequests.filter((r: APIKeyRequest) => !r.status?.phase || r.status.phase === 'Pending');\n const rejectedRequests = allRequests.filter((r: APIKeyRequest) => r.status?.phase === 'Rejected');\n\n const toggleKeyVisibility = (keyName: string) => {\n setVisibleKeys(prev => {\n const newSet = new Set(prev);\n if (newSet.has(keyName)) {\n newSet.delete(keyName);\n } else {\n newSet.add(keyName);\n }\n return newSet;\n });\n };\n\n const handleMenuClose = () => {\n setMenuAnchor(null);\n setMenuRequest(null);\n };\n\n const handleEdit = async () => {\n if (!menuRequest) return;\n\n const request = menuRequest;\n handleMenuClose();\n\n // Fetch available plans for this API\n try {\n const apiProductResponse = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${request.spec.apiNamespace}/${request.spec.apiName}`\n );\n\n if (apiProductResponse.ok) {\n const apiProduct = await apiProductResponse.json();\n const plans = apiProduct.spec?.plans || [];\n setEditDialogState({ open: true, request, plans });\n } else {\n console.error('Failed to fetch API product');\n setEditDialogState({ open: true, request, plans: [] });\n }\n } catch (err) {\n console.error('Error fetching plans:', err);\n setEditDialogState({ open: true, request, plans: [] });\n }\n };\n\n const handleDeleteClick = () => {\n if (!menuRequest) return;\n const request = menuRequest;\n handleMenuClose();\n setDeleteDialogState({ open: true, request });\n };\n\n const handleDeleteConfirm = async () => {\n if (!deleteDialogState.request) return;\n\n const request = deleteDialogState.request;\n const requestName = request.metadata.name;\n\n // optimistic update - remove from UI immediately\n setOptimisticallyDeleted(prev => new Set(prev).add(requestName));\n setDeleting(requestName);\n\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/${request.metadata.namespace}/${request.metadata.name}`,\n { method: 'DELETE' }\n );\n\n if (!response.ok) {\n throw new Error('Failed to delete request');\n }\n\n setRefresh(r => r + 1);\n alertApi.post({ message: 'Request deleted', severity: 'success', display: 'transient' });\n setDeleteDialogState({ open: false, request: null });\n } catch (err) {\n console.error('Error deleting request:', err);\n // rollback optimistic update on error\n setOptimisticallyDeleted(prev => {\n const next = new Set(prev);\n next.delete(requestName);\n return next;\n });\n alertApi.post({ message: 'Failed to delete request', severity: 'error', display: 'transient' });\n } finally {\n setDeleting(null);\n }\n };\n\n const handleDeleteCancel = () => {\n setDeleteDialogState({ open: false, request: null });\n };\n\n const columns: TableColumn<APIKeyRequest>[] = [\n {\n title: 'API Product',\n field: 'spec.apiName',\n render: (row: APIKeyRequest) => (\n <Link to={`/catalog/default/api/${row.spec.apiName}/api-keys`}>\n <strong>{row.spec.apiName}</strong>\n </Link>\n ),\n },\n {\n title: 'Plan',\n field: 'spec.planTier',\n render: (row: APIKeyRequest) => {\n const color = row.spec.planTier === 'gold' ? 'primary' :\n row.spec.planTier === 'silver' ? 'default' : 'secondary';\n return <Chip label={row.spec.planTier} color={color} size=\"small\" />;\n },\n },\n {\n title: 'Use Case',\n field: 'spec.useCase',\n render: (row: APIKeyRequest) => {\n if (!row.spec.useCase) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n return (\n <Tooltip title={row.spec.useCase} placement=\"top\">\n <Typography\n variant=\"body2\"\n style={{\n maxWidth: '200px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {row.spec.useCase}\n </Typography>\n </Tooltip>\n );\n },\n },\n {\n title: 'Status',\n field: 'status.phase',\n render: (row: APIKeyRequest) => {\n const phase = row.status?.phase || 'Pending';\n const color = phase === 'Approved' ? 'primary' :\n phase === 'Rejected' ? 'secondary' : 'default';\n return <Chip label={phase} color={color} size=\"small\" />;\n },\n },\n {\n title: 'Reason',\n field: 'status.reason',\n render: (row: APIKeyRequest) => {\n if (row.status?.reason) {\n const color = row.status.phase === 'Rejected' ? 'error' : 'textPrimary';\n return (\n <Tooltip title={row.status.reason} placement=\"top\">\n <Typography\n variant=\"body2\"\n color={color}\n style={{\n maxWidth: '200px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {row.status.reason}\n </Typography>\n </Tooltip>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Reviewed By',\n field: 'status.reviewedBy',\n render: (row: APIKeyRequest) => {\n if ((row.status?.phase === 'Approved' || row.status?.phase === 'Rejected') && row.status.reviewedBy) {\n const reviewedDate = row.status.reviewedAt ? new Date(row.status.reviewedAt).toLocaleDateString() : '';\n return (\n <Box>\n <Typography variant=\"body2\">{row.status.reviewedBy}</Typography>\n {reviewedDate && (\n <Typography variant=\"caption\" color=\"textSecondary\">\n {reviewedDate}\n </Typography>\n )}\n </Box>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'API Key',\n field: 'status.apiKey',\n filtering: false,\n render: (row: APIKeyRequest) => {\n if (row.status?.phase === 'Approved' && row.status.apiKey) {\n const isVisible = visibleKeys.has(row.metadata.name);\n return (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <Box fontFamily=\"monospace\" fontSize=\"0.875rem\">\n {isVisible ? row.status.apiKey : '•'.repeat(20) + '...'}\n </Box>\n <Tooltip title={isVisible ? 'hide key' : 'show key'}>\n <IconButton\n size=\"small\"\n onClick={() => toggleKeyVisibility(row.metadata.name)}\n >\n {isVisible ? <VisibilityOffIcon fontSize=\"small\" /> : <VisibilityIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </Box>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Requested',\n field: 'metadata.creationTimestamp',\n render: (row: APIKeyRequest) => {\n if (!row.metadata.creationTimestamp) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n const date = new Date(row.metadata.creationTimestamp);\n return <Typography variant=\"body2\">{date.toLocaleDateString()}</Typography>;\n },\n },\n {\n title: '',\n filtering: false,\n render: (row: APIKeyRequest) => {\n const isDeleting = deleting === row.metadata.name;\n if (isDeleting) {\n return <CircularProgress size={20} />;\n }\n return (\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n setMenuAnchor({ top: rect.bottom, left: rect.left });\n setMenuRequest(row);\n }}\n aria-controls={menuAnchor ? 'myapikeys-menu' : undefined}\n aria-haspopup=\"true\"\n >\n <MoreVertIcon />\n </IconButton>\n );\n },\n },\n ];\n\n const getTabData = () => {\n switch (selectedTab) {\n case 0:\n return approvedRequests;\n case 1:\n return pendingRequests;\n case 2:\n return rejectedRequests;\n default:\n return allRequests;\n }\n };\n\n const getTabColumns = () => {\n switch (selectedTab) {\n case 0: // Active - no Reason\n return columns.filter(col => col.title !== 'Reason');\n case 1: // Pending - no Reason, Reviewed By, API Key\n return columns.filter(col =>\n col.title !== 'Reason' &&\n col.title !== 'Reviewed By' &&\n col.title !== 'API Key'\n );\n case 2: // Rejected - no API Key\n return columns.filter(col => col.title !== 'API Key');\n default:\n return columns;\n }\n };\n\n const tabData = getTabData();\n const tabColumns = getTabColumns();\n const isPending = (row: APIKeyRequest) => !row.status || row.status.phase === 'Pending';\n\n return (\n <>\n <InfoCard\n title=\"My API Keys\"\n subheader={`${approvedRequests.length} active, ${pendingRequests.length} pending`}\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={`Active (${approvedRequests.length})`} />\n <Tab label={`Pending (${pendingRequests.length})`} />\n <Tab label={`Rejected (${rejectedRequests.length})`} />\n </Tabs>\n </Box>\n {tabData.length === 0 ? (\n <Box p={3} textAlign=\"center\">\n <Typography variant=\"body1\" color=\"textSecondary\">\n {selectedTab === 0 && 'No active API keys. Request access to an API to get started.'}\n {selectedTab === 1 && 'No pending requests.'}\n {selectedTab === 2 && 'No rejected requests.'}\n </Typography>\n </Box>\n ) : (\n <Table\n options={{\n paging: tabData.length > 5,\n pageSize: 20,\n search: true,\n filtering: true,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={tabColumns}\n data={tabData.map((item: APIKeyRequest) => ({\n ...item,\n id: item.metadata.name,\n }))}\n />\n )}\n </InfoCard>\n\n <Menu\n id=\"myapikeys-menu\"\n open={Boolean(menuAnchor)}\n onClose={handleMenuClose}\n anchorReference=\"anchorPosition\"\n anchorPosition={menuAnchor || { top: 0, left: 0 }}\n >\n {menuRequest && (() => {\n const items = [];\n if (isPending(menuRequest)) {\n items.push(<MenuItem key=\"edit\" onClick={handleEdit}>Edit</MenuItem>);\n }\n items.push(<MenuItem key=\"delete\" onClick={handleDeleteClick}>Delete</MenuItem>);\n return items;\n })()}\n </Menu>\n\n {editDialogState.request && (\n <EditAPIKeyRequestDialog\n open={editDialogState.open}\n request={editDialogState.request}\n availablePlans={editDialogState.plans}\n onClose={() => setEditDialogState({ open: false, request: null, plans: [] })}\n onSuccess={() => {\n setEditDialogState({ open: false, request: null, plans: [] });\n setRefresh(r => r + 1);\n }}\n />\n )}\n\n <ConfirmDeleteDialog\n open={deleteDialogState.open}\n title=\"Delete API Key Request\"\n description={`Are you sure you want to delete the API key request for ${deleteDialogState.request?.spec.apiName || 'this API'}?`}\n deleting={deleting !== null}\n onConfirm={handleDeleteConfirm}\n onCancel={handleDeleteCancel}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|