@kuadrant/kuadrant-backstage-plugin-frontend 0.0.2-dev-752cfa1 → 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.
Files changed (38) hide show
  1. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js +108 -26
  2. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js.map +1 -1
  3. package/dist/components/ApprovalQueueCard/ApprovalQueueCard.esm.js +58 -29
  4. package/dist/components/ApprovalQueueCard/ApprovalQueueCard.esm.js.map +1 -1
  5. package/dist/components/ConfirmDeleteDialog/ConfirmDeleteDialog.esm.js +65 -0
  6. package/dist/components/ConfirmDeleteDialog/ConfirmDeleteDialog.esm.js.map +1 -0
  7. package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js +28 -15
  8. package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js.map +1 -1
  9. package/dist/components/EditAPIKeyRequestDialog/EditAPIKeyRequestDialog.esm.js +4 -2
  10. package/dist/components/EditAPIKeyRequestDialog/EditAPIKeyRequestDialog.esm.js.map +1 -1
  11. package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js +26 -14
  12. package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js.map +1 -1
  13. package/dist/components/KuadrantPage/KuadrantPage.esm.js +36 -5
  14. package/dist/components/KuadrantPage/KuadrantPage.esm.js.map +1 -1
  15. package/dist/components/MyApiKeysCard/MyApiKeysCard.esm.js +61 -15
  16. package/dist/components/MyApiKeysCard/MyApiKeysCard.esm.js.map +1 -1
  17. package/dist-scalprum/{internal.plugin-kuadrant.95464756fb5320a8f8b8.js → internal.plugin-kuadrant.41278d0bcfa31baa5fae.js} +2 -2
  18. package/dist-scalprum/{internal.plugin-kuadrant.95464756fb5320a8f8b8.js.map → internal.plugin-kuadrant.41278d0bcfa31baa5fae.js.map} +1 -1
  19. package/dist-scalprum/plugin-manifest.json +2 -2
  20. package/dist-scalprum/static/4306.7eedfb3a.chunk.js +2 -0
  21. package/dist-scalprum/static/4306.7eedfb3a.chunk.js.map +1 -0
  22. package/dist-scalprum/static/6281.5f4d856e.chunk.js +2 -0
  23. package/dist-scalprum/static/6281.5f4d856e.chunk.js.map +1 -0
  24. package/dist-scalprum/static/7632.af7b3369.chunk.js +2 -0
  25. package/dist-scalprum/static/7632.af7b3369.chunk.js.map +1 -0
  26. package/dist-scalprum/static/8441.62394cfd.chunk.js +2 -0
  27. package/dist-scalprum/static/8441.62394cfd.chunk.js.map +1 -0
  28. package/dist-scalprum/static/{exposed-PluginRoot.9522bcfa.chunk.js → exposed-PluginRoot.0ac7fe4b.chunk.js} +2 -2
  29. package/dist-scalprum/static/{exposed-PluginRoot.9522bcfa.chunk.js.map → exposed-PluginRoot.0ac7fe4b.chunk.js.map} +1 -1
  30. package/package.json +1 -1
  31. package/dist-scalprum/static/4306.04dfa125.chunk.js +0 -2
  32. package/dist-scalprum/static/4306.04dfa125.chunk.js.map +0 -1
  33. package/dist-scalprum/static/6281.14f57b13.chunk.js +0 -2
  34. package/dist-scalprum/static/6281.14f57b13.chunk.js.map +0 -1
  35. package/dist-scalprum/static/7632.4c95ea50.chunk.js +0 -2
  36. package/dist-scalprum/static/7632.4c95ea50.chunk.js.map +0 -1
  37. package/dist-scalprum/static/9555.59e77806.chunk.js +0 -2
  38. 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, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Chip, IconButton } from '@material-ui/core';
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);
@@ -124,7 +130,7 @@ const ResourceList = () => {
124
130
  const columns = [
125
131
  {
126
132
  title: "Name",
127
- field: "name",
133
+ field: "spec.displayName",
128
134
  render: (row) => {
129
135
  const publishStatus = row.spec?.publishStatus;
130
136
  const isPublished = publishStatus === "Published";
@@ -133,6 +139,10 @@ const ResourceList = () => {
133
139
  return /* @__PURE__ */ React.createElement(Link, { to: `/catalog/default/api/${row.metadata.name}/api-product` }, /* @__PURE__ */ React.createElement("strong", null, displayName));
134
140
  }
135
141
  return /* @__PURE__ */ React.createElement("span", { className: "text-muted" }, /* @__PURE__ */ React.createElement("strong", null, displayName));
142
+ },
143
+ customFilterAndSearch: (term, row) => {
144
+ const displayName = row.spec?.displayName || row.metadata.name || "";
145
+ return displayName.toLowerCase().includes(term.toLowerCase());
136
146
  }
137
147
  },
138
148
  {
@@ -191,6 +201,7 @@ const ResourceList = () => {
191
201
  {
192
202
  title: "Actions",
193
203
  field: "actions",
204
+ filtering: false,
194
205
  render: (row) => /* @__PURE__ */ React.createElement(Box, { display: "flex", style: { gap: 4 } }, canUpdateApiProduct && /* @__PURE__ */ React.createElement(
195
206
  IconButton,
196
207
  {
@@ -228,7 +239,15 @@ const ResourceList = () => {
228
239
  return /* @__PURE__ */ React.createElement(
229
240
  Table,
230
241
  {
231
- options: { paging: false, search: false, toolbar: false },
242
+ options: {
243
+ paging: resources.length > 5,
244
+ pageSize: 20,
245
+ search: true,
246
+ filtering: true,
247
+ debounceInterval: 300,
248
+ toolbar: true,
249
+ emptyRowsWhenPaging: false
250
+ },
232
251
  columns,
233
252
  data: resources
234
253
  }
@@ -280,7 +299,19 @@ const ResourceList = () => {
280
299
  namespace: apiProductToEdit?.namespace || "",
281
300
  name: apiProductToEdit?.name || ""
282
301
  }
283
- ), /* @__PURE__ */ React.createElement(Dialog, { open: deleteDialogOpen, onClose: handleDeleteCancel }, /* @__PURE__ */ React.createElement(DialogTitle, null, "Delete API Product"), /* @__PURE__ */ React.createElement(DialogContent, null, /* @__PURE__ */ React.createElement(DialogContentText, null, "Are you sure you want to delete ", apiProductToDelete?.name, " from namespace ", apiProductToDelete?.namespace, "? This will permanently remove the API Product from Kubernetes.")), /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(Button, { onClick: handleDeleteCancel, color: "primary" }, "Cancel"), /* @__PURE__ */ React.createElement(Button, { onClick: handleDeleteConfirm, color: "secondary", disabled: deleting }, deleting ? "Deleting..." : "Delete")))));
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
+ )));
284
315
  };
285
316
  const KuadrantPage = () => {
286
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: 'name',\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 },\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 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={{ paging: false, search: false, toolbar: false }}\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(Typography, null, "Loading..."));
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 handleDelete = async () => {
96
+ const handleDeleteClick = () => {
90
97
  if (!menuRequest) return;
91
98
  const request = menuRequest;
92
99
  handleMenuClose();
93
- if (!window.confirm("Are you sure you want to delete this request?")) {
94
- return;
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
- alert("Failed to delete request");
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",
@@ -154,6 +178,7 @@ const MyApiKeysCard = () => {
154
178
  },
155
179
  {
156
180
  title: "Reason",
181
+ field: "status.reason",
157
182
  render: (row) => {
158
183
  if (row.status?.reason) {
159
184
  const color = row.status.phase === "Rejected" ? "error" : "textPrimary";
@@ -177,6 +202,7 @@ const MyApiKeysCard = () => {
177
202
  },
178
203
  {
179
204
  title: "Reviewed By",
205
+ field: "status.reviewedBy",
180
206
  render: (row) => {
181
207
  if ((row.status?.phase === "Approved" || row.status?.phase === "Rejected") && row.status.reviewedBy) {
182
208
  const reviewedDate = row.status.reviewedAt ? new Date(row.status.reviewedAt).toLocaleDateString() : "";
@@ -187,6 +213,8 @@ const MyApiKeysCard = () => {
187
213
  },
188
214
  {
189
215
  title: "API Key",
216
+ field: "status.apiKey",
217
+ filtering: false,
190
218
  render: (row) => {
191
219
  if (row.status?.phase === "Approved" && row.status.apiKey) {
192
220
  const isVisible = visibleKeys.has(row.metadata.name);
@@ -215,7 +243,12 @@ const MyApiKeysCard = () => {
215
243
  },
216
244
  {
217
245
  title: "",
246
+ filtering: false,
218
247
  render: (row) => {
248
+ const isDeleting = deleting === row.metadata.name;
249
+ if (isDeleting) {
250
+ return /* @__PURE__ */ React.createElement(CircularProgress, { size: 20 });
251
+ }
219
252
  return /* @__PURE__ */ React.createElement(
220
253
  IconButton,
221
254
  {
@@ -285,10 +318,13 @@ const MyApiKeysCard = () => {
285
318
  Table,
286
319
  {
287
320
  options: {
288
- paging: tabData.length > 10,
289
- pageSize: 10,
290
- search: false,
291
- toolbar: false
321
+ paging: tabData.length > 5,
322
+ pageSize: 20,
323
+ search: true,
324
+ filtering: true,
325
+ debounceInterval: 300,
326
+ toolbar: true,
327
+ emptyRowsWhenPaging: false
292
328
  },
293
329
  columns: tabColumns,
294
330
  data: tabData.map((item) => ({
@@ -311,7 +347,7 @@ const MyApiKeysCard = () => {
311
347
  if (isPending(menuRequest)) {
312
348
  items.push(/* @__PURE__ */ React.createElement(MenuItem, { key: "edit", onClick: handleEdit }, "Edit"));
313
349
  }
314
- items.push(/* @__PURE__ */ React.createElement(MenuItem, { key: "delete", onClick: handleDelete }, "Delete"));
350
+ items.push(/* @__PURE__ */ React.createElement(MenuItem, { key: "delete", onClick: handleDeleteClick }, "Delete"));
315
351
  return items;
316
352
  })()
317
353
  ), editDialogState.request && /* @__PURE__ */ React.createElement(
@@ -326,6 +362,16 @@ const MyApiKeysCard = () => {
326
362
  setRefresh((r) => r + 1);
327
363
  }
328
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
+ }
329
375
  ));
330
376
  };
331
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 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 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 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 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 > 10,\n pageSize: 10,\n search: false,\n toolbar: 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":";;;;;;;;;;AAWO,MAAM,gBAAgB,MAAM;AACjC,EAAM,MAAA,MAAA,GAAS,OAAO,YAAY,CAAA;AAClC,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AACzC,EAAM,MAAA,UAAA,GAAa,MAAO,CAAA,SAAA,CAAU,iBAAiB,CAAA;AACrD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,CAAC,CAAA;AAChD,EAAA,MAAM,GAAG,SAAS,CAAA,GAAI,SAAiB,EAAE,CAAA;AACzC,EAAA,MAAM,CAAC,WAAa,EAAA,cAAc,IAAI,QAAsB,iBAAA,IAAI,KAAK,CAAA;AACrE,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAA+C,IAAI,CAAA;AACvF,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAA+B,IAAI,CAAA;AACzE,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,QAAyE,CAAA;AAAA,IACrH,IAAM,EAAA,KAAA;AAAA,IACN,OAAS,EAAA,IAAA;AAAA,IACT,OAAO;AAAC,GACT,CAAA;AACD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,CAAC,CAAA;AAExC,EAAA,QAAA,CAAS,YAAY;AACnB,IAAM,MAAA,QAAA,GAAW,MAAM,WAAA,CAAY,oBAAqB,EAAA;AACxD,IAAA,MAAM,kBAAkB,QAAS,CAAA,aAAA,CAAc,MAAM,GAAG,CAAA,CAAE,CAAC,CAAK,IAAA,OAAA;AAChE,IAAA,OAAA,CAAQ,IAAI,CAAqD,kDAAA,EAAA,QAAA,CAAS,aAAa,CAAA,KAAA,EAAQ,eAAe,CAAG,CAAA,CAAA,CAAA;AACjH,IAAA,SAAA,CAAU,eAAe,CAAA;AAAA,GAC3B,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,MAAM,EAAE,KAAO,EAAA,QAAA,EAAU,SAAS,KAAM,EAAA,GAAI,SAAS,YAAY;AAC/D,IAAM,MAAA,QAAA,GAAW,MAAM,QAAS,CAAA,KAAA;AAAA,MAC9B,GAAG,UAAU,CAAA,yBAAA;AAAA,KACf;AACA,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,IAAI,MAAM,0BAA0B,CAAA;AAAA;AAE5C,IAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AACjC,IAAO,OAAA,IAAA,CAAK,SAAS,EAAC;AAAA,GACrB,EAAA,CAAC,UAAY,EAAA,QAAA,EAAU,OAAO,CAAC,CAAA;AAElC,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2CACG,QAAS,EAAA,EAAA,KAAA,EAAM,iCACb,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,IAAA,EAAW,YAAU,CACxB,CAAA;AAAA;AAIJ,EAAA,IAAI,KAAO,EAAA;AACT,IACE,uBAAA,KAAA,CAAA,aAAA,CAAC,QAAS,EAAA,EAAA,KAAA,EAAM,aACd,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,KAAA,EAAM,OAAQ,EAAA,EAAA,0BAAA,EAAyB,KAAM,CAAA,OAAQ,CACnE,CAAA;AAAA;AAIJ,EAAM,MAAA,WAAA,GAAc,YAAY,EAAC;AACjC,EAAM,MAAA,gBAAA,GAAmB,YAAY,MAAO,CAAA,CAAC,MAAqB,CAAE,CAAA,MAAA,EAAQ,UAAU,UAAU,CAAA;AAChG,EAAA,MAAM,eAAkB,GAAA,WAAA,CAAY,MAAO,CAAA,CAAC,CAAqB,KAAA,CAAC,CAAE,CAAA,MAAA,EAAQ,KAAS,IAAA,CAAA,CAAE,MAAO,CAAA,KAAA,KAAU,SAAS,CAAA;AACjH,EAAM,MAAA,gBAAA,GAAmB,YAAY,MAAO,CAAA,CAAC,MAAqB,CAAE,CAAA,MAAA,EAAQ,UAAU,UAAU,CAAA;AAEhG,EAAM,MAAA,mBAAA,GAAsB,CAAC,OAAoB,KAAA;AAC/C,IAAA,cAAA,CAAe,CAAQ,IAAA,KAAA;AACrB,MAAM,MAAA,MAAA,GAAS,IAAI,GAAA,CAAI,IAAI,CAAA;AAC3B,MAAI,IAAA,MAAA,CAAO,GAAI,CAAA,OAAO,CAAG,EAAA;AACvB,QAAA,MAAA,CAAO,OAAO,OAAO,CAAA;AAAA,OAChB,MAAA;AACL,QAAA,MAAA,CAAO,IAAI,OAAO,CAAA;AAAA;AAEpB,MAAO,OAAA,MAAA;AAAA,KACR,CAAA;AAAA,GACH;AAEA,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,cAAA,CAAe,IAAI,CAAA;AAAA,GACrB;AAEA,EAAA,MAAM,aAAa,YAAY;AAC7B,IAAA,IAAI,CAAC,WAAa,EAAA;AAElB,IAAA,MAAM,OAAU,GAAA,WAAA;AAChB,IAAgB,eAAA,EAAA;AAGhB,IAAI,IAAA;AACF,MAAM,MAAA,kBAAA,GAAqB,MAAM,QAAS,CAAA,KAAA;AAAA,QACxC,CAAA,EAAG,UAAU,CAA6B,0BAAA,EAAA,OAAA,CAAQ,KAAK,YAAY,CAAA,CAAA,EAAI,OAAQ,CAAA,IAAA,CAAK,OAAO,CAAA;AAAA,OAC7F;AAEA,MAAA,IAAI,mBAAmB,EAAI,EAAA;AACzB,QAAM,MAAA,UAAA,GAAa,MAAM,kBAAA,CAAmB,IAAK,EAAA;AACjD,QAAA,MAAM,KAAQ,GAAA,UAAA,CAAW,IAAM,EAAA,KAAA,IAAS,EAAC;AACzC,QAAA,kBAAA,CAAmB,EAAE,IAAA,EAAM,IAAM,EAAA,OAAA,EAAS,OAAO,CAAA;AAAA,OAC5C,MAAA;AACL,QAAA,OAAA,CAAQ,MAAM,6BAA6B,CAAA;AAC3C,QAAA,kBAAA,CAAmB,EAAE,IAAM,EAAA,IAAA,EAAM,SAAS,KAAO,EAAA,IAAI,CAAA;AAAA;AACvD,aACO,GAAK,EAAA;AACZ,MAAQ,OAAA,CAAA,KAAA,CAAM,yBAAyB,GAAG,CAAA;AAC1C,MAAA,kBAAA,CAAmB,EAAE,IAAM,EAAA,IAAA,EAAM,SAAS,KAAO,EAAA,IAAI,CAAA;AAAA;AACvD,GACF;AAEA,EAAA,MAAM,eAAe,YAAY;AAC/B,IAAA,IAAI,CAAC,WAAa,EAAA;AAElB,IAAA,MAAM,OAAU,GAAA,WAAA;AAChB,IAAgB,eAAA,EAAA;AAEhB,IAAA,IAAI,CAAC,MAAA,CAAO,OAAQ,CAAA,+CAA+C,CAAG,EAAA;AACpE,MAAA;AAAA;AAGF,IAAI,IAAA;AACF,MAAM,MAAA,QAAA,GAAW,MAAM,QAAS,CAAA,KAAA;AAAA,QAC9B,CAAA,EAAG,UAAU,CAA0B,uBAAA,EAAA,OAAA,CAAQ,SAAS,SAAS,CAAA,CAAA,EAAI,OAAQ,CAAA,QAAA,CAAS,IAAI,CAAA,CAAA;AAAA,QAC1F,EAAE,QAAQ,QAAS;AAAA,OACrB;AAEA,MAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,QAAM,MAAA,IAAI,MAAM,0BAA0B,CAAA;AAAA;AAG5C,MAAW,UAAA,CAAA,CAAA,CAAA,KAAK,IAAI,CAAC,CAAA;AAAA,aACd,GAAK,EAAA;AACZ,MAAQ,OAAA,CAAA,KAAA,CAAM,2BAA2B,GAAG,CAAA;AAC5C,MAAA,KAAA,CAAM,0BAA0B,CAAA;AAAA;AAClC,GACF;AAEA,EAAA,MAAM,OAAwC,GAAA;AAAA,IAC5C;AAAA,MACE,KAAO,EAAA,aAAA;AAAA,MACP,KAAO,EAAA,cAAA;AAAA,MACP,QAAQ,CAAC,GAAA,qBACN,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,CAAwB,qBAAA,EAAA,GAAA,CAAI,IAAK,CAAA,OAAO,+BAC/C,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAA,EAAQ,GAAI,CAAA,IAAA,CAAK,OAAQ,CAC5B;AAAA,KAEJ;AAAA,IACA;AAAA,MACE,KAAO,EAAA,MAAA;AAAA,MACP,KAAO,EAAA,eAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QAAM,MAAA,KAAA,GAAQ,GAAI,CAAA,IAAA,CAAK,QAAa,KAAA,MAAA,GAAS,YAChC,GAAI,CAAA,IAAA,CAAK,QAAa,KAAA,QAAA,GAAW,SAAY,GAAA,WAAA;AAC1D,QAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,KAAO,EAAA,GAAA,CAAI,KAAK,QAAU,EAAA,KAAA,EAAc,MAAK,OAAQ,EAAA,CAAA;AAAA;AACpE,KACF;AAAA,IACA;AAAA,MACE,KAAO,EAAA,UAAA;AAAA,MACP,KAAO,EAAA,cAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QAAI,IAAA,CAAC,GAAI,CAAA,IAAA,CAAK,OAAS,EAAA;AACrB,UAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAA,EAAQ,GAAC,CAAA;AAAA;AAEtC,QAAA,2CACG,OAAQ,EAAA,EAAA,KAAA,EAAO,IAAI,IAAK,CAAA,OAAA,EAAS,WAAU,KAC1C,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,OAAQ,EAAA,OAAA;AAAA,YACR,KAAO,EAAA;AAAA,cACL,QAAU,EAAA,OAAA;AAAA,cACV,QAAU,EAAA,QAAA;AAAA,cACV,YAAc,EAAA,UAAA;AAAA,cACd,UAAY,EAAA;AAAA;AACd,WAAA;AAAA,UAEC,IAAI,IAAK,CAAA;AAAA,SAEd,CAAA;AAAA;AAEJ,KACF;AAAA,IACA;AAAA,MACE,KAAO,EAAA,QAAA;AAAA,MACP,KAAO,EAAA,cAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QAAM,MAAA,KAAA,GAAQ,GAAI,CAAA,MAAA,EAAQ,KAAS,IAAA,SAAA;AACnC,QAAA,MAAM,QAAQ,KAAU,KAAA,UAAA,GAAa,SACxB,GAAA,KAAA,KAAU,aAAa,WAAc,GAAA,SAAA;AAClD,QAAA,2CAAQ,IAAK,EAAA,EAAA,KAAA,EAAO,KAAO,EAAA,KAAA,EAAc,MAAK,OAAQ,EAAA,CAAA;AAAA;AACxD,KACF;AAAA,IACA;AAAA,MACE,KAAO,EAAA,QAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QAAI,IAAA,GAAA,CAAI,QAAQ,MAAQ,EAAA;AACtB,UAAA,MAAM,KAAQ,GAAA,GAAA,CAAI,MAAO,CAAA,KAAA,KAAU,aAAa,OAAU,GAAA,aAAA;AAC1D,UAAA,2CACG,OAAQ,EAAA,EAAA,KAAA,EAAO,IAAI,MAAO,CAAA,MAAA,EAAQ,WAAU,KAC3C,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,OAAQ,EAAA,OAAA;AAAA,cACR,KAAA;AAAA,cACA,KAAO,EAAA;AAAA,gBACL,QAAU,EAAA,OAAA;AAAA,gBACV,QAAU,EAAA,QAAA;AAAA,gBACV,YAAc,EAAA,UAAA;AAAA,gBACd,UAAY,EAAA;AAAA;AACd,aAAA;AAAA,YAEC,IAAI,MAAO,CAAA;AAAA,WAEhB,CAAA;AAAA;AAGJ,QAAA,2CAAQ,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,KAAA,EAAM,mBAAgB,GAAC,CAAA;AAAA;AAC5D,KACF;AAAA,IACA;AAAA,MACE,KAAO,EAAA,aAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QAAK,IAAA,CAAA,GAAA,CAAI,MAAQ,EAAA,KAAA,KAAU,UAAc,IAAA,GAAA,CAAI,QAAQ,KAAU,KAAA,UAAA,KAAe,GAAI,CAAA,MAAA,CAAO,UAAY,EAAA;AACnG,UAAM,MAAA,YAAA,GAAe,GAAI,CAAA,MAAA,CAAO,UAAa,GAAA,IAAI,IAAK,CAAA,GAAA,CAAI,MAAO,CAAA,UAAU,CAAE,CAAA,kBAAA,EAAuB,GAAA,EAAA;AACpG,UAAA,2CACG,GACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,OAAQ,EAAA,OAAA,EAAA,EAAS,IAAI,MAAO,CAAA,UAAW,CAClD,EAAA,YAAA,wCACE,UAAW,EAAA,EAAA,OAAA,EAAQ,WAAU,KAAM,EAAA,eAAA,EAAA,EACjC,YACH,CAEJ,CAAA;AAAA;AAGJ,QAAA,2CAAQ,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,KAAA,EAAM,mBAAgB,GAAC,CAAA;AAAA;AAC5D,KACF;AAAA,IACA;AAAA,MACE,KAAO,EAAA,SAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QAAA,IAAI,IAAI,MAAQ,EAAA,KAAA,KAAU,UAAc,IAAA,GAAA,CAAI,OAAO,MAAQ,EAAA;AACzD,UAAA,MAAM,SAAY,GAAA,WAAA,CAAY,GAAI,CAAA,GAAA,CAAI,SAAS,IAAI,CAAA;AACnD,UAAA,uBACG,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,OAAQ,EAAA,MAAA,EAAO,YAAW,QAAS,EAAA,KAAA,EAAO,EAAE,GAAA,EAAK,CAAE,EAAA,EAAA,kBACrD,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,YAAW,WAAY,EAAA,QAAA,EAAS,UAClC,EAAA,EAAA,SAAA,GAAY,GAAI,CAAA,MAAA,CAAO,MAAS,GAAA,QAAA,CAAI,OAAO,EAAE,CAAA,GAAI,KACpD,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,KAAO,EAAA,SAAA,GAAY,aAAa,UACvC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,IAAK,EAAA,OAAA;AAAA,cACL,OAAS,EAAA,MAAM,mBAAoB,CAAA,GAAA,CAAI,SAAS,IAAI;AAAA,aAAA;AAAA,YAEnD,SAAA,uCAAa,iBAAkB,EAAA,EAAA,QAAA,EAAS,SAAQ,CAAK,mBAAA,KAAA,CAAA,aAAA,CAAC,cAAe,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA;AAAA,WAE3F,CACF,CAAA;AAAA;AAGJ,QAAA,2CAAQ,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,KAAA,EAAM,mBAAgB,GAAC,CAAA;AAAA;AAC5D,KACF;AAAA,IACA;AAAA,MACE,KAAO,EAAA,WAAA;AAAA,MACP,KAAO,EAAA,4BAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QAAI,IAAA,CAAC,GAAI,CAAA,QAAA,CAAS,iBAAmB,EAAA;AACnC,UAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAA,EAAQ,GAAC,CAAA;AAAA;AAEtC,QAAA,MAAM,IAAO,GAAA,IAAI,IAAK,CAAA,GAAA,CAAI,SAAS,iBAAiB,CAAA;AACpD,QAAA,2CAAQ,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAS,EAAA,EAAA,IAAA,CAAK,oBAAqB,CAAA;AAAA;AAChE,KACF;AAAA,IACA;AAAA,MACE,KAAO,EAAA,EAAA;AAAA,MACP,MAAA,EAAQ,CAAC,GAAuB,KAAA;AAC9B,QACE,uBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,IAAK,EAAA,OAAA;AAAA,YACL,OAAA,EAAS,CAAC,CAAM,KAAA;AACd,cAAA,CAAA,CAAE,eAAgB,EAAA;AAClB,cAAM,MAAA,IAAA,GAAO,CAAE,CAAA,aAAA,CAAc,qBAAsB,EAAA;AACnD,cAAA,aAAA,CAAc,EAAE,GAAK,EAAA,IAAA,CAAK,QAAQ,IAAM,EAAA,IAAA,CAAK,MAAM,CAAA;AACnD,cAAA,cAAA,CAAe,GAAG,CAAA;AAAA,aACpB;AAAA,YACA,eAAA,EAAe,aAAa,gBAAmB,GAAA,SAAA;AAAA,YAC/C,eAAc,EAAA;AAAA,WAAA;AAAA,8CAEb,YAAa,EAAA,IAAA;AAAA,SAChB;AAAA;AAEJ;AACF,GACF;AAEA,EAAA,MAAM,aAAa,MAAM;AACvB,IAAA,QAAQ,WAAa;AAAA,MACnB,KAAK,CAAA;AACH,QAAO,OAAA,gBAAA;AAAA,MACT,KAAK,CAAA;AACH,QAAO,OAAA,eAAA;AAAA,MACT,KAAK,CAAA;AACH,QAAO,OAAA,gBAAA;AAAA,MACT;AACE,QAAO,OAAA,WAAA;AAAA;AACX,GACF;AAEA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,QAAQ,WAAa;AAAA,MACnB,KAAK,CAAA;AACH,QAAA,OAAO,OAAQ,CAAA,MAAA,CAAO,CAAO,GAAA,KAAA,GAAA,CAAI,UAAU,QAAQ,CAAA;AAAA,MACrD,KAAK,CAAA;AACH,QAAA,OAAO,OAAQ,CAAA,MAAA;AAAA,UAAO,CAAA,GAAA,KACpB,IAAI,KAAU,KAAA,QAAA,IACd,IAAI,KAAU,KAAA,aAAA,IACd,IAAI,KAAU,KAAA;AAAA,SAChB;AAAA,MACF,KAAK,CAAA;AACH,QAAA,OAAO,OAAQ,CAAA,MAAA,CAAO,CAAO,GAAA,KAAA,GAAA,CAAI,UAAU,SAAS,CAAA;AAAA,MACtD;AACE,QAAO,OAAA,OAAA;AAAA;AACX,GACF;AAEA,EAAA,MAAM,UAAU,UAAW,EAAA;AAC3B,EAAA,MAAM,aAAa,aAAc,EAAA;AACjC,EAAM,MAAA,SAAA,GAAY,CAAC,GAAuB,KAAA,CAAC,IAAI,MAAU,IAAA,GAAA,CAAI,OAAO,KAAU,KAAA,SAAA;AAE9E,EAAA,uBAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,KAAM,EAAA,aAAA;AAAA,MACN,WAAW,CAAG,EAAA,gBAAA,CAAiB,MAAM,CAAA,SAAA,EAAY,gBAAgB,MAAM,CAAA,QAAA;AAAA,KAAA;AAAA,oBAEvE,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,CACP,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,KAAO,EAAA,WAAA;AAAA,QACP,QAAU,EAAA,CAAC,CAAG,EAAA,QAAA,KAAa,eAAe,QAAQ,CAAA;AAAA,QAClD,cAAe,EAAA,SAAA;AAAA,QACf,SAAU,EAAA;AAAA,OAAA;AAAA,0CAET,GAAI,EAAA,EAAA,KAAA,EAAO,CAAW,QAAA,EAAA,gBAAA,CAAiB,MAAM,CAAK,CAAA,CAAA,EAAA,CAAA;AAAA,0CAClD,GAAI,EAAA,EAAA,KAAA,EAAO,CAAY,SAAA,EAAA,eAAA,CAAgB,MAAM,CAAK,CAAA,CAAA,EAAA,CAAA;AAAA,0CAClD,GAAI,EAAA,EAAA,KAAA,EAAO,CAAa,UAAA,EAAA,gBAAA,CAAiB,MAAM,CAAK,CAAA,CAAA,EAAA;AAAA,KAEzD,CAAA;AAAA,IACC,OAAA,CAAQ,MAAW,KAAA,CAAA,mBACjB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,GAAG,CAAG,EAAA,SAAA,EAAU,QACnB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,KAAM,EAAA,eAAA,EAAA,EAC/B,WAAgB,KAAA,CAAA,IAAK,8DACrB,EAAA,WAAA,KAAgB,CAAK,IAAA,sBAAA,EACrB,WAAgB,KAAA,CAAA,IAAK,uBACxB,CACF,CAEA,mBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA;AAAA,UACP,MAAA,EAAQ,QAAQ,MAAS,GAAA,EAAA;AAAA,UACzB,QAAU,EAAA,EAAA;AAAA,UACV,MAAQ,EAAA,KAAA;AAAA,UACR,OAAS,EAAA;AAAA,SACX;AAAA,QACA,OAAS,EAAA,UAAA;AAAA,QACT,IAAM,EAAA,OAAA,CAAQ,GAAI,CAAA,CAAC,IAAyB,MAAA;AAAA,UAC1C,GAAG,IAAA;AAAA,UACH,EAAA,EAAI,KAAK,QAAS,CAAA;AAAA,SAClB,CAAA;AAAA;AAAA;AACJ,GAIJ,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,EAAG,EAAA,gBAAA;AAAA,MACH,IAAA,EAAM,QAAQ,UAAU,CAAA;AAAA,MACxB,OAAS,EAAA,eAAA;AAAA,MACT,eAAgB,EAAA,gBAAA;AAAA,MAChB,gBAAgB,UAAc,IAAA,EAAE,GAAK,EAAA,CAAA,EAAG,MAAM,CAAE;AAAA,KAAA;AAAA,IAE/C,gBAAgB,MAAM;AACrB,MAAA,MAAM,QAAQ,EAAC;AACf,MAAI,IAAA,SAAA,CAAU,WAAW,CAAG,EAAA;AAC1B,QAAM,KAAA,CAAA,IAAA,qCAAM,QAAS,EAAA,EAAA,GAAA,EAAI,QAAO,OAAS,EAAA,UAAA,EAAA,EAAY,MAAI,CAAW,CAAA;AAAA;AAEtE,MAAM,KAAA,CAAA,IAAA,qCAAM,QAAS,EAAA,EAAA,GAAA,EAAI,UAAS,OAAS,EAAA,YAAA,EAAA,EAAc,QAAM,CAAW,CAAA;AAC1E,MAAO,OAAA,KAAA;AAAA,KACN;AAAA,GACL,EAEC,gBAAgB,OACf,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,MAAM,eAAgB,CAAA,IAAA;AAAA,MACtB,SAAS,eAAgB,CAAA,OAAA;AAAA,MACzB,gBAAgB,eAAgB,CAAA,KAAA;AAAA,MAChC,OAAA,EAAS,MAAM,kBAAA,CAAmB,EAAE,IAAA,EAAM,KAAO,EAAA,OAAA,EAAS,IAAM,EAAA,KAAA,EAAO,EAAC,EAAG,CAAA;AAAA,MAC3E,WAAW,MAAM;AACf,QAAmB,kBAAA,CAAA,EAAE,MAAM,KAAO,EAAA,OAAA,EAAS,MAAM,KAAO,EAAA,IAAI,CAAA;AAC5D,QAAW,UAAA,CAAA,CAAA,CAAA,KAAK,IAAI,CAAC,CAAA;AAAA;AACvB;AAAA,GAGN,CAAA;AAEJ;;;;"}
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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"}