@kuadrant/kuadrant-backstage-plugin-frontend 0.2.1 → 0.3.0-aaa46b4

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 (152) hide show
  1. package/dist/api.esm.js +40 -2
  2. package/dist/api.esm.js.map +1 -1
  3. package/dist/components/ApiAccessCard/ApiAccessCard.esm.js +20 -85
  4. package/dist/components/ApiAccessCard/ApiAccessCard.esm.js.map +1 -1
  5. package/dist/components/ApiKeyApprovalPage/ApiKeyApprovalPageWithPermissions.esm.js +18 -0
  6. package/dist/components/ApiKeyApprovalPage/ApiKeyApprovalPageWithPermissions.esm.js.map +1 -0
  7. package/dist/components/ApiKeyApprovalPage/index.esm.js +1 -0
  8. package/dist/components/ApiKeyApprovalPage/index.esm.js.map +1 -1
  9. package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js +19 -60
  10. package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js.map +1 -1
  11. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js +45 -110
  12. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js.map +1 -1
  13. package/dist/components/ApiProductInfoCard/ApiProductInfoCard.esm.js +3 -2
  14. package/dist/components/ApiProductInfoCard/ApiProductInfoCard.esm.js.map +1 -1
  15. package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js +16 -15
  16. package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js.map +1 -1
  17. package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js +2 -3
  18. package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js.map +1 -1
  19. package/dist/components/KuadrantPage/ApiProductsPage.esm.js +5 -18
  20. package/dist/components/KuadrantPage/ApiProductsPage.esm.js.map +1 -1
  21. package/dist/components/MyApiKeysTable/MyApiKeysTable.esm.js +28 -138
  22. package/dist/components/MyApiKeysTable/MyApiKeysTable.esm.js.map +1 -1
  23. package/dist/components/PermissionGate/PermissionGate.esm.js +2 -2
  24. package/dist/components/PermissionGate/PermissionGate.esm.js.map +1 -1
  25. package/dist/components/RequestAccessDialog/RequestAccessDialog.esm.js +32 -18
  26. package/dist/components/RequestAccessDialog/RequestAccessDialog.esm.js.map +1 -1
  27. package/dist/components/SimpleRequestAccessDialog/SimpleRequestAccessDialog.esm.js +13 -2
  28. package/dist/components/SimpleRequestAccessDialog/SimpleRequestAccessDialog.esm.js.map +1 -1
  29. package/dist/index.d.ts +47 -6
  30. package/dist/index.esm.js +1 -1
  31. package/dist/plugin.esm.js +2 -10
  32. package/dist/plugin.esm.js.map +1 -1
  33. package/dist/utils/apikeys.esm.js +21 -0
  34. package/dist/utils/apikeys.esm.js.map +1 -0
  35. package/dist/utils/styles.esm.js +5 -2
  36. package/dist/utils/styles.esm.js.map +1 -1
  37. package/dist-scalprum/internal.plugin-kuadrant.7f1de85661b1b848af15.js +2 -0
  38. package/dist-scalprum/internal.plugin-kuadrant.7f1de85661b1b848af15.js.map +1 -0
  39. package/dist-scalprum/plugin-manifest.json +3 -3
  40. package/dist-scalprum/static/1340.7c4f4722.chunk.js +3 -0
  41. package/dist-scalprum/static/1340.7c4f4722.chunk.js.map +1 -0
  42. package/dist-scalprum/static/1719.52ca7daf.chunk.js +2 -0
  43. package/dist-scalprum/static/1719.52ca7daf.chunk.js.map +1 -0
  44. package/dist-scalprum/static/{1881.56cde36b.chunk.js → 1931.f6a5edbb.chunk.js} +2 -2
  45. package/dist-scalprum/static/1931.f6a5edbb.chunk.js.map +1 -0
  46. package/dist-scalprum/static/20.b3a37d1d.chunk.js +3 -0
  47. package/dist-scalprum/static/20.b3a37d1d.chunk.js.map +1 -0
  48. package/dist-scalprum/static/2251.08f3db99.chunk.js +2 -0
  49. package/dist-scalprum/static/2251.08f3db99.chunk.js.map +1 -0
  50. package/dist-scalprum/static/2769.e09b0ab0.chunk.js +2 -0
  51. package/dist-scalprum/static/2769.e09b0ab0.chunk.js.map +1 -0
  52. package/dist-scalprum/static/2821.1ac360ec.chunk.js +2 -0
  53. package/dist-scalprum/static/2821.1ac360ec.chunk.js.map +1 -0
  54. package/dist-scalprum/static/2967.004a950e.chunk.js +2 -0
  55. package/dist-scalprum/static/2967.004a950e.chunk.js.map +1 -0
  56. package/dist-scalprum/static/327.74ecd572.chunk.js +2 -0
  57. package/dist-scalprum/static/327.74ecd572.chunk.js.map +1 -0
  58. package/dist-scalprum/static/3658.104704cc.chunk.js +2 -0
  59. package/dist-scalprum/static/3658.104704cc.chunk.js.map +1 -0
  60. package/dist-scalprum/static/3917.888fba36.chunk.js +2 -0
  61. package/dist-scalprum/static/3917.888fba36.chunk.js.map +1 -0
  62. package/dist-scalprum/static/3947.f5320e89.chunk.js +2 -0
  63. package/dist-scalprum/static/3947.f5320e89.chunk.js.map +1 -0
  64. package/dist-scalprum/static/438.4335b833.chunk.js +2 -0
  65. package/dist-scalprum/static/438.4335b833.chunk.js.map +1 -0
  66. package/dist-scalprum/static/4908.4f21d453.chunk.js +2 -0
  67. package/dist-scalprum/static/4908.4f21d453.chunk.js.map +1 -0
  68. package/dist-scalprum/static/5197.53535ff4.chunk.js +2 -0
  69. package/dist-scalprum/static/5197.53535ff4.chunk.js.map +1 -0
  70. package/dist-scalprum/static/5289.6c803140.chunk.js +2 -0
  71. package/dist-scalprum/static/5289.6c803140.chunk.js.map +1 -0
  72. package/dist-scalprum/static/5943.4e1dedc5.chunk.js +2 -0
  73. package/dist-scalprum/static/5943.4e1dedc5.chunk.js.map +1 -0
  74. package/dist-scalprum/static/6311.da1849d1.chunk.js +2 -0
  75. package/dist-scalprum/static/6311.da1849d1.chunk.js.map +1 -0
  76. package/dist-scalprum/static/6371.02375475.chunk.js +3 -0
  77. package/dist-scalprum/static/6371.02375475.chunk.js.map +1 -0
  78. package/dist-scalprum/static/6837.6252b97a.chunk.js +2 -0
  79. package/dist-scalprum/static/6837.6252b97a.chunk.js.map +1 -0
  80. package/dist-scalprum/static/7270.8ee9d452.chunk.js +2 -0
  81. package/dist-scalprum/static/7270.8ee9d452.chunk.js.map +1 -0
  82. package/dist-scalprum/static/980.744a4d36.chunk.js +2 -0
  83. package/dist-scalprum/static/980.744a4d36.chunk.js.map +1 -0
  84. package/dist-scalprum/static/exposed-KuadrantPage.f123b200.chunk.js +2 -0
  85. package/dist-scalprum/static/exposed-KuadrantPage.f123b200.chunk.js.map +1 -0
  86. package/dist-scalprum/static/exposed-PluginRoot.3a5f9157.chunk.js +2 -0
  87. package/dist-scalprum/static/exposed-PluginRoot.3a5f9157.chunk.js.map +1 -0
  88. package/package.json +1 -1
  89. package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js +0 -265
  90. package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js.map +0 -1
  91. package/dist/components/EntityApiApprovalTab/index.esm.js +0 -2
  92. package/dist/components/EntityApiApprovalTab/index.esm.js.map +0 -1
  93. package/dist-scalprum/internal.plugin-kuadrant.c4fb9c2347d3ad03a5d0.js +0 -2
  94. package/dist-scalprum/internal.plugin-kuadrant.c4fb9c2347d3ad03a5d0.js.map +0 -1
  95. package/dist-scalprum/static/1584.1e45e570.chunk.js +0 -3
  96. package/dist-scalprum/static/1584.1e45e570.chunk.js.map +0 -1
  97. package/dist-scalprum/static/1719.246c020d.chunk.js +0 -2
  98. package/dist-scalprum/static/1719.246c020d.chunk.js.map +0 -1
  99. package/dist-scalprum/static/1881.56cde36b.chunk.js.map +0 -1
  100. package/dist-scalprum/static/286.ee43f560.chunk.js +0 -2
  101. package/dist-scalprum/static/286.ee43f560.chunk.js.map +0 -1
  102. package/dist-scalprum/static/2967.0c2ef90e.chunk.js +0 -2
  103. package/dist-scalprum/static/2967.0c2ef90e.chunk.js.map +0 -1
  104. package/dist-scalprum/static/3581.ebe5968a.chunk.js +0 -2
  105. package/dist-scalprum/static/3581.ebe5968a.chunk.js.map +0 -1
  106. package/dist-scalprum/static/369.2374941c.chunk.js +0 -2
  107. package/dist-scalprum/static/369.2374941c.chunk.js.map +0 -1
  108. package/dist-scalprum/static/3947.4f4aa8c2.chunk.js +0 -2
  109. package/dist-scalprum/static/3947.4f4aa8c2.chunk.js.map +0 -1
  110. package/dist-scalprum/static/3976.e8a8fda2.chunk.js +0 -2
  111. package/dist-scalprum/static/3976.e8a8fda2.chunk.js.map +0 -1
  112. package/dist-scalprum/static/4434.f92f6ba4.chunk.js +0 -2
  113. package/dist-scalprum/static/4434.f92f6ba4.chunk.js.map +0 -1
  114. package/dist-scalprum/static/4908.196a4425.chunk.js +0 -2
  115. package/dist-scalprum/static/4908.196a4425.chunk.js.map +0 -1
  116. package/dist-scalprum/static/512.d592d164.chunk.js +0 -2
  117. package/dist-scalprum/static/512.d592d164.chunk.js.map +0 -1
  118. package/dist-scalprum/static/5289.55069930.chunk.js +0 -2
  119. package/dist-scalprum/static/5289.55069930.chunk.js.map +0 -1
  120. package/dist-scalprum/static/5605.430f697e.chunk.js +0 -2
  121. package/dist-scalprum/static/5605.430f697e.chunk.js.map +0 -1
  122. package/dist-scalprum/static/5978.bf347a09.chunk.js +0 -2
  123. package/dist-scalprum/static/5978.bf347a09.chunk.js.map +0 -1
  124. package/dist-scalprum/static/6371.7b57ac27.chunk.js +0 -3
  125. package/dist-scalprum/static/6371.7b57ac27.chunk.js.map +0 -1
  126. package/dist-scalprum/static/6426.4c18bab5.chunk.js +0 -2
  127. package/dist-scalprum/static/6426.4c18bab5.chunk.js.map +0 -1
  128. package/dist-scalprum/static/6777.a2b77ec5.chunk.js +0 -2
  129. package/dist-scalprum/static/6777.a2b77ec5.chunk.js.map +0 -1
  130. package/dist-scalprum/static/6800.a45da2f4.chunk.js +0 -2
  131. package/dist-scalprum/static/6800.a45da2f4.chunk.js.map +0 -1
  132. package/dist-scalprum/static/7005.8190ad95.chunk.js +0 -2
  133. package/dist-scalprum/static/7005.8190ad95.chunk.js.map +0 -1
  134. package/dist-scalprum/static/7057.fcd688c7.chunk.js +0 -2
  135. package/dist-scalprum/static/7057.fcd688c7.chunk.js.map +0 -1
  136. package/dist-scalprum/static/7270.d52407cd.chunk.js +0 -2
  137. package/dist-scalprum/static/7270.d52407cd.chunk.js.map +0 -1
  138. package/dist-scalprum/static/7717.6f5b9dd7.chunk.js +0 -3
  139. package/dist-scalprum/static/7717.6f5b9dd7.chunk.js.map +0 -1
  140. package/dist-scalprum/static/9079.2ddaea57.chunk.js +0 -2
  141. package/dist-scalprum/static/9079.2ddaea57.chunk.js.map +0 -1
  142. package/dist-scalprum/static/9239.1acfe112.chunk.js +0 -2
  143. package/dist-scalprum/static/9239.1acfe112.chunk.js.map +0 -1
  144. package/dist-scalprum/static/9625.b0c6610a.chunk.js +0 -2
  145. package/dist-scalprum/static/9625.b0c6610a.chunk.js.map +0 -1
  146. package/dist-scalprum/static/exposed-KuadrantPage.5ae00605.chunk.js +0 -2
  147. package/dist-scalprum/static/exposed-KuadrantPage.5ae00605.chunk.js.map +0 -1
  148. package/dist-scalprum/static/exposed-PluginRoot.949381c2.chunk.js +0 -2
  149. package/dist-scalprum/static/exposed-PluginRoot.949381c2.chunk.js.map +0 -1
  150. /package/dist-scalprum/static/{1584.1e45e570.chunk.js.LICENSE.txt → 1340.7c4f4722.chunk.js.LICENSE.txt} +0 -0
  151. /package/dist-scalprum/static/{7717.6f5b9dd7.chunk.js.LICENSE.txt → 20.b3a37d1d.chunk.js.LICENSE.txt} +0 -0
  152. /package/dist-scalprum/static/{6371.7b57ac27.chunk.js.LICENSE.txt → 6371.02375475.chunk.js.LICENSE.txt} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"MyApiKeysTable.esm.js","sources":["../../../src/components/MyApiKeysTable/MyApiKeysTable.tsx"],"sourcesContent":["import React, { useState, useMemo } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport {\n Table,\n TableColumn,\n Link,\n ResponseErrorPanel,\n} from \"@backstage/core-components\";\nimport {\n useApi,\n alertApiRef,\n} from \"@backstage/core-plugin-api\";\nimport { kuadrantApiRef } from '../../api';\nimport useAsync from \"react-use/lib/useAsync\";\nimport {\n Box,\n Chip,\n Typography,\n IconButton,\n Tooltip,\n Menu,\n MenuItem,\n CircularProgress,\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n makeStyles,\n} from \"@material-ui/core\";\nimport { Skeleton } from \"@material-ui/lab\";\nimport { SimpleRequestAccessDialog } from \"../SimpleRequestAccessDialog\";\nimport VisibilityIcon from \"@material-ui/icons/Visibility\";\nimport VisibilityOffIcon from \"@material-ui/icons/VisibilityOff\";\nimport FileCopyIcon from \"@material-ui/icons/FileCopy\";\nimport WarningIcon from \"@material-ui/icons/Warning\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport { EditAPIKeyDialog } from \"../EditAPIKeyDialog\";\nimport { ConfirmDeleteDialog } from \"../ConfirmDeleteDialog\";\nimport { FilterPanel, FilterSection, FilterState } from \"../FilterPanel\";\nimport { APIKey, APIProduct } from \"../../types/api-management\";\nimport { getMyApiKeysStatusChipStyle } from \"../../utils/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n container: {\n display: \"flex\",\n height: \"100%\",\n minHeight: 400,\n },\n tableContainer: {\n flex: 1,\n overflow: \"auto\",\n padding: 10,\n },\n useCasePanel: {\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n },\n useCaseLabel: {\n fontWeight: 600,\n marginBottom: theme.spacing(1),\n color: theme.palette.text.secondary,\n textTransform: \"uppercase\",\n fontSize: \"0.75rem\",\n },\n rejectedBanner: {\n backgroundColor: theme.palette.error.light,\n border: `1px solid ${theme.palette.error.main}`,\n borderRadius: theme.shape.borderRadius,\n padding: theme.spacing(1.5, 2),\n marginBottom: theme.spacing(2),\n display: \"flex\",\n alignItems: \"center\",\n gap: theme.spacing(1),\n },\n}));\n\ninterface ExpandedRowProps {\n request: APIKey;\n}\n\nconst ExpandedRowContent = ({ request }: ExpandedRowProps) => {\n const classes = useStyles();\n const isRejected = request.status?.phase === \"Rejected\";\n const apiProductName = request.spec.apiProductRef?.name || \"unknown\";\n\n return (\n <Box className={classes.useCasePanel} onClick={(e) => e.stopPropagation()}>\n {isRejected && (\n <Box className={classes.rejectedBanner}>\n <WarningIcon color=\"error\" fontSize=\"small\" />\n <Typography variant=\"body2\">\n This API key was rejected.{\" \"}\n <Link to={`/catalog/default/api/${apiProductName}/api-keys`}>\n Request a new API key\n </Link>\n </Typography>\n </Box>\n )}\n <Typography className={classes.useCaseLabel}>Use Case</Typography>\n <Typography variant=\"body2\">\n {request.spec.useCase || \"No use case provided\"}\n </Typography>\n </Box>\n );\n};\n\nexport const MyApiKeysTable = () => {\n const classes = useStyles();\n const navigate = useNavigate();\n const kuadrantApi = useApi(kuadrantApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [requestDialogOpen, setRequestDialogOpen] = useState(false);\n const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());\n const [menuAnchor, setMenuAnchor] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const [menuRequest, setMenuRequest] = useState<APIKey | null>(null);\n const [editDialogState, setEditDialogState] = useState<{\n open: boolean;\n request: APIKey | null;\n plans: any[];\n }>({ open: false, request: null, plans: [] });\n const [refresh, setRefresh] = useState(0);\n const [deleting, setDeleting] = useState<string | null>(null);\n const [deleteDialogState, setDeleteDialogState] = useState<{\n open: boolean;\n request: APIKey | null;\n }>({ open: false, request: null });\n const [apiKeyValues, setApiKeyValues] = useState<Map<string, string>>(\n new Map(),\n );\n const [apiKeyLoading, setApiKeyLoading] = useState<Set<string>>(new Set());\n const [alreadyReadKeys, setAlreadyReadKeys] = useState<Set<string>>(\n new Set(),\n );\n const [showOnceWarningOpen, setShowOnceWarningOpen] = useState(false);\n const [pendingKeyReveal, setPendingKeyReveal] = useState<{\n namespace: string;\n name: string;\n } | null>(null);\n const [optimisticallyDeleted, setOptimisticallyDeleted] = useState<\n Set<string>\n >(new Set());\n\n const [filters, setFilters] = useState<FilterState>({\n status: [],\n apiProduct: [],\n tier: [],\n });\n\n const {\n value: data,\n loading,\n error,\n } = useAsync(async () => {\n const [requestsData, productsData] = await Promise.all([\n kuadrantApi.getRequests(),\n kuadrantApi.getApiProducts(),\n ]);\n\n const requests: APIKey[] = requestsData.items || [];\n const products: APIProduct[] = productsData.items || [];\n\n // build owner map from products\n const ownerMap = new Map<string, string>();\n products.forEach((p) => {\n const key = `${p.metadata.namespace}/${p.metadata.name}`;\n const owner = p.metadata.annotations?.[\"backstage.io/owner\"] || \"unknown\";\n ownerMap.set(key, owner);\n });\n\n return { requests, products, ownerMap };\n }, [kuadrantApi, refresh]);\n\n const allRequests = useMemo(() => {\n if (!data?.requests) return [];\n return data.requests.filter(\n (r: APIKey) => !optimisticallyDeleted.has(r.metadata.name),\n );\n }, [data?.requests, optimisticallyDeleted]);\n\n // filter options from data\n const filterSections: FilterSection[] = useMemo(() => {\n const statusCounts = { Approved: 0, Pending: 0, Rejected: 0 };\n const apiProductCounts = new Map<string, number>();\n const tierCounts = new Map<string, number>();\n\n allRequests.forEach((r: APIKey) => {\n const status = r.status?.phase || \"Pending\";\n statusCounts[status as keyof typeof statusCounts]++;\n\n const apiProduct = r.spec.apiProductRef?.name || \"unknown\";\n apiProductCounts.set(\n apiProduct,\n (apiProductCounts.get(apiProduct) || 0) + 1,\n );\n\n const tier = r.spec.planTier || \"unknown\";\n tierCounts.set(tier, (tierCounts.get(tier) || 0) + 1);\n });\n\n return [\n {\n id: \"status\",\n title: \"Status\",\n options: [\n { value: \"Approved\", label: \"Active\", count: statusCounts.Approved },\n { value: \"Pending\", label: \"Pending\", count: statusCounts.Pending },\n {\n value: \"Rejected\",\n label: \"Rejected\",\n count: statusCounts.Rejected,\n },\n ],\n },\n {\n id: \"apiProduct\",\n title: \"API Product\",\n options: Array.from(apiProductCounts.entries()).map(\n ([name, count]) => ({\n value: name,\n label: name,\n count,\n }),\n ),\n collapsed: apiProductCounts.size > 5,\n },\n {\n id: \"tier\",\n title: \"Tier\",\n options: Array.from(tierCounts.entries()).map(([tier, count]) => ({\n value: tier,\n label: tier.charAt(0).toUpperCase() + tier.slice(1),\n count,\n })),\n },\n ];\n }, [allRequests]);\n\n // filtered requests\n const filteredRequests = useMemo(() => {\n return allRequests.filter((r: APIKey) => {\n // status filter\n if (filters.status.length > 0) {\n const status = r.status?.phase || \"Pending\";\n if (!filters.status.includes(status)) return false;\n }\n\n // api product filter\n if (filters.apiProduct.length > 0) {\n const apiProduct = r.spec.apiProductRef?.name || \"unknown\";\n if (!filters.apiProduct.includes(apiProduct)) return false;\n }\n\n // tier filter\n if (filters.tier.length > 0) {\n const tier = r.spec.planTier || \"unknown\";\n if (!filters.tier.includes(tier)) return false;\n }\n\n return true;\n });\n }, [allRequests, filters]);\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 fetchApiKeyFromSecret = async (\n requestNamespace: string,\n requestName: string,\n ) => {\n const key = `${requestNamespace}/${requestName}`;\n if (apiKeyLoading.has(key)) return;\n\n setApiKeyLoading((prev) => new Set(prev).add(key));\n try {\n const result = await kuadrantApi.getApiKeySecret(requestNamespace, requestName);\n setApiKeyValues((prev) => new Map(prev).set(key, result.apiKey));\n setAlreadyReadKeys((prev) => new Set(prev).add(key));\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : \"unknown error occurred\";\n if (errorMessage.includes(\"403\") || errorMessage.includes(\"already been viewed\")) {\n setAlreadyReadKeys((prev) => new Set(prev).add(key));\n alertApi.post({\n message:\n \"This API key has already been viewed and cannot be retrieved again.\",\n severity: \"warning\",\n display: \"transient\",\n });\n } else {\n alertApi.post({\n message: `Failed to fetch api key: ${errorMessage}`,\n severity: \"error\",\n display: \"transient\",\n });\n }\n } finally {\n setApiKeyLoading((prev) => {\n const next = new Set(prev);\n next.delete(key);\n return next;\n });\n }\n };\n\n const clearApiKeyValue = (requestNamespace: string, requestName: string) => {\n const key = `${requestNamespace}/${requestName}`;\n setApiKeyValues((prev) => {\n const next = new Map(prev);\n next.delete(key);\n return next;\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 try {\n const apiProductName = request.spec.apiProductRef?.name;\n const apiProductNamespace = request.metadata.namespace;\n const apiProduct = await kuadrantApi.getApiProduct(apiProductNamespace, apiProductName);\n const plans = apiProduct.status?.discoveredPlans || [];\n setEditDialogState({ open: true, request, plans });\n } catch (err) {\n console.error(\"Error fetching plans:\", err);\n setEditDialogState({ open: true, request: menuRequest, plans: [] });\n const errorMessage = err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to fetch Plans. ${errorMessage}`,\n severity: 'error',\n display: 'transient',\n });\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 setOptimisticallyDeleted((prev) => new Set(prev).add(requestName));\n setDeleting(requestName);\n\n try {\n await kuadrantApi.deleteRequest(request.metadata.namespace, request.metadata.name);\n setRefresh((r) => r + 1);\n alertApi.post({\n message: \"API key deleted\",\n severity: \"success\",\n display: \"transient\",\n });\n setDeleteDialogState({ open: false, request: null });\n } catch (err) {\n console.error(\"Error deleting request:\", err);\n setOptimisticallyDeleted((prev) => {\n const next = new Set(prev);\n next.delete(requestName);\n return next;\n });\n const errorMessage = err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to delete APIKey. ${errorMessage}`,\n severity: 'error',\n display: 'transient',\n });\n } finally {\n setDeleting(null);\n }\n };\n\n const handleDeleteCancel = () => {\n setDeleteDialogState({ open: false, request: null });\n };\n\n const columns: TableColumn<APIKey>[] = [\n {\n title: \"API Product\",\n field: \"spec.apiProductRef.name\",\n render: (row: APIKey) => {\n const apiProductName = row.spec.apiProductRef?.name || \"unknown\";\n return (\n <Link to={`/catalog/default/api/${apiProductName}/api-keys`}>\n <strong>{apiProductName}</strong>\n </Link>\n );\n },\n },\n {\n title: \"Owner\",\n field: \"owner\",\n render: (row: APIKey) => {\n const key = `${row.metadata.namespace}/${row.spec.apiProductRef?.name}`;\n const owner = data?.ownerMap?.get(key) || \"unknown\";\n // strip 'user:default/' prefix if present\n const displayOwner = owner.replace(/^user:default\\//, \"\");\n return <Typography variant=\"body2\">{displayOwner}</Typography>;\n },\n },\n {\n title: \"Status\",\n field: \"status.phase\",\n render: (row: APIKey) => {\n const phase = row.status?.phase || \"Pending\";\n const label = phase === \"Approved\" ? \"Active\" : phase;\n return (\n <Chip label={label} size=\"small\" style={getMyApiKeysStatusChipStyle(phase)} />\n );\n },\n },\n {\n title: \"Tier\",\n field: \"spec.planTier\",\n render: (row: APIKey) => (\n <Chip label={row.spec.planTier} size=\"small\" variant=\"outlined\" />\n ),\n },\n {\n title: \"API Key\",\n field: \"status.secretRef\",\n filtering: false,\n render: (row: APIKey) => {\n if (row.status?.phase !== \"Approved\") {\n return (\n <Typography variant=\"body2\" color=\"textSecondary\">\n -\n </Typography>\n );\n }\n\n const key = `${row.metadata.namespace}/${row.metadata.name}`;\n const hasSecretRef = row.status?.secretRef?.name;\n const isVisible = visibleKeys.has(row.metadata.name);\n const isLoading = apiKeyLoading.has(key);\n const apiKeyValue = apiKeyValues.get(key);\n const canReadSecret = row.status?.canReadSecret !== false;\n const isAlreadyRead = alreadyReadKeys.has(key) || !canReadSecret;\n\n if (!hasSecretRef) {\n return (\n <Typography variant=\"body2\" color=\"textSecondary\">\n Awaiting secret...\n </Typography>\n );\n }\n\n if (isAlreadyRead && !apiKeyValue) {\n return (\n <Tooltip title=\"This API key has already been viewed and cannot be retrieved again\">\n <Box display=\"flex\" alignItems=\"center\">\n <Typography\n variant=\"body2\"\n color=\"textSecondary\"\n style={{ fontFamily: \"monospace\", marginRight: 8 }}\n >\n Already viewed\n </Typography>\n <VisibilityOffIcon fontSize=\"small\" color=\"disabled\" />\n </Box>\n </Tooltip>\n );\n }\n\n const handleRevealClick = () => {\n if (isVisible) {\n clearApiKeyValue(row.metadata.namespace, row.metadata.name);\n toggleKeyVisibility(row.metadata.name);\n } else if (!isAlreadyRead) {\n setPendingKeyReveal({\n namespace: row.metadata.namespace,\n name: row.metadata.name,\n });\n setShowOnceWarningOpen(true);\n }\n };\n\n const handleCopy = async () => {\n if (apiKeyValue) {\n await navigator.clipboard.writeText(apiKeyValue);\n alertApi.post({\n message: \"API key copied to clipboard\",\n severity: \"success\",\n display: \"transient\",\n });\n }\n };\n\n return (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <Box fontFamily=\"monospace\" fontSize=\"0.875rem\">\n {isLoading\n ? \"Loading...\"\n : isVisible && apiKeyValue\n ? apiKeyValue\n : \"•\".repeat(20) + \"...\"}\n </Box>\n {isVisible && apiKeyValue && (\n <Tooltip title=\"Copy to clipboard\">\n <IconButton size=\"small\" onClick={handleCopy}>\n <FileCopyIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n <Tooltip\n title={\n isVisible ? \"Hide API key\" : \"Reveal API key (one-time only)\"\n }\n >\n <span>\n <IconButton\n size=\"small\"\n onClick={handleRevealClick}\n disabled={isLoading || (isAlreadyRead && !apiKeyValue)}\n >\n {isVisible ? (\n <VisibilityOffIcon fontSize=\"small\" />\n ) : (\n <VisibilityIcon fontSize=\"small\" />\n )}\n </IconButton>\n </span>\n </Tooltip>\n </Box>\n );\n },\n },\n {\n title: \"Requested\",\n field: \"metadata.creationTimestamp\",\n render: (row: APIKey) => {\n if (!row.metadata.creationTimestamp) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n const date = new Date(row.metadata.creationTimestamp);\n return (\n <Typography variant=\"body2\">{date.toLocaleDateString()}</Typography>\n );\n },\n },\n {\n title: \"Actions\",\n filtering: false,\n width: \"100px\",\n render: (row: APIKey) => {\n const isDeleting = deleting === row.metadata.name;\n if (isDeleting) {\n return <CircularProgress size={20} />;\n }\n return (\n <Box display=\"flex\" style={{ gap: 4 }}>\n <Tooltip title=\"View details\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(\n `/kuadrant/api-keys/${row.metadata.namespace}/${row.metadata.name}`,\n );\n }}\n >\n <VisibilityIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Delete\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n setDeleteDialogState({ open: true, request: row });\n }}\n >\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </Box>\n );\n },\n },\n ];\n\n const detailPanelConfig = useMemo(\n () => [\n {\n render: (data: any) => {\n const request = data.rowData as APIKey;\n if (!request?.metadata?.name) {\n return <Box />;\n }\n return <ExpandedRowContent request={request} />;\n },\n },\n ],\n [],\n );\n\n if (loading) {\n return (\n <Box p={2}>\n {[...Array(5)].map((_, i) => (\n <Box key={i} p={2}>\n <Skeleton variant=\"text\" width=\"100%\" />\n </Box>\n ))}\n </Box>\n );\n }\n\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n const isPending = (row: APIKey) =>\n !row.status || row.status.phase === \"Pending\";\n\n return (\n <>\n <Box display=\"flex\" justifyContent=\"flex-end\" mb={2} px={2}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setRequestDialogOpen(true)}\n data-testid=\"request-access-button\"\n >\n Request Access\n </Button>\n </Box>\n <Box className={classes.container}>\n <FilterPanel\n sections={filterSections}\n filters={filters}\n onChange={setFilters}\n />\n <Box className={classes.tableContainer}>\n {allRequests.length === 0 ? (\n <Box p={4} textAlign=\"center\">\n <Typography variant=\"body1\" color=\"textSecondary\" gutterBottom>\n No API keys found. Request access to an API to get started.\n </Typography>\n </Box>\n ) : filteredRequests.length === 0 ? (\n <Box p={4} textAlign=\"center\">\n <Typography variant=\"body1\" color=\"textSecondary\">\n No API keys match the selected filters.\n </Typography>\n </Box>\n ) : (\n <Table\n options={{\n paging: filteredRequests.length > 10,\n pageSize: 20,\n search: true,\n filtering: false,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={columns}\n data={filteredRequests.map((item: APIKey) => ({\n ...item,\n id: item.metadata.name,\n }))}\n detailPanel={detailPanelConfig}\n />\n )}\n </Box>\n </Box>\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 (() => {\n const items = [];\n items.push(\n <MenuItem\n key=\"view\"\n onClick={() => {\n navigate(\n `/kuadrant/api-keys/${menuRequest.metadata.namespace}/${menuRequest.metadata.name}`,\n );\n handleMenuClose();\n }}\n >\n View Details\n </MenuItem>,\n );\n if (isPending(menuRequest)) {\n items.push(\n <MenuItem key=\"edit\" onClick={handleEdit}>\n Edit\n </MenuItem>,\n );\n }\n items.push(\n <MenuItem key=\"delete\" onClick={handleDeleteClick}>\n Delete\n </MenuItem>,\n );\n return items;\n })()}\n </Menu>\n\n {editDialogState.request && (\n <EditAPIKeyDialog\n open={editDialogState.open}\n request={editDialogState.request}\n availablePlans={editDialogState.plans}\n onClose={() =>\n setEditDialogState({ open: false, request: null, plans: [] })\n }\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\"\n description={`Are you sure you want to delete this API key for ${deleteDialogState.request?.spec.apiProductRef?.name || \"this API\"}?`}\n deleting={deleting !== null}\n onConfirm={handleDeleteConfirm}\n onCancel={handleDeleteCancel}\n />\n\n <Dialog\n open={showOnceWarningOpen}\n onClose={() => {\n setShowOnceWarningOpen(false);\n setPendingKeyReveal(null);\n }}\n maxWidth=\"sm\"\n >\n <DialogTitle>\n <Box display=\"flex\" alignItems=\"center\">\n <WarningIcon color=\"primary\" style={{ marginRight: 8 }} />\n View API Key\n </Box>\n </DialogTitle>\n <DialogContent>\n <Typography variant=\"body1\" paragraph>\n This API key can only be viewed <strong>once</strong>. After you\n reveal it, you will not be able to retrieve it again.\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Make sure to copy and store it securely before closing this view.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() => {\n setShowOnceWarningOpen(false);\n setPendingKeyReveal(null);\n }}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={() => {\n if (pendingKeyReveal) {\n fetchApiKeyFromSecret(\n pendingKeyReveal.namespace,\n pendingKeyReveal.name,\n );\n toggleKeyVisibility(pendingKeyReveal.name);\n }\n setShowOnceWarningOpen(false);\n setPendingKeyReveal(null);\n }}\n >\n Reveal API Key\n </Button>\n </DialogActions>\n </Dialog>\n\n <SimpleRequestAccessDialog\n open={requestDialogOpen}\n onClose={() => setRequestDialogOpen(false)}\n onSuccess={() => {\n setRequestDialogOpen(false);\n setRefresh((prev) => prev + 1);\n }}\n />\n </>\n );\n};\n"],"names":["data"],"mappings":"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"}
