@kuadrant/kuadrant-backstage-plugin-frontend 0.0.2-dev-83763ff → 0.0.2-dev-b696169

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 (91) hide show
  1. package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js +319 -0
  2. package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js.map +1 -0
  3. package/dist/components/ApiKeyDetailPage/index.esm.js +2 -0
  4. package/dist/components/ApiKeyDetailPage/index.esm.js.map +1 -0
  5. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js +340 -162
  6. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js.map +1 -1
  7. package/dist/components/ApiKeysPage/ApiKeysPage.esm.js +43 -0
  8. package/dist/components/ApiKeysPage/ApiKeysPage.esm.js.map +1 -0
  9. package/dist/components/ApiKeysPage/index.esm.js +2 -0
  10. package/dist/components/ApiKeysPage/index.esm.js.map +1 -0
  11. package/dist/components/ApprovalQueueCard/ApprovalQueueCard.esm.js +312 -118
  12. package/dist/components/ApprovalQueueCard/ApprovalQueueCard.esm.js.map +1 -1
  13. package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js +645 -0
  14. package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js.map +1 -0
  15. package/dist/components/EditAPIKeyDialog/EditAPIKeyDialog.esm.js +14 -2
  16. package/dist/components/EditAPIKeyDialog/EditAPIKeyDialog.esm.js.map +1 -1
  17. package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js +276 -0
  18. package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js.map +1 -0
  19. package/dist/components/EntityApiApprovalTab/index.esm.js +2 -0
  20. package/dist/components/EntityApiApprovalTab/index.esm.js.map +1 -0
  21. package/dist/components/FilterPanel/FilterPanel.esm.js +127 -0
  22. package/dist/components/FilterPanel/FilterPanel.esm.js.map +1 -0
  23. package/dist/components/KuadrantPage/KuadrantPage.esm.js +123 -40
  24. package/dist/components/KuadrantPage/KuadrantPage.esm.js.map +1 -1
  25. package/dist/components/KuadrantPage/index.esm.js +1 -1
  26. package/dist/components/{MyApiKeysCard/MyApiKeysCard.esm.js → MyApiKeysTable/MyApiKeysTable.esm.js} +294 -176
  27. package/dist/components/MyApiKeysTable/MyApiKeysTable.esm.js.map +1 -0
  28. package/dist/components/PlanPolicyDetailsCard/PlanPolicyDetails.esm.js +5 -4
  29. package/dist/components/PlanPolicyDetailsCard/PlanPolicyDetails.esm.js.map +1 -1
  30. package/dist/index.d.ts +8 -4
  31. package/dist/index.esm.js +1 -1
  32. package/dist/plugin.esm.js +30 -1
  33. package/dist/plugin.esm.js.map +1 -1
  34. package/dist/utils/styles.esm.js +14 -0
  35. package/dist/utils/styles.esm.js.map +1 -0
  36. package/dist-scalprum/{internal.plugin-kuadrant.6dd50c0e0265251d3d4f.js → internal.plugin-kuadrant.e37d8046ec4d7ed991e0.js} +2 -2
  37. package/dist-scalprum/internal.plugin-kuadrant.e37d8046ec4d7ed991e0.js.map +1 -0
  38. package/dist-scalprum/plugin-manifest.json +2 -2
  39. package/dist-scalprum/static/2967.c684efaf.chunk.js +2 -0
  40. package/dist-scalprum/static/2967.c684efaf.chunk.js.map +1 -0
  41. package/dist-scalprum/static/3097.4bd6b35f.chunk.js +2 -0
  42. package/dist-scalprum/static/3097.4bd6b35f.chunk.js.map +1 -0
  43. package/dist-scalprum/static/4306.3a218ff1.chunk.js +2 -0
  44. package/dist-scalprum/static/4306.3a218ff1.chunk.js.map +1 -0
  45. package/dist-scalprum/static/5010.acf9a415.chunk.js +3 -0
  46. package/dist-scalprum/static/5010.acf9a415.chunk.js.map +1 -0
  47. package/dist-scalprum/static/5453.ae292ab1.chunk.js +2 -0
  48. package/dist-scalprum/static/5453.ae292ab1.chunk.js.map +1 -0
  49. package/dist-scalprum/static/6800.736d5da3.chunk.js +2 -0
  50. package/dist-scalprum/static/6800.736d5da3.chunk.js.map +1 -0
  51. package/dist-scalprum/static/6813.036a322f.chunk.js +2 -0
  52. package/dist-scalprum/static/6813.036a322f.chunk.js.map +1 -0
  53. package/dist-scalprum/static/6840.4728fab9.chunk.js +2 -0
  54. package/dist-scalprum/static/6840.4728fab9.chunk.js.map +1 -0
  55. package/dist-scalprum/static/6979.9699b350.chunk.js +2 -0
  56. package/dist-scalprum/static/6979.9699b350.chunk.js.map +1 -0
  57. package/dist-scalprum/static/7684.3d1fc1a1.chunk.js +2 -0
  58. package/dist-scalprum/static/7684.3d1fc1a1.chunk.js.map +1 -0
  59. package/dist-scalprum/static/8365.d3360f18.chunk.js +2 -0
  60. package/dist-scalprum/static/8365.d3360f18.chunk.js.map +1 -0
  61. package/dist-scalprum/static/8416.3604a311.chunk.js +2 -0
  62. package/dist-scalprum/static/8416.3604a311.chunk.js.map +1 -0
  63. package/dist-scalprum/static/8563.7e068fb0.chunk.js +3 -0
  64. package/dist-scalprum/static/8563.7e068fb0.chunk.js.map +1 -0
  65. package/dist-scalprum/static/exposed-PluginRoot.0717f1ce.chunk.js +2 -0
  66. package/dist-scalprum/static/exposed-PluginRoot.0717f1ce.chunk.js.map +1 -0
  67. package/package.json +1 -1
  68. package/dist/components/MyApiKeysCard/MyApiKeysCard.esm.js.map +0 -1
  69. package/dist-scalprum/internal.plugin-kuadrant.6dd50c0e0265251d3d4f.js.map +0 -1
  70. package/dist-scalprum/static/3483.2f14a8ca.chunk.js +0 -3
  71. package/dist-scalprum/static/3483.2f14a8ca.chunk.js.map +0 -1
  72. package/dist-scalprum/static/4306.b68910c9.chunk.js +0 -2
  73. package/dist-scalprum/static/4306.b68910c9.chunk.js.map +0 -1
  74. package/dist-scalprum/static/4556.c6bedfc4.chunk.js +0 -3
  75. package/dist-scalprum/static/4556.c6bedfc4.chunk.js.map +0 -1
  76. package/dist-scalprum/static/5222.796292ca.chunk.js +0 -2
  77. package/dist-scalprum/static/5222.796292ca.chunk.js.map +0 -1
  78. package/dist-scalprum/static/532.e406b85b.chunk.js +0 -2
  79. package/dist-scalprum/static/532.e406b85b.chunk.js.map +0 -1
  80. package/dist-scalprum/static/5453.29118045.chunk.js +0 -2
  81. package/dist-scalprum/static/5453.29118045.chunk.js.map +0 -1
  82. package/dist-scalprum/static/6281.eb6e16a2.chunk.js +0 -2
  83. package/dist-scalprum/static/6281.eb6e16a2.chunk.js.map +0 -1
  84. package/dist-scalprum/static/8365.75ea3581.chunk.js +0 -2
  85. package/dist-scalprum/static/8365.75ea3581.chunk.js.map +0 -1
  86. package/dist-scalprum/static/8441.62394cfd.chunk.js +0 -2
  87. package/dist-scalprum/static/8441.62394cfd.chunk.js.map +0 -1
  88. package/dist-scalprum/static/exposed-PluginRoot.7023ce03.chunk.js +0 -2
  89. package/dist-scalprum/static/exposed-PluginRoot.7023ce03.chunk.js.map +0 -1
  90. /package/dist-scalprum/static/{4556.c6bedfc4.chunk.js.LICENSE.txt → 5010.acf9a415.chunk.js.LICENSE.txt} +0 -0
  91. /package/dist-scalprum/static/{3483.2f14a8ca.chunk.js.LICENSE.txt → 8563.7e068fb0.chunk.js.LICENSE.txt} +0 -0