1
+ {"version":3,"file":"MyApiKeysTable.esm.js","sources":["../../../src/components/MyApiKeysTable/MyApiKeysTable.tsx"],"sourcesContent":["import React, { useState, useMemo } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport {\n Table,\n TableColumn,\n Link,\n ResponseErrorPanel,\n} from \"@backstage/core-components\";\nimport {\n useApi,\n alertApiRef,\n} from \"@backstage/core-plugin-api\";\nimport { kuadrantApiRef } from '../../api';\nimport { getAPIKeyPhase } from '../../utils/apikeys';\nimport useAsync from \"react-use/lib/useAsync\";\nimport {\n Box,\n Chip,\n Typography,\n IconButton,\n Tooltip,\n CircularProgress,\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n makeStyles,\n} from \"@material-ui/core\";\nimport { Skeleton } from \"@material-ui/lab\";\nimport { SimpleRequestAccessDialog } from \"../SimpleRequestAccessDialog\";\nimport VisibilityIcon from \"@material-ui/icons/Visibility\";\nimport VisibilityOffIcon from \"@material-ui/icons/VisibilityOff\";\nimport FileCopyIcon from \"@material-ui/icons/FileCopy\";\nimport WarningIcon from \"@material-ui/icons/Warning\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport { ConfirmDeleteDialog } from \"../ConfirmDeleteDialog\";\nimport { FilterPanel, FilterSection, FilterState } from \"../FilterPanel\";\nimport { APIKey, APIProduct } from \"../../types/api-management\";\nimport { getMyApiKeysStatusChipStyle } from \"../../utils/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n container: {\n display: \"flex\",\n height: \"100%\",\n minHeight: 400,\n },\n tableContainer: {\n flex: 1,\n overflow: \"auto\",\n padding: 10,\n },\n useCasePanel: {\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n },\n useCaseLabel: {\n fontWeight: 600,\n marginBottom: theme.spacing(1),\n color: theme.palette.text.secondary,\n textTransform: \"uppercase\",\n fontSize: \"0.75rem\",\n },\n rejectedBanner: {\n backgroundColor: theme.palette.error.light,\n border: `1px solid ${theme.palette.error.main}`,\n borderRadius: theme.shape.borderRadius,\n padding: theme.spacing(1.5, 2),\n marginBottom: theme.spacing(2),\n display: \"flex\",\n alignItems: \"center\",\n gap: theme.spacing(1),\n },\n}));\n\ninterface ExpandedRowProps {\n request: APIKey;\n}\n\nconst ExpandedRowContent = ({ request }: ExpandedRowProps) => {\n const classes = useStyles();\n const isRejected = getAPIKeyPhase(request.status?.conditions) === \"Denied\";\n const apiProductName = request.spec.apiProductRef?.name || \"unknown\";\n\n return (\n <Box className={classes.useCasePanel} onClick={(e) => e.stopPropagation()}>\n {isRejected && (\n <Box className={classes.rejectedBanner}>\n <WarningIcon color=\"error\" fontSize=\"small\" />\n <Typography variant=\"body2\">\n This API key was denied.{\" \"}\n <Link to={`/catalog/default/api/${apiProductName}/api-keys`}>\n Request a new API key\n </Link>\n </Typography>\n </Box>\n )}\n <Typography className={classes.useCaseLabel}>Use Case</Typography>\n <Typography variant=\"body2\">\n {request.spec.useCase || \"No use case provided\"}\n </Typography>\n </Box>\n );\n};\n\nexport const MyApiKeysTable = () => {\n const classes = useStyles();\n const navigate = useNavigate();\n const kuadrantApi = useApi(kuadrantApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [requestDialogOpen, setRequestDialogOpen] = useState(false);\n const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());\n const [refresh, setRefresh] = useState(0);\n const [deleting, setDeleting] = useState<string | null>(null);\n const [deleteDialogState, setDeleteDialogState] = useState<{\n open: boolean;\n request: APIKey | null;\n }>({ open: false, request: null });\n const [apiKeyValues, setApiKeyValues] = useState<Map<string, string>>(\n new Map(),\n );\n const [apiKeyLoading, setApiKeyLoading] = useState<Set<string>>(new Set());\n const [showOnceWarningOpen, setShowOnceWarningOpen] = useState(false);\n const [pendingKeyReveal, setPendingKeyReveal] = useState<{\n namespace: string;\n name: string;\n } | null>(null);\n const [optimisticallyDeleted, setOptimisticallyDeleted] = useState<\n Set<string>\n >(new Set());\n\n const [filters, setFilters] = useState<FilterState>({\n status: [],\n apiProduct: [],\n tier: [],\n });\n\n const {\n value: data,\n loading,\n error,\n } = useAsync(async () => {\n const [requestsData, productsData] = await Promise.all([\n kuadrantApi.getRequests(),\n kuadrantApi.getApiProducts(),\n ]);\n\n const requests: APIKey[] = requestsData.items || [];\n const products: APIProduct[] = productsData.items || [];\n\n // build owner map from products\n const ownerMap = new Map<string, string>();\n products.forEach((p) => {\n const key = `${p.metadata.namespace}/${p.metadata.name}`;\n const owner = p.metadata.annotations?.[\"backstage.io/owner\"] || \"unknown\";\n ownerMap.set(key, owner);\n });\n\n return { requests, products, ownerMap };\n }, [kuadrantApi, refresh]);\n\n const allRequests = useMemo(() => {\n if (!data?.requests) return [];\n return data.requests.filter(\n (r: APIKey) => !optimisticallyDeleted.has(r.metadata.name),\n );\n }, [data?.requests, optimisticallyDeleted]);\n\n // pass through phase as-is for UI display\n const toUiStatus = (phase: ReturnType<typeof getAPIKeyPhase>) => phase;\n\n // filter options from data\n const filterSections: FilterSection[] = useMemo(() => {\n const statusCounts = { Approved: 0, Pending: 0, Denied: 0, Failed: 0 };\n const apiProductCounts = new Map<string, number>();\n const tierCounts = new Map<string, number>();\n\n allRequests.forEach((r: APIKey) => {\n const status = toUiStatus(getAPIKeyPhase(r.status?.conditions));\n statusCounts[status as keyof typeof statusCounts]++;\n\n const apiProduct = r.spec.apiProductRef?.name || \"unknown\";\n apiProductCounts.set(\n apiProduct,\n (apiProductCounts.get(apiProduct) || 0) + 1,\n );\n\n const tier = r.spec.planTier || \"unknown\";\n tierCounts.set(tier, (tierCounts.get(tier) || 0) + 1);\n });\n\n return [\n {\n id: \"status\",\n title: \"Status\",\n options: [\n { value: \"Approved\", label: \"Active\", count: statusCounts.Approved },\n { value: \"Pending\", label: \"Pending\", count: statusCounts.Pending },\n {\n value: \"Denied\",\n label: \"Denied\",\n count: statusCounts.Denied,\n },\n { value: \"Failed\", label: \"Failed\", count: statusCounts.Failed },\n ],\n },\n {\n id: \"apiProduct\",\n title: \"API Product\",\n options: Array.from(apiProductCounts.entries()).map(\n ([name, count]) => ({\n value: name,\n label: name,\n count,\n }),\n ),\n collapsed: apiProductCounts.size > 5,\n },\n {\n id: \"tier\",\n title: \"Tier\",\n options: Array.from(tierCounts.entries()).map(([tier, count]) => ({\n value: tier,\n label: tier.charAt(0).toUpperCase() + tier.slice(1),\n count,\n })),\n },\n ];\n }, [allRequests]);\n\n // filtered requests\n const filteredRequests = useMemo(() => {\n return allRequests.filter((r: APIKey) => {\n // status filter\n if (filters.status.length > 0) {\n const status = toUiStatus(getAPIKeyPhase(r.status?.conditions));\n if (!filters.status.includes(status)) return false;\n }\n\n // api product filter\n if (filters.apiProduct.length > 0) {\n const apiProduct = r.spec.apiProductRef?.name || \"unknown\";\n if (!filters.apiProduct.includes(apiProduct)) return false;\n }\n\n // tier filter\n if (filters.tier.length > 0) {\n const tier = r.spec.planTier || \"unknown\";\n if (!filters.tier.includes(tier)) return false;\n }\n\n return true;\n });\n }, [allRequests, filters]);\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 fetchApiKeyFromSecret = async (\n requestNamespace: string,\n requestName: string,\n ) => {\n const key = `${requestNamespace}/${requestName}`;\n if (apiKeyLoading.has(key)) return;\n\n setApiKeyLoading((prev) => new Set(prev).add(key));\n try {\n const result = await kuadrantApi.getApiKeySecret(requestNamespace, requestName);\n setApiKeyValues((prev) => new Map(prev).set(key, result.apiKey));\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to fetch api key: ${errorMessage}`,\n severity: \"error\",\n display: \"transient\",\n });\n } finally {\n setApiKeyLoading((prev) => {\n const next = new Set(prev);\n next.delete(key);\n return next;\n });\n }\n };\n\n const clearApiKeyValue = (requestNamespace: string, requestName: string) => {\n const key = `${requestNamespace}/${requestName}`;\n setApiKeyValues((prev) => {\n const next = new Map(prev);\n next.delete(key);\n return next;\n });\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 setOptimisticallyDeleted((prev) => new Set(prev).add(requestName));\n setDeleting(requestName);\n\n try {\n await kuadrantApi.deleteRequest(request.metadata.namespace, request.metadata.name);\n setRefresh((r) => r + 1);\n alertApi.post({\n message: \"API key deleted\",\n severity: \"success\",\n display: \"transient\",\n });\n setDeleteDialogState({ open: false, request: null });\n } catch (err) {\n console.error(\"Error deleting request:\", err);\n setOptimisticallyDeleted((prev) => {\n const next = new Set(prev);\n next.delete(requestName);\n return next;\n });\n const errorMessage = err instanceof Error ? err.message : \"unknown error occurred\";\n alertApi.post({\n message: `Failed to delete APIKey. ${errorMessage}`,\n severity: 'error',\n display: 'transient',\n });\n } finally {\n setDeleting(null);\n }\n };\n\n const handleDeleteCancel = () => {\n setDeleteDialogState({ open: false, request: null });\n };\n\n const columns: TableColumn<APIKey>[] = [\n {\n title: \"API Product\",\n field: \"spec.apiProductRef.name\",\n render: (row: APIKey) => {\n const apiProductName = row.spec.apiProductRef?.name || \"unknown\";\n return (\n <Link to={`/catalog/default/api/${apiProductName}/api-keys`}>\n <strong>{apiProductName}</strong>\n </Link>\n );\n },\n },\n {\n title: \"Owner\",\n field: \"owner\",\n render: (row: APIKey) => {\n const key = `${row.metadata.namespace}/${row.spec.apiProductRef?.name}`;\n const owner = data?.ownerMap?.get(key) || \"unknown\";\n // strip 'user:default/' prefix if present\n const displayOwner = owner.replace(/^user:default\\//, \"\");\n return <Typography variant=\"body2\">{displayOwner}</Typography>;\n },\n },\n {\n title: \"Status\",\n field: \"status.conditions\",\n render: (row: APIKey) => {\n const phase = getAPIKeyPhase(row.status?.conditions);\n const displayPhase = toUiStatus(phase);\n const label = displayPhase === \"Approved\" ? \"Active\" : displayPhase;\n return (\n <Chip label={label} size=\"small\" style={getMyApiKeysStatusChipStyle(phase)} />\n );\n },\n },\n {\n title: \"Tier\",\n field: \"spec.planTier\",\n render: (row: APIKey) => (\n <Chip label={row.spec.planTier} size=\"small\" variant=\"outlined\" />\n ),\n },\n {\n title: \"API Key\",\n field: \"status.secretRef\",\n filtering: false,\n render: (row: APIKey) => {\n if (getAPIKeyPhase(row.status?.conditions) !== \"Approved\") {\n return (\n <Typography variant=\"body2\" color=\"textSecondary\">\n -\n </Typography>\n );\n }\n\n const key = `${row.metadata.namespace}/${row.metadata.name}`;\n const isVisible = visibleKeys.has(row.metadata.name);\n const isLoading = apiKeyLoading.has(key);\n const apiKeyValue = apiKeyValues.get(key);\n\n const handleRevealClick = () => {\n if (isVisible) {\n clearApiKeyValue(row.metadata.namespace, row.metadata.name);\n toggleKeyVisibility(row.metadata.name);\n } else {\n setPendingKeyReveal({\n namespace: row.metadata.namespace,\n name: row.metadata.name,\n });\n setShowOnceWarningOpen(true);\n }\n };\n\n const handleCopy = async () => {\n if (apiKeyValue) {\n await navigator.clipboard.writeText(apiKeyValue);\n alertApi.post({\n message: \"API key copied to clipboard\",\n severity: \"success\",\n display: \"transient\",\n });\n }\n };\n\n return (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <Box fontFamily=\"monospace\" fontSize=\"0.875rem\">\n {isLoading\n ? \"Loading...\"\n : isVisible && apiKeyValue\n ? apiKeyValue\n : \"•\".repeat(20)}\n </Box>\n {isVisible && apiKeyValue && (\n <Tooltip title=\"Copy to clipboard\">\n <IconButton size=\"small\" onClick={handleCopy}>\n <FileCopyIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n <Tooltip\n title={\n isVisible ? \"Hide API key\" : \"Reveal API key\"\n }\n >\n <span>\n <IconButton\n size=\"small\"\n onClick={handleRevealClick}\n disabled={isLoading}\n >\n {isVisible ? (\n <VisibilityOffIcon fontSize=\"small\" />\n ) : (\n <VisibilityIcon fontSize=\"small\" />\n )}\n </IconButton>\n </span>\n </Tooltip>\n </Box>\n );\n },\n },\n {\n title: \"Requested\",\n field: \"metadata.creationTimestamp\",\n render: (row: APIKey) => {\n if (!row.metadata.creationTimestamp) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n const date = new Date(row.metadata.creationTimestamp);\n return (\n <Typography variant=\"body2\">{date.toLocaleDateString()}</Typography>\n );\n },\n },\n {\n title: \"Actions\",\n filtering: false,\n width: \"100px\",\n render: (row: APIKey) => {\n const isDeleting = deleting === row.metadata.name;\n if (isDeleting) {\n return <CircularProgress size={20} />;\n }\n return (\n <Box display=\"flex\" style={{ gap: 4 }}>\n <Tooltip title=\"View details\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(\n `/kuadrant/api-keys/${row.metadata.namespace}/${row.metadata.name}`,\n );\n }}\n >\n <VisibilityIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Delete\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n setDeleteDialogState({ open: true, request: row });\n }}\n >\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </Box>\n );\n },\n },\n ];\n\n const detailPanelConfig = useMemo(\n () => [\n {\n render: (data: any) => {\n const request = data.rowData as APIKey;\n if (!request?.metadata?.name) {\n return <Box />;\n }\n return <ExpandedRowContent request={request} />;\n },\n },\n ],\n [],\n );\n\n if (loading) {\n return (\n <Box p={2}>\n {[...Array(5)].map((_, i) => (\n <Box key={i} p={2}>\n <Skeleton variant=\"text\" width=\"100%\" />\n </Box>\n ))}\n </Box>\n );\n }\n\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <>\n <Box display=\"flex\" justifyContent=\"flex-end\" mb={2} px={2}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setRequestDialogOpen(true)}\n data-testid=\"request-access-button\"\n >\n Request Access\n </Button>\n </Box>\n <Box className={classes.container}>\n <FilterPanel\n sections={filterSections}\n filters={filters}\n onChange={setFilters}\n />\n <Box className={classes.tableContainer}>\n {allRequests.length === 0 ? (\n <Box p={4} textAlign=\"center\">\n <Typography variant=\"body1\" color=\"textSecondary\" gutterBottom>\n No API keys found. Request access to an API to get started.\n </Typography>\n </Box>\n ) : filteredRequests.length === 0 ? (\n <Box p={4} textAlign=\"center\">\n <Typography variant=\"body1\" color=\"textSecondary\">\n No API keys match the selected filters.\n </Typography>\n </Box>\n ) : (\n <Table\n options={{\n paging: filteredRequests.length > 10,\n pageSize: 20,\n search: true,\n filtering: false,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={columns}\n data={filteredRequests.map((item: APIKey) => ({\n ...item,\n id: item.metadata.name,\n }))}\n detailPanel={detailPanelConfig}\n />\n )}\n </Box>\n </Box>\n\n <ConfirmDeleteDialog\n open={deleteDialogState.open}\n title=\"Delete API Key\"\n description={`Are you sure you want to delete this API key for ${deleteDialogState.request?.spec.apiProductRef?.name || \"this API\"}?`}\n deleting={deleting !== null}\n onConfirm={handleDeleteConfirm}\n onCancel={handleDeleteCancel}\n />\n\n <Dialog\n open={showOnceWarningOpen}\n onClose={() => {\n setShowOnceWarningOpen(false);\n setPendingKeyReveal(null);\n }}\n maxWidth=\"sm\"\n >\n <DialogTitle>\n <Box display=\"flex\" alignItems=\"center\">\n <WarningIcon color=\"primary\" style={{ marginRight: 8 }} />\n View API Key\n </Box>\n </DialogTitle>\n <DialogContent>\n <Typography variant=\"body1\" paragraph>\n You are about to reveal the API key. Make sure to copy and store it\n securely.\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n The key will remain accessible for future viewing if needed.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() => {\n setShowOnceWarningOpen(false);\n setPendingKeyReveal(null);\n }}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={() => {\n if (pendingKeyReveal) {\n fetchApiKeyFromSecret(\n pendingKeyReveal.namespace,\n pendingKeyReveal.name,\n );\n toggleKeyVisibility(pendingKeyReveal.name);\n }\n setShowOnceWarningOpen(false);\n setPendingKeyReveal(null);\n }}\n >\n Reveal API Key\n </Button>\n </DialogActions>\n </Dialog>\n\n <SimpleRequestAccessDialog\n open={requestDialogOpen}\n onClose={() => setRequestDialogOpen(false)}\n onSuccess={() => {\n setRequestDialogOpen(false);\n setRefresh((prev) => prev + 1);\n }}\n />\n </>\n );\n};\n"],"names":["data"],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  import React from 'react';
2
2
  import { Box, Typography } from '@material-ui/core';
3
- import { Progress } from '@backstage/core-components';
3
+ import { Skeleton } from '@material-ui/lab';
4
4
  import { useKuadrantPermission } from '../../utils/permissions.esm.js';
5
5
 
6
6
  const PermissionGate = ({ children, permission, fallback, errorMessage }) => {
7
7
  const { allowed, loading, error } = useKuadrantPermission(permission);
8
8
  if (loading) {
9
- return /* @__PURE__ */ React.createElement(Progress, null);
9
+ return /* @__PURE__ */ React.createElement(Box, { p: 2 }, [...Array(5)].map((_, i) => /* @__PURE__ */ React.createElement(Box, { key: i, p: 2 }, /* @__PURE__ */ React.createElement(Skeleton, { variant: "text", width: "100%" }))));
10
10
  }
11
11
  if (error) {
12
12
  return /* @__PURE__ */ React.createElement(Box, { p: 4 }, /* @__PURE__ */ React.createElement(Typography, { color: "error" }, "Unable to check permissions: ", error.message), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "textSecondary" }, "Please try again or contact your administrator"));
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionGate.esm.js","sources":["../../../src/components/PermissionGate/PermissionGate.tsx"],"sourcesContent":["import React from 'react';\nimport { Typography, Box } from '@material-ui/core';\nimport { Progress } from '@backstage/core-components';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport { useKuadrantPermission } from '../../utils/permissions';\n\ninterface PermissionGateProps {\n children: React.ReactNode;\n permission: Permission;\n fallback?: React.ReactNode;\n errorMessage?: string;\n}\n\nexport const PermissionGate = ({ children, permission, fallback, errorMessage }: PermissionGateProps) => {\n const { allowed, loading, error } = useKuadrantPermission(permission);\n\n if (loading) {\n return <Progress />;\n }\n\n if (error) {\n return (\n <Box p={4}>\n <Typography color=\"error\">\n Unable to check permissions: {error.message}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Please try again or contact your administrator\n </Typography>\n </Box>\n );\n }\n\n if (!allowed) {\n if (fallback) {\n return <>{fallback}</>;\n }\n return (\n <Box p={4}>\n <Typography color=\"textSecondary\">\n {errorMessage || 'You don\\'t have permission to view this page'}\n </Typography>\n <Box mt={1}>\n <Typography variant=\"caption\" color=\"textSecondary\">\n Required permission: {permission.name}\n </Typography>\n </Box>\n </Box>\n );\n }\n\n return <>{children}</>;\n};\n"],"names":[],"mappings":";;;;;AAaO,MAAM,iBAAiB,CAAC,EAAE,UAAU,UAAY,EAAA,QAAA,EAAU,cAAwC,KAAA;AACvG,EAAA,MAAM,EAAE,OAAS,EAAA,OAAA,EAAS,KAAM,EAAA,GAAI,sBAAsB,UAAU,CAAA;AAEpE,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2CAAQ,QAAS,EAAA,IAAA,CAAA;AAAA;AAGnB,EAAA,IAAI,KAAO,EAAA;AACT,IAAA,2CACG,GAAI,EAAA,EAAA,CAAA,EAAG,qBACL,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAM,OAAQ,EAAA,EAAA,+BAAA,EACM,MAAM,OACtC,CAAA,sCACC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,KAAM,EAAA,eAAA,EAAA,EAAgB,gDAElD,CACF,CAAA;AAAA;AAIJ,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAA,IAAI,QAAU,EAAA;AACZ,MAAA,iEAAU,QAAS,CAAA;AAAA;AAErB,IACE,uBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,CAAA,EAAG,CACN,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,KAAM,EAAA,eAAA,EAAA,EACf,YAAgB,IAAA,6CACnB,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAA,kBACN,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,SAAA,EAAU,KAAM,EAAA,eAAA,EAAA,EAAgB,uBAC5B,EAAA,UAAA,CAAW,IACnC,CACF,CACF,CAAA;AAAA;AAIJ,EAAA,iEAAU,QAAS,CAAA;AACrB;;;;"}
1
+ {"version":3,"file":"PermissionGate.esm.js","sources":["../../../src/components/PermissionGate/PermissionGate.tsx"],"sourcesContent":["import React from 'react';\nimport { Typography, Box } from '@material-ui/core';\nimport { Skeleton } from '@material-ui/lab';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport { useKuadrantPermission } from '../../utils/permissions';\n\ninterface PermissionGateProps {\n children: React.ReactNode;\n permission: Permission;\n fallback?: React.ReactNode;\n errorMessage?: string;\n}\n\nexport const PermissionGate = ({ children, permission, fallback, errorMessage }: PermissionGateProps) => {\n const { allowed, loading, error } = useKuadrantPermission(permission);\n\n if (loading) {\n return (\n <Box p={2}>\n {[...Array(5)].map((_, i) => (\n <Box key={i} p={2}>\n <Skeleton variant=\"text\" width=\"100%\" />\n </Box>\n ))}\n </Box>\n );\n }\n\n if (error) {\n return (\n <Box p={4}>\n <Typography color=\"error\">\n Unable to check permissions: {error.message}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Please try again or contact your administrator\n </Typography>\n </Box>\n );\n }\n\n if (!allowed) {\n if (fallback) {\n return <>{fallback}</>;\n }\n return (\n <Box p={4}>\n <Typography color=\"textSecondary\">\n {errorMessage || 'You don\\'t have permission to view this page'}\n </Typography>\n <Box mt={1}>\n <Typography variant=\"caption\" color=\"textSecondary\">\n Required permission: {permission.name}\n </Typography>\n </Box>\n </Box>\n );\n }\n\n return <>{children}</>;\n};\n"],"names":[],"mappings":";;;;;AAaO,MAAM,iBAAiB,CAAC,EAAE,UAAU,UAAY,EAAA,QAAA,EAAU,cAAwC,KAAA;AACvG,EAAA,MAAM,EAAE,OAAS,EAAA,OAAA,EAAS,KAAM,EAAA,GAAI,sBAAsB,UAAU,CAAA;AAEpE,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,uBACG,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,CAAG,EAAA,CAAA,EAAA,EACL,CAAC,GAAG,KAAM,CAAA,CAAC,CAAC,CAAA,CAAE,GAAI,CAAA,CAAC,CAAG,EAAA,CAAA,qBACpB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,GAAK,EAAA,CAAA,EAAG,CAAG,EAAA,CAAA,EAAA,kBACb,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,OAAQ,EAAA,MAAA,EAAO,KAAM,EAAA,MAAA,EAAO,CACxC,CACD,CACH,CAAA;AAAA;AAIJ,EAAA,IAAI,KAAO,EAAA;AACT,IAAA,2CACG,GAAI,EAAA,EAAA,CAAA,EAAG,qBACL,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAM,OAAQ,EAAA,EAAA,+BAAA,EACM,MAAM,OACtC,CAAA,sCACC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,KAAM,EAAA,eAAA,EAAA,EAAgB,gDAElD,CACF,CAAA;AAAA;AAIJ,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAA,IAAI,QAAU,EAAA;AACZ,MAAA,iEAAU,QAAS,CAAA;AAAA;AAErB,IACE,uBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,CAAA,EAAG,CACN,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,KAAM,EAAA,eAAA,EAAA,EACf,YAAgB,IAAA,6CACnB,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAA,kBACN,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,SAAA,EAAU,KAAM,EAAA,eAAA,EAAA,EAAgB,uBAC5B,EAAA,UAAA,CAAW,IACnC,CACF,CACF,CAAA;AAAA;AAIJ,EAAA,iEAAU,QAAS,CAAA;AACrB;;;;"}
@@ -30,25 +30,39 @@ const RequestAccessDialog = ({
30
30
  setCreating(true);
31
31
  setCreateError(null);
32
32
  try {
33
- await kuadrantApi.createRequest({
34
- apiProductName,
35
- namespace,
36
- planTier: selectedPlan,
37
- useCase: useCase.trim() || "",
38
- userEmail
39
- });
40
- alertApi.post({
41
- message: "API key requested successfully",
42
- severity: "success",
43
- display: "transient"
44
- });
45
- setSelectedPlan("");
46
- setUseCase("");
47
- onSuccess();
48
- } catch (err) {
49
- const errorMessage = err instanceof Error ? err.message : "unknown error occurred";
33
+ const randomSuffix = Math.random().toString(36).substring(2, 10);
34
+ const secretName = `${apiProductName}-${randomSuffix}-secret`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
35
+ const apiKeyValue = crypto.randomUUID().replace(/-/g, "");
36
+ await kuadrantApi.createSecret(secretName, apiKeyValue);
37
+ try {
38
+ await kuadrantApi.createRequest({
39
+ apiProductName,
40
+ namespace,
41
+ planTier: selectedPlan,
42
+ useCase: useCase.trim() || "",
43
+ userEmail,
44
+ secretName
45
+ });
46
+ alertApi.post({
47
+ message: `Request submitted successfully. Pending API owner approval.`,
48
+ severity: "info",
49
+ display: "transient"
50
+ });
51
+ setSelectedPlan("");
52
+ setUseCase("");
53
+ onSuccess();
54
+ } catch (apiKeyError) {
55
+ try {
56
+ await kuadrantApi.deleteSecret(secretName);
57
+ } catch (deleteError) {
58
+ console.warn("Failed to cleanup orphaned secret:", deleteError);
59
+ }
60
+ throw apiKeyError;
61
+ }
62
+ } catch (error) {
63
+ const errorMessage = error instanceof Error ? error.message : "unknown error occurred";
50
64
  alertApi.post({
51
- message: `Failed to request API key: ${errorMessage}`,
65
+ message: `Failed to create request: ${errorMessage}`,
52
66
  severity: "error",
53
67
  display: "transient"
54
68
  });
@@ -1 +1 @@
1
- {"version":3,"file":"RequestAccessDialog.esm.js","sources":["../../../src/components/RequestAccessDialog/RequestAccessDialog.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Select,\n MenuItem,\n FormControl,\n InputLabel,\n Box,\n Typography,\n CircularProgress,\n} from '@material-ui/core';\nimport InfoIcon from '@material-ui/icons/Info';\nimport {\n useApi,\n alertApiRef,\n} from '@backstage/core-plugin-api';\nimport { kuadrantApiRef } from '../../api';\nimport { Plan } from \"../../types/api-management.ts\";\n\nexport interface RequestAccessDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n apiProductName: string;\n namespace: string;\n userEmail: string;\n plans: Plan[];\n}\n\nexport const RequestAccessDialog = ({\n open,\n onClose,\n onSuccess,\n apiProductName,\n namespace,\n userEmail,\n plans,\n}: RequestAccessDialogProps) => {\n const kuadrantApi = useApi(kuadrantApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [selectedPlan, setSelectedPlan] = useState('');\n const [useCase, setUseCase] = useState('');\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n\n const handleClose = () => {\n setSelectedPlan('');\n setUseCase('');\n setCreateError(null);\n onClose();\n };\n\n const handleRequestAccess = async () => {\n if (!selectedPlan) return;\n\n setCreating(true);\n setCreateError(null);\n try {\n await kuadrantApi.createRequest({\n apiProductName,\n namespace,\n planTier: selectedPlan,\n useCase: useCase.trim() || '',\n userEmail,\n });\n\n alertApi.post({\n message: 'API key requested successfully',\n severity: 'success',\n display: 'transient',\n });\n\n setSelectedPlan('');\n setUseCase('');\n onSuccess();\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : 'unknown error occurred';\n alertApi.post({\n message: `Failed to request API key: ${errorMessage}`,\n severity: 'error',\n display: 'transient',\n });\n setCreateError(errorMessage);\n } finally {\n setCreating(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Request API Access</DialogTitle>\n <DialogContent>\n <Box\n mb={2}\n p={1.5}\n bgcolor=\"info.light\"\n borderRadius={1}\n display=\"flex\"\n alignItems=\"flex-start\"\n style={{ gap: 8 }}\n >\n <InfoIcon\n color=\"primary\"\n fontSize=\"small\"\n style={{ marginTop: 2 }}\n />\n <Typography variant=\"body2\">\n Your request will be reviewed by an API owner before access is\n granted.\n </Typography>\n </Box>\n {createError && (\n <Box\n mb={2}\n p={2}\n bgcolor=\"error.main\"\n color=\"error.contrastText\"\n borderRadius={1}\n >\n <Typography variant=\"body2\">{createError}</Typography>\n </Box>\n )}\n <FormControl\n fullWidth\n margin=\"normal\"\n disabled={creating}\n data-testid=\"tier-select-form\"\n >\n <InputLabel id=\"tier-select-label\">Select Tier</InputLabel>\n <Select\n labelId=\"tier-select-label\"\n data-testid=\"tier-select\"\n value={selectedPlan}\n onChange={(e) => setSelectedPlan(e.target.value as string)}\n disabled={creating}\n >\n {plans.map((plan: Plan) => {\n const limitDesc = Object.entries(plan.limits || {})\n .map(([key, val]) => `${val} per ${key}`)\n .join(', ');\n return (\n <MenuItem\n key={plan.tier}\n value={plan.tier}\n data-testid={`tier-option-${plan.tier}`}\n >\n {plan.tier} {limitDesc ? `(${limitDesc})` : ''}\n </MenuItem>\n );\n })}\n </Select>\n </FormControl>\n <TextField\n label=\"Use Case (optional)\"\n placeholder=\"Describe how you plan to use this API\"\n multiline\n rows={3}\n fullWidth\n margin=\"normal\"\n value={useCase}\n onChange={(e) => setUseCase(e.target.value)}\n helperText=\"Explain your intended use of this API for admin review\"\n disabled={creating}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={creating}>\n Cancel\n </Button>\n <Button\n onClick={handleRequestAccess}\n color=\"primary\"\n variant=\"contained\"\n disabled={!selectedPlan || creating}\n startIcon={\n creating ? (\n <CircularProgress size={16} color=\"inherit\" />\n ) : undefined\n }\n >\n {creating ? 'Submitting...' : 'Submit Request'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RequestAccessDialog.esm.js","sources":["../../../src/components/RequestAccessDialog/RequestAccessDialog.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Select,\n MenuItem,\n FormControl,\n InputLabel,\n Box,\n Typography,\n CircularProgress,\n} from '@material-ui/core';\nimport InfoIcon from '@material-ui/icons/Info';\nimport {\n useApi,\n alertApiRef,\n} from '@backstage/core-plugin-api';\nimport { kuadrantApiRef } from '../../api';\nimport { Plan } from \"../../types/api-management.ts\";\n\nexport interface RequestAccessDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n apiProductName: string;\n namespace: string;\n userEmail: string;\n plans: Plan[];\n}\n\nexport const RequestAccessDialog = ({\n open,\n onClose,\n onSuccess,\n apiProductName,\n namespace,\n userEmail,\n plans,\n}: RequestAccessDialogProps) => {\n const kuadrantApi = useApi(kuadrantApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [selectedPlan, setSelectedPlan] = useState('');\n const [useCase, setUseCase] = useState('');\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n\n const handleClose = () => {\n setSelectedPlan('');\n setUseCase('');\n setCreateError(null);\n onClose();\n };\n\n const handleRequestAccess = async () => {\n if (!selectedPlan) return;\n\n setCreating(true);\n setCreateError(null);\n\n try {\n // 1. generate secret name and API key value\n const randomSuffix = Math.random().toString(36).substring(2, 10);\n const secretName = `${apiProductName}-${randomSuffix}-secret`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n const apiKeyValue = crypto.randomUUID().replace(/-/g, '');\n\n // 2. create secret in consumer's namespace first (design doc: secret before APIKey)\n await kuadrantApi.createSecret(secretName, apiKeyValue);\n\n try {\n // 3. create APIKey referencing the pre-existing secret\n await kuadrantApi.createRequest({\n apiProductName,\n namespace,\n planTier: selectedPlan,\n useCase: useCase.trim() || '',\n userEmail,\n secretName,\n });\n\n alertApi.post({\n message: `Request submitted successfully. Pending API owner approval.`,\n severity: 'info',\n display: 'transient',\n });\n\n setSelectedPlan('');\n setUseCase('');\n onSuccess();\n\n } catch (apiKeyError) {\n // cleanup orphaned secret if APIKey creation fails\n try {\n await kuadrantApi.deleteSecret(secretName);\n } catch (deleteError) {\n console.warn('Failed to cleanup orphaned secret:', deleteError);\n }\n throw apiKeyError;\n }\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'unknown error occurred';\n alertApi.post({\n message: `Failed to create request: ${errorMessage}`,\n severity: 'error',\n display: 'transient',\n });\n setCreateError(errorMessage);\n } finally {\n setCreating(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Request API Access</DialogTitle>\n <DialogContent>\n <Box\n mb={2}\n p={1.5}\n bgcolor=\"info.light\"\n borderRadius={1}\n display=\"flex\"\n alignItems=\"flex-start\"\n style={{ gap: 8 }}\n >\n <InfoIcon\n color=\"primary\"\n fontSize=\"small\"\n style={{ marginTop: 2 }}\n />\n <Typography variant=\"body2\">\n Your request will be reviewed by an API owner before access is\n granted.\n </Typography>\n </Box>\n {createError && (\n <Box\n mb={2}\n p={2}\n bgcolor=\"error.main\"\n color=\"error.contrastText\"\n borderRadius={1}\n >\n <Typography variant=\"body2\">{createError}</Typography>\n </Box>\n )}\n <FormControl\n fullWidth\n margin=\"normal\"\n disabled={creating}\n data-testid=\"tier-select-form\"\n >\n <InputLabel id=\"tier-select-label\">Select Tier</InputLabel>\n <Select\n labelId=\"tier-select-label\"\n data-testid=\"tier-select\"\n value={selectedPlan}\n onChange={(e) => setSelectedPlan(e.target.value as string)}\n disabled={creating}\n >\n {plans.map((plan: Plan) => {\n const limitDesc = Object.entries(plan.limits || {})\n .map(([key, val]) => `${val} per ${key}`)\n .join(', ');\n return (\n <MenuItem\n key={plan.tier}\n value={plan.tier}\n data-testid={`tier-option-${plan.tier}`}\n >\n {plan.tier} {limitDesc ? `(${limitDesc})` : ''}\n </MenuItem>\n );\n })}\n </Select>\n </FormControl>\n <TextField\n label=\"Use Case (optional)\"\n placeholder=\"Describe how you plan to use this API\"\n multiline\n rows={3}\n fullWidth\n margin=\"normal\"\n value={useCase}\n onChange={(e) => setUseCase(e.target.value)}\n helperText=\"Explain your intended use of this API for admin review\"\n disabled={creating}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={creating}>\n Cancel\n </Button>\n <Button\n onClick={handleRequestAccess}\n color=\"primary\"\n variant=\"contained\"\n disabled={!selectedPlan || creating}\n startIcon={\n creating ? (\n <CircularProgress size={16} color=\"inherit\" />\n ) : undefined\n }\n >\n {creating ? 'Submitting...' : 'Submit Request'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
2
2
  import { Dialog, DialogTitle, DialogContent, Typography, FormControl, InputLabel, Select, MenuItem, FormHelperText, TextField, DialogActions, Button, CircularProgress } from '@material-ui/core';
3
3
  import { useApi, configApiRef, fetchApiRef, alertApiRef, identityApiRef } from '@backstage/core-plugin-api';
4
4
  import useAsync from 'react-use/lib/useAsync';
5
+ import { kuadrantApiRef } from '../../api.esm.js';
5
6
 
6
7
  const SimpleRequestAccessDialog = ({
7
8
  open,
@@ -12,6 +13,7 @@ const SimpleRequestAccessDialog = ({
12
13
  const fetchApi = useApi(fetchApiRef);
13
14
  const alertApi = useApi(alertApiRef);
14
15
  const identityApi = useApi(identityApiRef);
16
+ const kuadrantApi = useApi(kuadrantApiRef);
15
17
  const backendUrl = config.getString("backend.baseUrl");
16
18
  const [selectedApi, setSelectedApi] = useState("");
17
19
  const [selectedTier, setSelectedTier] = useState("");
@@ -53,6 +55,12 @@ const SimpleRequestAccessDialog = ({
53
55
  const [namespace, apiProductName] = selectedApi.split("/");
54
56
  setCreating(true);
55
57
  try {
58
+ const identity = await identityApi.getBackstageIdentity();
59
+ const username = identity.userEntityRef.split("/")[1] || "unknown";
60
+ const randomSuffix = Math.random().toString(36).substring(2, 10);
61
+ const secretName = `${username}-${apiProductName}-secret-${randomSuffix}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
62
+ const apiKeyValue = crypto.randomUUID().replace(/-/g, "");
63
+ await kuadrantApi.createSecret(secretName, apiKeyValue);
56
64
  const response = await fetchApi.fetch(
57
65
  `${backendUrl}/api/kuadrant/requests`,
58
66
  {
@@ -65,7 +73,8 @@ const SimpleRequestAccessDialog = ({
65
73
  namespace,
66
74
  planTier: selectedTier,
67
75
  useCase: useCase.trim() || "",
68
- userEmail: userEmail || "unknown"
76
+ userEmail: userEmail || "unknown",
77
+ secretName
69
78
  })
70
79
  }
71
80
  );
@@ -85,7 +94,8 @@ const SimpleRequestAccessDialog = ({
85
94
  namespace,
86
95
  planTier: selectedTier,
87
96
  useCase: useCase.trim() || "",
88
- userEmail: userEmail || "unknown"
97
+ userEmail: userEmail || "unknown",
98
+ secretName: "(generated)"
89
99
  }
90
100
  });
91
101
  const rawError = errorData.error || errorData.message || `Server returned ${response.status}`;
@@ -104,6 +114,7 @@ const SimpleRequestAccessDialog = ({
104
114
  } else if (response.status >= 500) {
105
115
  errorMsg = `Server error: ${rawError}`;
106
116
  }
117
+ await kuadrantApi.deleteSecret(secretName).catch((e) => console.warn("Failed to cleanup orphaned secret:", e));
107
118
  throw new Error(errorMsg);
108
119
  }
109
120
  alertApi.post({
@@ -1 +1 @@
1
- {"version":3,"file":"SimpleRequestAccessDialog.esm.js","sources":["../../../src/components/SimpleRequestAccessDialog/SimpleRequestAccessDialog.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Select,\n MenuItem,\n FormControl,\n InputLabel,\n Typography,\n CircularProgress,\n FormHelperText,\n} from '@material-ui/core';\nimport {\n useApi,\n configApiRef,\n fetchApiRef,\n alertApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\n\nexport interface SimpleRequestAccessDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\ntype ApiProduct = {\n metadata: {\n name: string;\n namespace: string;\n };\n spec?: {\n publishStatus?: string;\n };\n status?: {\n discoveredPlans?: Array<{\n tier: string;\n limits?: Record<string, number>;\n }>;\n };\n};\n\nexport const SimpleRequestAccessDialog = ({\n open,\n onClose,\n onSuccess,\n}: SimpleRequestAccessDialogProps) => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const alertApi = useApi(alertApiRef);\n const identityApi = useApi(identityApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n\n const [selectedApi, setSelectedApi] = useState('');\n const [selectedTier, setSelectedTier] = useState('');\n const [useCase, setUseCase] = useState('');\n const [creating, setCreating] = useState(false);\n\n // Fetch all published API products\n const {\n value: apiProducts,\n loading: loadingProducts,\n } = useAsync(async () => {\n if (!open) return [];\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts`,\n );\n if (!response.ok) {\n throw new Error('Failed to fetch API products');\n }\n const data = await response.json();\n // Filter to only show Published products\n return (data.items || []).filter(\n (p: ApiProduct) => p.spec?.publishStatus === 'Published',\n );\n }, [backendUrl, fetchApi, open]);\n\n // Get user email\n const { value: userEmail } = useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n\n // Extract username from userEntityRef (e.g., \"user:default/john\" -> \"john\")\n const username = identity.userEntityRef.split('/')[1] || 'unknown';\n\n // Construct email from username\n return `${username}@example.com`;\n }, [identityApi]);\n\n // Get available tiers for selected API\n const selectedProduct = apiProducts?.find(\n (p: ApiProduct) =>\n `${p.metadata.namespace}/${p.metadata.name}` === selectedApi,\n );\n const availableTiers = selectedProduct?.status?.discoveredPlans || [];\n\n const handleClose = () => {\n setSelectedApi('');\n setSelectedTier('');\n setUseCase('');\n onClose();\n };\n\n const handleSubmit = async () => {\n if (!selectedApi || !selectedTier) return;\n\n const [namespace, apiProductName] = selectedApi.split('/');\n\n setCreating(true);\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n apiProductName,\n namespace,\n planTier: selectedTier,\n useCase: useCase.trim() || '',\n userEmail: userEmail || 'unknown',\n }),\n },\n );\n\n if (!response.ok) {\n let errorData;\n try {\n errorData = await response.json();\n } catch {\n errorData = { error: `Server returned ${response.status} ${response.statusText}` };\n }\n\n console.error('Backend error response:', {\n status: response.status,\n statusText: response.statusText,\n errorData,\n requestBody: {\n apiProductName,\n namespace,\n planTier: selectedTier,\n useCase: useCase.trim() || '',\n userEmail: userEmail || 'unknown',\n }\n });\n\n // Extract user-friendly error message\n const rawError = errorData.error || errorData.message || `Server returned ${response.status}`;\n\n // Try to extract validation error details from Kubernetes error messages\n // Example: \"failed to create apikeys: APIKey.devportal.kuadrant.io \"name\" is invalid: spec.requestedBy.email: Invalid value: \"admin\": spec.requestedBy.email in body should match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'\"\n let errorMsg = rawError;\n\n if (rawError.includes('spec.requestedBy.email')) {\n errorMsg = 'Invalid email format. Please contact your administrator to update your profile email.';\n } else if (rawError.includes('is invalid:')) {\n // Extract the validation message after \"is invalid:\"\n const match = rawError.match(/is invalid: (.+?)(?:\\s+\\(|$)/);\n if (match) {\n errorMsg = `Validation error: ${match[1]}`;\n }\n } else if (response.status === 403) {\n errorMsg = 'You do not have permission to request access to this API.';\n } else if (response.status === 404) {\n errorMsg = 'The selected API or tier was not found.';\n } else if (response.status >= 500) {\n errorMsg = `Server error: ${rawError}`;\n }\n\n throw new Error(errorMsg);\n }\n\n alertApi.post({\n message: 'API key requested successfully',\n severity: 'success',\n display: 'transient',\n });\n\n handleClose();\n onSuccess();\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : 'unknown error occurred';\n console.error('Failed to create API key request:', {\n error: err,\n selectedApi,\n selectedTier,\n userEmail,\n });\n alertApi.post({\n message: `Failed to request API key: ${errorMessage}`,\n severity: 'error',\n display: 'permanent',\n });\n } finally {\n setCreating(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Request API key</DialogTitle>\n <DialogContent>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Submit your request to generate an API key.\n </Typography>\n\n <FormControl fullWidth margin=\"normal\" disabled={creating || loadingProducts}>\n <InputLabel id=\"api-select-label\" required>\n API\n </InputLabel>\n <Select\n labelId=\"api-select-label\"\n value={selectedApi}\n onChange={e => {\n setSelectedApi(e.target.value as string);\n setSelectedTier(''); // Reset tier when API changes\n }}\n disabled={creating || loadingProducts}\n data-testid=\"api-select\"\n >\n {loadingProducts ? (\n <MenuItem disabled>Loading...</MenuItem>\n ) : (\n apiProducts?.map((product: ApiProduct) => (\n <MenuItem\n key={`${product.metadata.namespace}/${product.metadata.name}`}\n value={`${product.metadata.namespace}/${product.metadata.name}`}\n >\n {product.metadata.name}\n </MenuItem>\n ))\n )}\n </Select>\n <FormHelperText>\n Select one API. Please submit separate requests for multiple APIs.\n </FormHelperText>\n </FormControl>\n\n <FormControl\n fullWidth\n margin=\"normal\"\n disabled={creating || !selectedApi}\n required\n >\n <InputLabel id=\"tier-select-label\">Tiers</InputLabel>\n <Select\n labelId=\"tier-select-label\"\n value={selectedTier}\n onChange={e => setSelectedTier(e.target.value as string)}\n disabled={creating || !selectedApi}\n data-testid=\"tier-select\"\n >\n {!selectedApi ? (\n <MenuItem disabled>Select an API first</MenuItem>\n ) : availableTiers.length === 0 ? (\n <MenuItem disabled>No tiers available</MenuItem>\n ) : (\n availableTiers.map((plan: { tier: string; limits?: Record<string, number> }) => {\n const limitDesc = Object.entries(plan.limits || {})\n .map(([key, val]) => `${val} per ${key}`)\n .join(', ');\n return (\n <MenuItem key={plan.tier} value={plan.tier}>\n {plan.tier} {limitDesc ? `(${limitDesc})` : ''}\n </MenuItem>\n );\n })\n )}\n </Select>\n <FormHelperText>Select an API to view available tiers.</FormHelperText>\n </FormControl>\n\n <TextField\n label=\"Use case\"\n placeholder=\"Briefly describe your specific use case of using this API key\"\n multiline\n rows={2}\n fullWidth\n margin=\"normal\"\n value={useCase}\n onChange={e => setUseCase(e.target.value)}\n disabled={creating}\n inputProps={{ 'data-testid': 'usecase-input' }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={creating} data-testid=\"cancel-button\">\n Cancel\n </Button>\n <Button\n onClick={handleSubmit}\n color=\"primary\"\n variant=\"contained\"\n disabled={!selectedApi || !selectedTier || creating}\n startIcon={\n creating ? (\n <CircularProgress size={16} color=\"inherit\" />\n ) : undefined\n }\n data-testid=\"submit-button\"\n >\n {creating ? 'Submitting...' : 'Request'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SimpleRequestAccessDialog.esm.js","sources":["../../../src/components/SimpleRequestAccessDialog/SimpleRequestAccessDialog.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Select,\n MenuItem,\n FormControl,\n InputLabel,\n Typography,\n CircularProgress,\n FormHelperText,\n} from '@material-ui/core';\nimport {\n useApi,\n configApiRef,\n fetchApiRef,\n alertApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\nimport { kuadrantApiRef } from '../../api';\n\nexport interface SimpleRequestAccessDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\ntype ApiProduct = {\n metadata: {\n name: string;\n namespace: string;\n };\n spec?: {\n publishStatus?: string;\n };\n status?: {\n discoveredPlans?: Array<{\n tier: string;\n limits?: Record<string, number>;\n }>;\n };\n};\n\nexport const SimpleRequestAccessDialog = ({\n open,\n onClose,\n onSuccess,\n}: SimpleRequestAccessDialogProps) => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const alertApi = useApi(alertApiRef);\n const identityApi = useApi(identityApiRef);\n const kuadrantApi = useApi(kuadrantApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n\n const [selectedApi, setSelectedApi] = useState('');\n const [selectedTier, setSelectedTier] = useState('');\n const [useCase, setUseCase] = useState('');\n const [creating, setCreating] = useState(false);\n\n // Fetch all published API products\n const {\n value: apiProducts,\n loading: loadingProducts,\n } = useAsync(async () => {\n if (!open) return [];\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts`,\n );\n if (!response.ok) {\n throw new Error('Failed to fetch API products');\n }\n const data = await response.json();\n // Filter to only show Published products\n return (data.items || []).filter(\n (p: ApiProduct) => p.spec?.publishStatus === 'Published',\n );\n }, [backendUrl, fetchApi, open]);\n\n // Get user email\n const { value: userEmail } = useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n\n // Extract username from userEntityRef (e.g., \"user:default/john\" -> \"john\")\n const username = identity.userEntityRef.split('/')[1] || 'unknown';\n\n // Construct email from username\n return `${username}@example.com`;\n }, [identityApi]);\n\n // Get available tiers for selected API\n const selectedProduct = apiProducts?.find(\n (p: ApiProduct) =>\n `${p.metadata.namespace}/${p.metadata.name}` === selectedApi,\n );\n const availableTiers = selectedProduct?.status?.discoveredPlans || [];\n\n const handleClose = () => {\n setSelectedApi('');\n setSelectedTier('');\n setUseCase('');\n onClose();\n };\n\n const handleSubmit = async () => {\n if (!selectedApi || !selectedTier) return;\n\n const [namespace, apiProductName] = selectedApi.split('/');\n\n setCreating(true);\n try {\n // 1. generate secret name and API key value\n const identity = await identityApi.getBackstageIdentity();\n const username = identity.userEntityRef.split('/')[1] || 'unknown';\n const randomSuffix = Math.random().toString(36).substring(2, 10);\n const secretName = `${username}-${apiProductName}-secret-${randomSuffix}`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n const apiKeyValue = crypto.randomUUID().replace(/-/g, '');\n\n // 2. create secret first (design doc: secret must exist before APIKey)\n await kuadrantApi.createSecret(secretName, apiKeyValue);\n\n // 3. create APIKey referencing the pre-existing secret\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n apiProductName,\n namespace,\n planTier: selectedTier,\n useCase: useCase.trim() || '',\n userEmail: userEmail || 'unknown',\n secretName,\n }),\n },\n );\n\n if (!response.ok) {\n let errorData;\n try {\n errorData = await response.json();\n } catch {\n errorData = { error: `Server returned ${response.status} ${response.statusText}` };\n }\n\n console.error('Backend error response:', {\n status: response.status,\n statusText: response.statusText,\n errorData,\n requestBody: {\n apiProductName,\n namespace,\n planTier: selectedTier,\n useCase: useCase.trim() || '',\n userEmail: userEmail || 'unknown',\n secretName: '(generated)',\n }\n });\n\n // Extract user-friendly error message\n const rawError = errorData.error || errorData.message || `Server returned ${response.status}`;\n\n // Try to extract validation error details from Kubernetes error messages\n // Example: \"failed to create apikeys: APIKey.devportal.kuadrant.io \"name\" is invalid: spec.requestedBy.email: Invalid value: \"admin\": spec.requestedBy.email in body should match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'\"\n let errorMsg = rawError;\n\n if (rawError.includes('spec.requestedBy.email')) {\n errorMsg = 'Invalid email format. Please contact your administrator to update your profile email.';\n } else if (rawError.includes('is invalid:')) {\n // Extract the validation message after \"is invalid:\"\n const match = rawError.match(/is invalid: (.+?)(?:\\s+\\(|$)/);\n if (match) {\n errorMsg = `Validation error: ${match[1]}`;\n }\n } else if (response.status === 403) {\n errorMsg = 'You do not have permission to request access to this API.';\n } else if (response.status === 404) {\n errorMsg = 'The selected API or tier was not found.';\n } else if (response.status >= 500) {\n errorMsg = `Server error: ${rawError}`;\n }\n\n // cleanup orphaned secret since APIKey creation failed\n await kuadrantApi.deleteSecret(secretName)\n .catch(e => console.warn('Failed to cleanup orphaned secret:', e));\n\n throw new Error(errorMsg);\n }\n\n alertApi.post({\n message: 'API key requested successfully',\n severity: 'success',\n display: 'transient',\n });\n\n handleClose();\n onSuccess();\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : 'unknown error occurred';\n console.error('Failed to create API key request:', {\n error: err,\n selectedApi,\n selectedTier,\n userEmail,\n });\n alertApi.post({\n message: `Failed to request API key: ${errorMessage}`,\n severity: 'error',\n display: 'permanent',\n });\n } finally {\n setCreating(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Request API key</DialogTitle>\n <DialogContent>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Submit your request to generate an API key.\n </Typography>\n\n <FormControl fullWidth margin=\"normal\" disabled={creating || loadingProducts}>\n <InputLabel id=\"api-select-label\" required>\n API\n </InputLabel>\n <Select\n labelId=\"api-select-label\"\n value={selectedApi}\n onChange={e => {\n setSelectedApi(e.target.value as string);\n setSelectedTier(''); // Reset tier when API changes\n }}\n disabled={creating || loadingProducts}\n data-testid=\"api-select\"\n >\n {loadingProducts ? (\n <MenuItem disabled>Loading...</MenuItem>\n ) : (\n apiProducts?.map((product: ApiProduct) => (\n <MenuItem\n key={`${product.metadata.namespace}/${product.metadata.name}`}\n value={`${product.metadata.namespace}/${product.metadata.name}`}\n >\n {product.metadata.name}\n </MenuItem>\n ))\n )}\n </Select>\n <FormHelperText>\n Select one API. Please submit separate requests for multiple APIs.\n </FormHelperText>\n </FormControl>\n\n <FormControl\n fullWidth\n margin=\"normal\"\n disabled={creating || !selectedApi}\n required\n >\n <InputLabel id=\"tier-select-label\">Tiers</InputLabel>\n <Select\n labelId=\"tier-select-label\"\n value={selectedTier}\n onChange={e => setSelectedTier(e.target.value as string)}\n disabled={creating || !selectedApi}\n data-testid=\"tier-select\"\n >\n {!selectedApi ? (\n <MenuItem disabled>Select an API first</MenuItem>\n ) : availableTiers.length === 0 ? (\n <MenuItem disabled>No tiers available</MenuItem>\n ) : (\n availableTiers.map((plan: { tier: string; limits?: Record<string, number> }) => {\n const limitDesc = Object.entries(plan.limits || {})\n .map(([key, val]) => `${val} per ${key}`)\n .join(', ');\n return (\n <MenuItem key={plan.tier} value={plan.tier}>\n {plan.tier} {limitDesc ? `(${limitDesc})` : ''}\n </MenuItem>\n );\n })\n )}\n </Select>\n <FormHelperText>Select an API to view available tiers.</FormHelperText>\n </FormControl>\n\n <TextField\n label=\"Use case\"\n placeholder=\"Briefly describe your specific use case of using this API key\"\n multiline\n rows={2}\n fullWidth\n margin=\"normal\"\n value={useCase}\n onChange={e => setUseCase(e.target.value)}\n disabled={creating}\n inputProps={{ 'data-testid': 'usecase-input' }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={creating} data-testid=\"cancel-button\">\n Cancel\n </Button>\n <Button\n onClick={handleSubmit}\n color=\"primary\"\n variant=\"contained\"\n disabled={!selectedApi || !selectedTier || creating}\n startIcon={\n creating ? (\n <CircularProgress size={16} color=\"inherit\" />\n ) : undefined\n }\n data-testid=\"submit-button\"\n >\n {creating ? 'Submitting...' : 'Request'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}