@@ -0,0 +1,319 @@
1
+ import React, { useState } from 'react';
2
+ import { useParams } from 'react-router-dom';
3
+ import { useApi, configApiRef, fetchApiRef, alertApiRef } from '@backstage/core-plugin-api';
4
+ import { useAsync } from 'react-use';
5
+ import { Progress, ResponseErrorPanel, Page, Header, Link, Content, Breadcrumbs, InfoCard } from '@backstage/core-components';
6
+ import { makeStyles, Button, Box, Typography, Grid, Chip, Tooltip, IconButton, Tabs, Tab, Dialog, DialogTitle, DialogContent, DialogActions } from '@material-ui/core';
7
+ import VisibilityIcon from '@material-ui/icons/Visibility';
8
+ import VisibilityOffIcon from '@material-ui/icons/VisibilityOff';
9
+ import FileCopyIcon from '@material-ui/icons/FileCopy';
10
+ import WarningIcon from '@material-ui/icons/Warning';
11
+ import ArrowBackIcon from '@material-ui/icons/ArrowBack';
12
+ import OpenInNewIcon from '@material-ui/icons/OpenInNew';
13
+ import EmailIcon from '@material-ui/icons/Email';
14
+ import { getStatusChipStyle } from '../../utils/styles.esm.js';
15
+
16
+ const useStyles = makeStyles((theme) => ({
17
+ label: {
18
+ fontWeight: 600,
19
+ color: theme.palette.text.secondary,
20
+ marginBottom: theme.spacing(0.5)
21
+ },
22
+ value: {
23
+ marginBottom: theme.spacing(2)
24
+ },
25
+ codeBlock: {
26
+ backgroundColor: theme.palette.background.default,
27
+ padding: theme.spacing(2),
28
+ borderRadius: theme.shape.borderRadius,
29
+ fontFamily: "monospace",
30
+ fontSize: "0.875rem",
31
+ overflow: "auto",
32
+ whiteSpace: "pre-wrap",
33
+ wordBreak: "break-all"
34
+ },
35
+ apiKeyContainer: {
36
+ display: "flex",
37
+ alignItems: "center",
38
+ gap: theme.spacing(1),
39
+ padding: theme.spacing(1.5),
40
+ backgroundColor: theme.palette.background.default,
41
+ borderRadius: theme.shape.borderRadius,
42
+ fontFamily: "monospace"
43
+ },
44
+ tabPanel: {
45
+ marginTop: theme.spacing(2)
46
+ }
47
+ }));
48
+ const CodeExample = ({
49
+ code,
50
+ onCopy
51
+ }) => {
52
+ const classes = useStyles();
53
+ return /* @__PURE__ */ React.createElement(Box, { position: "relative" }, /* @__PURE__ */ React.createElement(Box, { className: classes.codeBlock }, code), /* @__PURE__ */ React.createElement(Tooltip, { title: "Copy code" }, /* @__PURE__ */ React.createElement(
54
+ IconButton,
55
+ {
56
+ size: "small",
57
+ style: { position: "absolute", top: 8, right: 8 },
58
+ onClick: onCopy
59
+ },
60
+ /* @__PURE__ */ React.createElement(FileCopyIcon, { fontSize: "small" })
61
+ )));
62
+ };
63
+ const ApiKeyDetailPage = () => {
64
+ const classes = useStyles();
65
+ const { namespace, name } = useParams();
66
+ const config = useApi(configApiRef);
67
+ const fetchApi = useApi(fetchApiRef);
68
+ const alertApi = useApi(alertApiRef);
69
+ const backendUrl = config.getString("backend.baseUrl");
70
+ const [selectedTab, setSelectedTab] = useState(0);
71
+ const [showApiKey, setShowApiKey] = useState(false);
72
+ const [apiKeyValue, setApiKeyValue] = useState(null);
73
+ const [apiKeyLoading, setApiKeyLoading] = useState(false);
74
+ const [alreadyRead, setAlreadyRead] = useState(false);
75
+ const [showWarning, setShowWarning] = useState(false);
76
+ const {
77
+ value: data,
78
+ loading,
79
+ error
80
+ } = useAsync(async () => {
81
+ const [apiKeyResponse, productsResponse] = await Promise.all([
82
+ fetchApi.fetch(`${backendUrl}/api/kuadrant/apikeys/${namespace}/${name}`),
83
+ fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`)
84
+ ]);
85
+ if (!apiKeyResponse.ok) {
86
+ throw new Error("Failed to fetch API key");
87
+ }
88
+ const apiKeyData = await apiKeyResponse.json();
89
+ if (apiKeyData.status?.canReadSecret === false) {
90
+ setAlreadyRead(true);
91
+ }
92
+ let apiProduct2;
93
+ if (productsResponse.ok) {
94
+ const productsData = await productsResponse.json();
95
+ apiProduct2 = (productsData.items || []).find(
96
+ (p) => p.metadata.name === apiKeyData.spec.apiProductRef?.name && p.metadata.namespace === apiKeyData.metadata.namespace
97
+ );
98
+ }
99
+ return { apiKey: apiKeyData, apiProduct: apiProduct2 };
100
+ }, [namespace, name, backendUrl, fetchApi]);
101
+ const apiKey = data?.apiKey;
102
+ const apiProduct = data?.apiProduct;
103
+ const fetchApiKeySecret = async () => {
104
+ setApiKeyLoading(true);
105
+ try {
106
+ const response = await fetchApi.fetch(
107
+ `${backendUrl}/api/kuadrant/apikeys/${namespace}/${name}/secret`
108
+ );
109
+ if (response.ok) {
110
+ const data2 = await response.json();
111
+ setApiKeyValue(data2.apiKey);
112
+ setAlreadyRead(true);
113
+ setShowApiKey(true);
114
+ } else if (response.status === 403) {
115
+ setAlreadyRead(true);
116
+ alertApi.post({
117
+ message: "This API key has already been viewed and cannot be retrieved again.",
118
+ severity: "warning",
119
+ display: "transient"
120
+ });
121
+ }
122
+ } catch (err) {
123
+ console.error("Failed to fetch API key:", err);
124
+ alertApi.post({
125
+ message: "Failed to fetch API key",
126
+ severity: "error",
127
+ display: "transient"
128
+ });
129
+ } finally {
130
+ setApiKeyLoading(false);
131
+ }
132
+ };
133
+ const handleRevealClick = () => {
134
+ if (showApiKey) {
135
+ setShowApiKey(false);
136
+ setApiKeyValue(null);
137
+ } else if (!alreadyRead) {
138
+ setShowWarning(true);
139
+ }
140
+ };
141
+ const handleConfirmReveal = () => {
142
+ setShowWarning(false);
143
+ fetchApiKeySecret();
144
+ };
145
+ const handleCopy = async (text) => {
146
+ await navigator.clipboard.writeText(text);
147
+ alertApi.post({
148
+ message: "Copied to clipboard",
149
+ severity: "success",
150
+ display: "transient"
151
+ });
152
+ };
153
+ if (loading) {
154
+ return /* @__PURE__ */ React.createElement(Progress, null);
155
+ }
156
+ if (error || !apiKey) {
157
+ return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error: error || new Error("API key not found") });
158
+ }
159
+ const phase = apiKey.status?.phase || "Pending";
160
+ const statusLabel = phase === "Approved" ? "Active" : phase;
161
+ const hostname = apiKey.status?.apiHostname || "api.example.com";
162
+ const displayApiKey = apiKeyValue || "<your-api-key>";
163
+ const curlExample = `curl -H "Authorization: Bearer ${displayApiKey}" \\
164
+ https://${hostname}/`;
165
+ const nodeExample = `const response = await fetch('https://${hostname}/', {
166
+ headers: {
167
+ 'Authorization': 'Bearer ${displayApiKey}'
168
+ }
169
+ });
170
+ const data = await response.json();`;
171
+ const pythonExample = `import requests
172
+
173
+ response = requests.get(
174
+ 'https://${hostname}/',
175
+ headers={'Authorization': 'Bearer ${displayApiKey}'}
176
+ )
177
+ data = response.json()`;
178
+ const goExample = `package main
179
+
180
+ import (
181
+ "net/http"
182
+ )
183
+
184
+ func main() {
185
+ client := &http.Client{}
186
+ req, _ := http.NewRequest("GET", "https://${hostname}/", nil)
187
+ req.Header.Set("Authorization", "Bearer ${displayApiKey}")
188
+ resp, _ := client.Do(req)
189
+ defer resp.Body.Close()
190
+ }`;
191
+ const codeExamples = [
192
+ { label: "cURL", code: curlExample },
193
+ { label: "Node.js", code: nodeExample },
194
+ { label: "Python", code: pythonExample },
195
+ { label: "Go", code: goExample }
196
+ ];
197
+ return /* @__PURE__ */ React.createElement(Page, { themeId: "tool" }, /* @__PURE__ */ React.createElement(
198
+ Header,
199
+ {
200
+ title: apiKey.metadata.name,
201
+ subtitle: `API Key for ${apiKey.spec.apiProductRef?.name || "unknown"}`
202
+ },
203
+ /* @__PURE__ */ React.createElement(Link, { to: "/kuadrant/api-keys" }, /* @__PURE__ */ React.createElement(Button, { startIcon: /* @__PURE__ */ React.createElement(ArrowBackIcon, null) }, "Back to API Keys"))
204
+ ), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(Box, { mb: 2 }, /* @__PURE__ */ React.createElement(Breadcrumbs, { "aria-label": "breadcrumb" }, /* @__PURE__ */ React.createElement(Link, { to: "/kuadrant/api-keys" }, "API keys"), /* @__PURE__ */ React.createElement(Typography, null, apiKey.metadata.name))), /* @__PURE__ */ React.createElement(Box, { mb: 3, display: "flex", style: { gap: 8 } }, /* @__PURE__ */ React.createElement(Link, { to: `/catalog/default/api/${apiKey.spec.apiProductRef?.name}` }, /* @__PURE__ */ React.createElement(
205
+ Button,
206
+ {
207
+ variant: "outlined",
208
+ startIcon: /* @__PURE__ */ React.createElement(OpenInNewIcon, null),
209
+ "data-testid": "view-api-button"
210
+ },
211
+ "View API"
212
+ )), apiProduct?.spec?.contact && (apiProduct.spec.contact.email || apiProduct.spec.contact.url || apiProduct.spec.contact.slack) && /* @__PURE__ */ React.createElement(
213
+ Button,
214
+ {
215
+ variant: "outlined",
216
+ startIcon: /* @__PURE__ */ React.createElement(EmailIcon, null),
217
+ href: apiProduct.spec.contact.email ? `mailto:${apiProduct.spec.contact.email}` : apiProduct.spec.contact.slack ? apiProduct.spec.contact.slack : apiProduct.spec.contact.url || "#",
218
+ target: "_blank",
219
+ rel: "noopener noreferrer"
220
+ },
221
+ "Contact Owner"
222
+ )), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(InfoCard, { title: "API Key Details" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Status"), /* @__PURE__ */ React.createElement(Box, { className: classes.value }, /* @__PURE__ */ React.createElement(
223
+ Chip,
224
+ {
225
+ label: statusLabel,
226
+ size: "small",
227
+ style: getStatusChipStyle(phase),
228
+ "data-testid": "api-key-status-chip"
229
+ }
230
+ )), /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "API Product"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1", className: classes.value }, /* @__PURE__ */ React.createElement(
231
+ Link,
232
+ {
233
+ to: `/catalog/default/api/${apiKey.spec.apiProductRef?.name}/api-keys`
234
+ },
235
+ apiKey.spec.apiProductRef?.name || "unknown"
236
+ )), /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Tier"), /* @__PURE__ */ React.createElement(Box, { className: classes.value }, /* @__PURE__ */ React.createElement(
237
+ Chip,
238
+ {
239
+ label: apiKey.spec.planTier,
240
+ size: "small",
241
+ variant: "outlined"
242
+ }
243
+ )), /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Requester"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1", className: classes.value }, apiKey.spec.requestedBy?.userId), /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Requested"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1", className: classes.value }, apiKey.metadata.creationTimestamp ? new Date(
244
+ apiKey.metadata.creationTimestamp
245
+ ).toLocaleDateString() : "-"), apiKey.status?.reviewedBy && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Reviewed By"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1", className: classes.value }, apiKey.status.reviewedBy.replace(/^user:default\//, ""), apiKey.status.reviewedAt && /* @__PURE__ */ React.createElement(Typography, { variant: "caption", color: "textSecondary" }, " ", "on", " ", new Date(
246
+ apiKey.status.reviewedAt
247
+ ).toLocaleDateString())))))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(InfoCard, { title: "Use Case" }, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, apiKey.spec.useCase || "No use case provided")), phase === "Approved" && /* @__PURE__ */ React.createElement(Box, { mt: 2 }, /* @__PURE__ */ React.createElement(InfoCard, { title: "API Key" }, alreadyRead && !apiKeyValue ? /* @__PURE__ */ React.createElement(Tooltip, { title: "This API key has already been viewed and cannot be retrieved again" }, /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "textSecondary" }, "Already viewed - cannot be retrieved again"), /* @__PURE__ */ React.createElement(
248
+ VisibilityOffIcon,
249
+ {
250
+ fontSize: "small",
251
+ color: "disabled",
252
+ style: { marginLeft: 8 }
253
+ }
254
+ ))) : /* @__PURE__ */ React.createElement(Box, { className: classes.apiKeyContainer }, /* @__PURE__ */ React.createElement(
255
+ Typography,
256
+ {
257
+ variant: "body2",
258
+ style: { fontFamily: "monospace", flex: 1 }
259
+ },
260
+ apiKeyLoading ? "Loading..." : showApiKey && apiKeyValue ? apiKeyValue : "\u2022".repeat(32)
261
+ ), showApiKey && apiKeyValue && /* @__PURE__ */ React.createElement(Tooltip, { title: "Copy to clipboard" }, /* @__PURE__ */ React.createElement(
262
+ IconButton,
263
+ {
264
+ size: "small",
265
+ onClick: () => handleCopy(apiKeyValue)
266
+ },
267
+ /* @__PURE__ */ React.createElement(FileCopyIcon, { fontSize: "small" })
268
+ )), /* @__PURE__ */ React.createElement(
269
+ Tooltip,
270
+ {
271
+ title: showApiKey ? "Hide API key" : "Reveal API key (one-time only)"
272
+ },
273
+ /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement(
274
+ IconButton,
275
+ {
276
+ size: "small",
277
+ onClick: handleRevealClick,
278
+ disabled: apiKeyLoading || alreadyRead && !apiKeyValue
279
+ },
280
+ showApiKey ? /* @__PURE__ */ React.createElement(VisibilityOffIcon, { fontSize: "small" }) : /* @__PURE__ */ React.createElement(VisibilityIcon, { fontSize: "small" })
281
+ ))
282
+ ))))), phase === "Approved" && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(InfoCard, { title: "Code Examples" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
283
+ Tabs,
284
+ {
285
+ value: selectedTab,
286
+ onChange: (_, newValue) => setSelectedTab(newValue),
287
+ indicatorColor: "primary",
288
+ textColor: "primary"
289
+ },
290
+ codeExamples.map((ex) => /* @__PURE__ */ React.createElement(Tab, { key: ex.label, label: ex.label }))
291
+ ), /* @__PURE__ */ React.createElement(Box, { className: classes.tabPanel }, /* @__PURE__ */ React.createElement(
292
+ CodeExample,
293
+ {
294
+ code: codeExamples[selectedTab].code,
295
+ onCopy: () => handleCopy(codeExamples[selectedTab].code)
296
+ }
297
+ ))))), apiKey.status?.limits && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(InfoCard, { title: "Rate Limits" }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, apiKey.status.limits.daily && /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Daily"), /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, apiKey.status.limits.daily.toLocaleString())), apiKey.status.limits.weekly && /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Weekly"), /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, apiKey.status.limits.weekly.toLocaleString())), apiKey.status.limits.monthly && /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Monthly"), /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, apiKey.status.limits.monthly.toLocaleString()))))))), /* @__PURE__ */ React.createElement(
298
+ Dialog,
299
+ {
300
+ open: showWarning,
301
+ onClose: () => setShowWarning(false),
302
+ maxWidth: "sm"
303
+ },
304
+ /* @__PURE__ */ React.createElement(DialogTitle, null, /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(WarningIcon, { color: "primary", style: { marginRight: 8 } }), "View API Key")),
305
+ /* @__PURE__ */ React.createElement(DialogContent, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body1", paragraph: true }, "This API key can only be viewed ", /* @__PURE__ */ React.createElement("strong", null, "once"), ". After you reveal it, you will not be able to retrieve it again."), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "textSecondary" }, "Make sure to copy and store it securely before closing this view.")),
306
+ /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(Button, { onClick: () => setShowWarning(false) }, "Cancel"), /* @__PURE__ */ React.createElement(
307
+ Button,
308
+ {
309
+ variant: "contained",
310
+ color: "primary",
311
+ onClick: handleConfirmReveal
312
+ },
313
+ "Reveal API Key"
314
+ ))
315
+ ));
316
+ };
317
+
318
+ export { ApiKeyDetailPage };
319
+ //# sourceMappingURL=ApiKeyDetailPage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiKeyDetailPage.esm.js","sources":["../../../src/components/ApiKeyDetailPage/ApiKeyDetailPage.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport {\n useApi,\n configApiRef,\n fetchApiRef,\n alertApiRef,\n} from \"@backstage/core-plugin-api\";\nimport { useAsync } from \"react-use\";\nimport {\n Header,\n Page,\n Content,\n Progress,\n ResponseErrorPanel,\n InfoCard,\n Link,\n Breadcrumbs,\n} from \"@backstage/core-components\";\nimport {\n Box,\n Grid,\n Typography,\n Chip,\n IconButton,\n Tooltip,\n Tabs,\n Tab,\n Button,\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n makeStyles,\n} from \"@material-ui/core\";\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 ArrowBackIcon from \"@material-ui/icons/ArrowBack\";\nimport OpenInNewIcon from \"@material-ui/icons/OpenInNew\";\nimport EmailIcon from \"@material-ui/icons/Email\";\nimport { APIKey, APIProduct } from \"../../types/api-management\";\nimport { getStatusChipStyle } from \"../../utils/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n label: {\n fontWeight: 600,\n color: theme.palette.text.secondary,\n marginBottom: theme.spacing(0.5),\n },\n value: {\n marginBottom: theme.spacing(2),\n },\n codeBlock: {\n backgroundColor: theme.palette.background.default,\n padding: theme.spacing(2),\n borderRadius: theme.shape.borderRadius,\n fontFamily: \"monospace\",\n fontSize: \"0.875rem\",\n overflow: \"auto\",\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-all\",\n },\n apiKeyContainer: {\n display: \"flex\",\n alignItems: \"center\",\n gap: theme.spacing(1),\n padding: theme.spacing(1.5),\n backgroundColor: theme.palette.background.default,\n borderRadius: theme.shape.borderRadius,\n fontFamily: \"monospace\",\n },\n tabPanel: {\n marginTop: theme.spacing(2),\n },\n}));\n\nconst CodeExample = ({\n code,\n onCopy,\n}: {\n code: string;\n onCopy: () => void;\n}) => {\n const classes = useStyles();\n\n return (\n <Box position=\"relative\">\n <Box className={classes.codeBlock}>{code}</Box>\n <Tooltip title=\"Copy code\">\n <IconButton\n size=\"small\"\n style={{ position: \"absolute\", top: 8, right: 8 }}\n onClick={onCopy}\n >\n <FileCopyIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </Box>\n );\n};\n\nexport const ApiKeyDetailPage = () => {\n const classes = useStyles();\n const { namespace, name } = useParams<{ namespace: string; name: string }>();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const alertApi = useApi(alertApiRef);\n const backendUrl = config.getString(\"backend.baseUrl\");\n\n const [selectedTab, setSelectedTab] = useState(0);\n const [showApiKey, setShowApiKey] = useState(false);\n const [apiKeyValue, setApiKeyValue] = useState<string | null>(null);\n const [apiKeyLoading, setApiKeyLoading] = useState(false);\n const [alreadyRead, setAlreadyRead] = useState(false);\n const [showWarning, setShowWarning] = useState(false);\n\n const {\n value: data,\n loading,\n error,\n } = useAsync(async () => {\n const [apiKeyResponse, productsResponse] = await Promise.all([\n fetchApi.fetch(`${backendUrl}/api/kuadrant/apikeys/${namespace}/${name}`),\n fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`),\n ]);\n\n if (!apiKeyResponse.ok) {\n throw new Error(\"Failed to fetch API key\");\n }\n const apiKeyData = await apiKeyResponse.json();\n\n // check if key has already been read\n if (apiKeyData.status?.canReadSecret === false) {\n setAlreadyRead(true);\n }\n\n // find matching api product to get contact info\n let apiProduct: APIProduct | undefined;\n if (productsResponse.ok) {\n const productsData = await productsResponse.json();\n apiProduct = (productsData.items || []).find(\n (p: APIProduct) =>\n p.metadata.name === apiKeyData.spec.apiProductRef?.name &&\n p.metadata.namespace === apiKeyData.metadata.namespace,\n );\n }\n\n return { apiKey: apiKeyData as APIKey, apiProduct };\n }, [namespace, name, backendUrl, fetchApi]);\n\n const apiKey = data?.apiKey;\n const apiProduct = data?.apiProduct;\n\n const fetchApiKeySecret = async () => {\n setApiKeyLoading(true);\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apikeys/${namespace}/${name}/secret`,\n );\n if (response.ok) {\n const data = await response.json();\n setApiKeyValue(data.apiKey);\n setAlreadyRead(true);\n setShowApiKey(true);\n } else if (response.status === 403) {\n setAlreadyRead(true);\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 }\n } catch (err) {\n console.error(\"Failed to fetch API key:\", err);\n alertApi.post({\n message: \"Failed to fetch API key\",\n severity: \"error\",\n display: \"transient\",\n });\n } finally {\n setApiKeyLoading(false);\n }\n };\n\n const handleRevealClick = () => {\n if (showApiKey) {\n setShowApiKey(false);\n setApiKeyValue(null);\n } else if (!alreadyRead) {\n setShowWarning(true);\n }\n };\n\n const handleConfirmReveal = () => {\n setShowWarning(false);\n fetchApiKeySecret();\n };\n\n const handleCopy = async (text: string) => {\n await navigator.clipboard.writeText(text);\n alertApi.post({\n message: \"Copied to clipboard\",\n severity: \"success\",\n display: \"transient\",\n });\n };\n\n if (loading) {\n return <Progress />;\n }\n\n if (error || !apiKey) {\n return (\n <ResponseErrorPanel error={error || new Error(\"API key not found\")} />\n );\n }\n\n const phase = apiKey.status?.phase || \"Pending\";\n const statusLabel = phase === \"Approved\" ? \"Active\" : phase;\n const hostname = apiKey.status?.apiHostname || \"api.example.com\";\n const displayApiKey = apiKeyValue || \"<your-api-key>\";\n\n // code examples\n const curlExample = `curl -H \"Authorization: Bearer ${displayApiKey}\" \\\\\n https://${hostname}/`;\n\n const nodeExample = `const response = await fetch('https://${hostname}/', {\n headers: {\n 'Authorization': 'Bearer ${displayApiKey}'\n }\n});\nconst data = await response.json();`;\n\n const pythonExample = `import requests\n\nresponse = requests.get(\n 'https://${hostname}/',\n headers={'Authorization': 'Bearer ${displayApiKey}'}\n)\ndata = response.json()`;\n\n const goExample = `package main\n\nimport (\n \"net/http\"\n)\n\nfunc main() {\n client := &http.Client{}\n req, _ := http.NewRequest(\"GET\", \"https://${hostname}/\", nil)\n req.Header.Set(\"Authorization\", \"Bearer ${displayApiKey}\")\n resp, _ := client.Do(req)\n defer resp.Body.Close()\n}`;\n\n const codeExamples = [\n { label: \"cURL\", code: curlExample },\n { label: \"Node.js\", code: nodeExample },\n { label: \"Python\", code: pythonExample },\n { label: \"Go\", code: goExample },\n ];\n\n return (\n <Page themeId=\"tool\">\n <Header\n title={apiKey.metadata.name}\n subtitle={`API Key for ${apiKey.spec.apiProductRef?.name || \"unknown\"}`}\n >\n <Link to=\"/kuadrant/api-keys\">\n <Button startIcon={<ArrowBackIcon />}>Back to API Keys</Button>\n </Link>\n </Header>\n <Content>\n <Box mb={2}>\n <Breadcrumbs aria-label=\"breadcrumb\">\n <Link to=\"/kuadrant/api-keys\">API keys</Link>\n <Typography>{apiKey.metadata.name}</Typography>\n </Breadcrumbs>\n </Box>\n\n <Box mb={3} display=\"flex\" style={{ gap: 8 }}>\n <Link to={`/catalog/default/api/${apiKey.spec.apiProductRef?.name}`}>\n <Button\n variant=\"outlined\"\n startIcon={<OpenInNewIcon />}\n data-testid=\"view-api-button\"\n >\n View API\n </Button>\n </Link>\n {apiProduct?.spec?.contact &&\n (apiProduct.spec.contact.email ||\n apiProduct.spec.contact.url ||\n apiProduct.spec.contact.slack) && (\n <Button\n variant=\"outlined\"\n startIcon={<EmailIcon />}\n href={\n apiProduct.spec.contact.email\n ? `mailto:${apiProduct.spec.contact.email}`\n : apiProduct.spec.contact.slack\n ? apiProduct.spec.contact.slack\n : apiProduct.spec.contact.url || \"#\"\n }\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Contact Owner\n </Button>\n )}\n </Box>\n\n <Grid container spacing={3}>\n <Grid item xs={12} md={6}>\n <InfoCard title=\"API Key Details\">\n <Box>\n <Typography variant=\"caption\" className={classes.label}>\n Status\n </Typography>\n <Box className={classes.value}>\n <Chip\n label={statusLabel}\n size=\"small\"\n style={getStatusChipStyle(phase)}\n data-testid=\"api-key-status-chip\"\n />\n </Box>\n\n <Typography variant=\"caption\" className={classes.label}>\n API Product\n </Typography>\n <Typography variant=\"body1\" className={classes.value}>\n <Link\n to={`/catalog/default/api/${apiKey.spec.apiProductRef?.name}/api-keys`}\n >\n {apiKey.spec.apiProductRef?.name || \"unknown\"}\n </Link>\n </Typography>\n\n <Typography variant=\"caption\" className={classes.label}>\n Tier\n </Typography>\n <Box className={classes.value}>\n <Chip\n label={apiKey.spec.planTier}\n size=\"small\"\n variant=\"outlined\"\n />\n </Box>\n\n <Typography variant=\"caption\" className={classes.label}>\n Requester\n </Typography>\n <Typography variant=\"body1\" className={classes.value}>\n {apiKey.spec.requestedBy?.userId}\n </Typography>\n\n <Typography variant=\"caption\" className={classes.label}>\n Requested\n </Typography>\n <Typography variant=\"body1\" className={classes.value}>\n {apiKey.metadata.creationTimestamp\n ? new Date(\n apiKey.metadata.creationTimestamp,\n ).toLocaleDateString()\n : \"-\"}\n </Typography>\n\n {apiKey.status?.reviewedBy && (\n <>\n <Typography variant=\"caption\" className={classes.label}>\n Reviewed By\n </Typography>\n <Typography variant=\"body1\" className={classes.value}>\n {apiKey.status.reviewedBy.replace(/^user:default\\//, \"\")}\n {apiKey.status.reviewedAt && (\n <Typography variant=\"caption\" color=\"textSecondary\">\n {\" \"}\n on{\" \"}\n {new Date(\n apiKey.status.reviewedAt,\n ).toLocaleDateString()}\n </Typography>\n )}\n </Typography>\n </>\n )}\n </Box>\n </InfoCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <InfoCard title=\"Use Case\">\n <Typography variant=\"body1\">\n {apiKey.spec.useCase || \"No use case provided\"}\n </Typography>\n </InfoCard>\n\n {phase === \"Approved\" && (\n <Box mt={2}>\n <InfoCard title=\"API Key\">\n {alreadyRead && !apiKeyValue ? (\n <Tooltip title=\"This API key has already been viewed and cannot be retrieved again\">\n <Box display=\"flex\" alignItems=\"center\">\n <Typography variant=\"body2\" color=\"textSecondary\">\n Already viewed - cannot be retrieved again\n </Typography>\n <VisibilityOffIcon\n fontSize=\"small\"\n color=\"disabled\"\n style={{ marginLeft: 8 }}\n />\n </Box>\n </Tooltip>\n ) : (\n <Box className={classes.apiKeyContainer}>\n <Typography\n variant=\"body2\"\n style={{ fontFamily: \"monospace\", flex: 1 }}\n >\n {apiKeyLoading\n ? \"Loading...\"\n : showApiKey && apiKeyValue\n ? apiKeyValue\n : \"•\".repeat(32)}\n </Typography>\n {showApiKey && apiKeyValue && (\n <Tooltip title=\"Copy to clipboard\">\n <IconButton\n size=\"small\"\n onClick={() => handleCopy(apiKeyValue)}\n >\n <FileCopyIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n <Tooltip\n title={\n showApiKey\n ? \"Hide API key\"\n : \"Reveal API key (one-time only)\"\n }\n >\n <span>\n <IconButton\n size=\"small\"\n onClick={handleRevealClick}\n disabled={\n apiKeyLoading || (alreadyRead && !apiKeyValue)\n }\n >\n {showApiKey ? (\n <VisibilityOffIcon fontSize=\"small\" />\n ) : (\n <VisibilityIcon fontSize=\"small\" />\n )}\n </IconButton>\n </span>\n </Tooltip>\n </Box>\n )}\n </InfoCard>\n </Box>\n )}\n </Grid>\n\n {phase === \"Approved\" && (\n <Grid item xs={12}>\n <InfoCard title=\"Code Examples\">\n <Box>\n <Tabs\n value={selectedTab}\n onChange={(_, newValue) => setSelectedTab(newValue)}\n indicatorColor=\"primary\"\n textColor=\"primary\"\n >\n {codeExamples.map((ex) => (\n <Tab key={ex.label} label={ex.label} />\n ))}\n </Tabs>\n <Box className={classes.tabPanel}>\n <CodeExample\n code={codeExamples[selectedTab].code}\n onCopy={() => handleCopy(codeExamples[selectedTab].code)}\n />\n </Box>\n </Box>\n </InfoCard>\n </Grid>\n )}\n\n {apiKey.status?.limits && (\n <Grid item xs={12}>\n <InfoCard title=\"Rate Limits\">\n <Grid container spacing={2}>\n {apiKey.status.limits.daily && (\n <Grid item>\n <Typography variant=\"caption\" className={classes.label}>\n Daily\n </Typography>\n <Typography variant=\"h6\">\n {apiKey.status.limits.daily.toLocaleString()}\n </Typography>\n </Grid>\n )}\n {apiKey.status.limits.weekly && (\n <Grid item>\n <Typography variant=\"caption\" className={classes.label}>\n Weekly\n </Typography>\n <Typography variant=\"h6\">\n {apiKey.status.limits.weekly.toLocaleString()}\n </Typography>\n </Grid>\n )}\n {apiKey.status.limits.monthly && (\n <Grid item>\n <Typography variant=\"caption\" className={classes.label}>\n Monthly\n </Typography>\n <Typography variant=\"h6\">\n {apiKey.status.limits.monthly.toLocaleString()}\n </Typography>\n </Grid>\n )}\n </Grid>\n </InfoCard>\n </Grid>\n )}\n </Grid>\n </Content>\n\n <Dialog\n open={showWarning}\n onClose={() => setShowWarning(false)}\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 onClick={() => setShowWarning(false)}>Cancel</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleConfirmReveal}\n >\n Reveal API Key\n </Button>\n </DialogActions>\n </Dialog>\n </Page>\n );\n};\n"],"names":["apiProduct","data"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { ApiKeyDetailPage } from './ApiKeyDetailPage.esm.js';
2
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}