@kuadrant/kuadrant-backstage-plugin-frontend 0.0.2-dev-0b744dd → 0.0.2-dev-9be93a3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/dist/api.esm.js +220 -0
  2. package/dist/api.esm.js.map +1 -0
  3. package/dist/apis.esm.js +15 -0
  4. package/dist/apis.esm.js.map +1 -0
  5. package/dist/components/ApiAccessCard/ApiAccessCard.esm.js +27 -37
  6. package/dist/components/ApiAccessCard/ApiAccessCard.esm.js.map +1 -1
  7. package/dist/components/ApiKeyApprovalPage/ApiKeyApprovalPage.esm.js +10 -0
  8. package/dist/components/ApiKeyApprovalPage/ApiKeyApprovalPage.esm.js.map +1 -0
  9. package/dist/components/ApiKeyApprovalPage/index.esm.js +2 -0
  10. package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js +28 -40
  11. package/dist/components/ApiKeyDetailPage/ApiKeyDetailPage.esm.js.map +1 -1
  12. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js +20 -46
  13. package/dist/components/ApiKeyManagementTab/ApiKeyManagementTab.esm.js.map +1 -1
  14. package/dist/components/ApiProductDetailPage/ApiProductDetailPage.esm.js +27 -35
  15. package/dist/components/ApiProductDetailPage/ApiProductDetailPage.esm.js.map +1 -1
  16. package/dist/components/ApiProductDetails/ApiProductDetails.esm.js +13 -3
  17. package/dist/components/ApiProductDetails/ApiProductDetails.esm.js.map +1 -1
  18. package/dist/components/ApiProductInfoCard/ApiProductInfoCard.esm.js +5 -13
  19. package/dist/components/ApiProductInfoCard/ApiProductInfoCard.esm.js.map +1 -1
  20. package/dist/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.esm.js +7 -10
  21. package/dist/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.esm.js.map +1 -1
  22. package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js +34 -66
  23. package/dist/components/ApprovalQueueTable/ApprovalQueueTable.esm.js.map +1 -1
  24. package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js +143 -58
  25. package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js.map +1 -1
  26. package/dist/components/EditAPIKeyDialog/EditAPIKeyDialog.esm.js +8 -18
  27. package/dist/components/EditAPIKeyDialog/EditAPIKeyDialog.esm.js.map +1 -1
  28. package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js +52 -30
  29. package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js.map +1 -1
  30. package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js +11 -27
  31. package/dist/components/EntityApiApprovalTab/EntityApiApprovalTab.esm.js.map +1 -1
  32. package/dist/components/KuadrantPage/ApiProductsPage.esm.js +71 -55
  33. package/dist/components/KuadrantPage/ApiProductsPage.esm.js.map +1 -1
  34. package/dist/components/MyApiKeysPage/MyApiKeysPage.esm.js +10 -0
  35. package/dist/components/MyApiKeysPage/MyApiKeysPage.esm.js.map +1 -0
  36. package/dist/components/MyApiKeysPage/index.esm.js +2 -0
  37. package/dist/components/MyApiKeysPage/index.esm.js.map +1 -0
  38. package/dist/components/MyApiKeysTable/MyApiKeysTable.esm.js +51 -57
  39. package/dist/components/MyApiKeysTable/MyApiKeysTable.esm.js.map +1 -1
  40. package/dist/components/RequestAccessDialog/RequestAccessDialog.esm.js +10 -25
  41. package/dist/components/RequestAccessDialog/RequestAccessDialog.esm.js.map +1 -1
  42. package/dist/components/SimpleRequestAccessDialog/SimpleRequestAccessDialog.esm.js +206 -0
  43. package/dist/components/SimpleRequestAccessDialog/SimpleRequestAccessDialog.esm.js.map +1 -0
  44. package/dist/index.d.ts +461 -2
  45. package/dist/index.esm.js +3 -1
  46. package/dist/index.esm.js.map +1 -1
  47. package/dist/plugin.esm.js +11 -4
  48. package/dist/plugin.esm.js.map +1 -1
  49. package/dist/utils/styles.esm.js +44 -5
  50. package/dist/utils/styles.esm.js.map +1 -1
  51. package/dist-scalprum/internal.plugin-kuadrant.8bf02d5482a5a3ed6337.js +2 -0
  52. package/dist-scalprum/internal.plugin-kuadrant.8bf02d5482a5a3ed6337.js.map +1 -0
  53. package/dist-scalprum/plugin-manifest.json +3 -3
  54. package/dist-scalprum/static/2118.82433765.chunk.js +2 -0
  55. package/dist-scalprum/static/2118.82433765.chunk.js.map +1 -0
  56. package/dist-scalprum/static/2967.28e7c7f8.chunk.js +2 -0
  57. package/dist-scalprum/static/2967.28e7c7f8.chunk.js.map +1 -0
  58. package/dist-scalprum/static/369.2374941c.chunk.js +2 -0
  59. package/dist-scalprum/static/369.2374941c.chunk.js.map +1 -0
  60. package/dist-scalprum/static/3947.ff1c25cf.chunk.js +2 -0
  61. package/dist-scalprum/static/3947.ff1c25cf.chunk.js.map +1 -0
  62. package/dist-scalprum/static/3976.cf3ec7be.chunk.js +2 -0
  63. package/dist-scalprum/static/3976.cf3ec7be.chunk.js.map +1 -0
  64. package/dist-scalprum/static/4447.222bb58d.chunk.js +2 -0
  65. package/dist-scalprum/static/4447.222bb58d.chunk.js.map +1 -0
  66. package/dist-scalprum/static/5010.4ef96c87.chunk.js +3 -0
  67. package/dist-scalprum/static/5010.4ef96c87.chunk.js.map +1 -0
  68. package/dist-scalprum/static/5203.e92a3353.chunk.js +2 -0
  69. package/dist-scalprum/static/5203.e92a3353.chunk.js.map +1 -0
  70. package/dist-scalprum/static/6371.6ee1f11d.chunk.js +2 -0
  71. package/dist-scalprum/static/6371.6ee1f11d.chunk.js.map +1 -0
  72. package/dist-scalprum/static/6422.969d9b8c.chunk.js +2 -0
  73. package/dist-scalprum/static/6422.969d9b8c.chunk.js.map +1 -0
  74. package/dist-scalprum/static/6800.a7645f4c.chunk.js +2 -0
  75. package/dist-scalprum/static/6800.a7645f4c.chunk.js.map +1 -0
  76. package/dist-scalprum/static/69.1decc5e8.chunk.js +2 -0
  77. package/dist-scalprum/static/69.1decc5e8.chunk.js.map +1 -0
  78. package/dist-scalprum/static/7005.a9f73153.chunk.js +2 -0
  79. package/dist-scalprum/static/7005.a9f73153.chunk.js.map +1 -0
  80. package/dist-scalprum/static/7270.b0e185f1.chunk.js +2 -0
  81. package/dist-scalprum/static/7270.b0e185f1.chunk.js.map +1 -0
  82. package/dist-scalprum/static/7791.5c1eea8a.chunk.js +2 -0
  83. package/dist-scalprum/static/7791.5c1eea8a.chunk.js.map +1 -0
  84. package/dist-scalprum/static/{6763.d6cd937f.chunk.js → 8563.46f1a3e1.chunk.js} +3 -3
  85. package/dist-scalprum/static/8563.46f1a3e1.chunk.js.map +1 -0
  86. package/dist-scalprum/static/8789.84963cbc.chunk.js +2 -0
  87. package/dist-scalprum/static/8789.84963cbc.chunk.js.map +1 -0
  88. package/dist-scalprum/static/8804.63919453.chunk.js +2 -0
  89. package/dist-scalprum/static/8804.63919453.chunk.js.map +1 -0
  90. package/dist-scalprum/static/9051.db875198.chunk.js +2 -0
  91. package/dist-scalprum/static/9051.db875198.chunk.js.map +1 -0
  92. package/dist-scalprum/static/{2946.a35243f1.chunk.js → 9370.2e9fe34b.chunk.js} +3 -3
  93. package/dist-scalprum/static/9370.2e9fe34b.chunk.js.map +1 -0
  94. package/dist-scalprum/static/9838.5df9b1de.chunk.js +2 -0
  95. package/dist-scalprum/static/9838.5df9b1de.chunk.js.map +1 -0
  96. package/dist-scalprum/static/exposed-PluginRoot.8a8dd91f.chunk.js +2 -0
  97. package/dist-scalprum/static/exposed-PluginRoot.8a8dd91f.chunk.js.map +1 -0
  98. package/package.json +3 -1
  99. package/dist/components/ApiKeysPage/ApiKeysPage.esm.js +0 -43
  100. package/dist/components/ApiKeysPage/ApiKeysPage.esm.js.map +0 -1
  101. package/dist/components/ApiKeysPage/index.esm.js +0 -2
  102. package/dist-scalprum/internal.plugin-kuadrant.114cbbe1d3ddb939d776.js +0 -2
  103. package/dist-scalprum/internal.plugin-kuadrant.114cbbe1d3ddb939d776.js.map +0 -1
  104. package/dist-scalprum/static/2821.0829f14d.chunk.js +0 -2
  105. package/dist-scalprum/static/2821.0829f14d.chunk.js.map +0 -1
  106. package/dist-scalprum/static/2946.a35243f1.chunk.js.map +0 -1
  107. package/dist-scalprum/static/2967.65c51af8.chunk.js +0 -2
  108. package/dist-scalprum/static/2967.65c51af8.chunk.js.map +0 -1
  109. package/dist-scalprum/static/3650.ee76eba9.chunk.js +0 -2
  110. package/dist-scalprum/static/3650.ee76eba9.chunk.js.map +0 -1
  111. package/dist-scalprum/static/3947.7458971d.chunk.js +0 -2
  112. package/dist-scalprum/static/3947.7458971d.chunk.js.map +0 -1
  113. package/dist-scalprum/static/3984.647ef00c.chunk.js +0 -2
  114. package/dist-scalprum/static/3984.647ef00c.chunk.js.map +0 -1
  115. package/dist-scalprum/static/4651.c85cecc4.chunk.js +0 -2
  116. package/dist-scalprum/static/4651.c85cecc4.chunk.js.map +0 -1
  117. package/dist-scalprum/static/4682.75f17114.chunk.js +0 -2
  118. package/dist-scalprum/static/4682.75f17114.chunk.js.map +0 -1
  119. package/dist-scalprum/static/5010.0cd6c959.chunk.js +0 -3
  120. package/dist-scalprum/static/5010.0cd6c959.chunk.js.map +0 -1
  121. package/dist-scalprum/static/5203.b654e8e0.chunk.js +0 -2
  122. package/dist-scalprum/static/5203.b654e8e0.chunk.js.map +0 -1
  123. package/dist-scalprum/static/5453.ecdee66d.chunk.js +0 -2
  124. package/dist-scalprum/static/5453.ecdee66d.chunk.js.map +0 -1
  125. package/dist-scalprum/static/6371.d45f37cc.chunk.js +0 -2
  126. package/dist-scalprum/static/6371.d45f37cc.chunk.js.map +0 -1
  127. package/dist-scalprum/static/6763.d6cd937f.chunk.js.map +0 -1
  128. package/dist-scalprum/static/6800.20f46859.chunk.js +0 -2
  129. package/dist-scalprum/static/6800.20f46859.chunk.js.map +0 -1
  130. package/dist-scalprum/static/6840.1653e6b0.chunk.js +0 -2
  131. package/dist-scalprum/static/6840.1653e6b0.chunk.js.map +0 -1
  132. package/dist-scalprum/static/7236.f3886d59.chunk.js +0 -2
  133. package/dist-scalprum/static/7236.f3886d59.chunk.js.map +0 -1
  134. package/dist-scalprum/static/7791.ac1ac509.chunk.js +0 -2
  135. package/dist-scalprum/static/7791.ac1ac509.chunk.js.map +0 -1
  136. package/dist-scalprum/static/8172.cbe1f2c4.chunk.js +0 -2
  137. package/dist-scalprum/static/8172.cbe1f2c4.chunk.js.map +0 -1
  138. package/dist-scalprum/static/8799.939d14f9.chunk.js +0 -2
  139. package/dist-scalprum/static/8799.939d14f9.chunk.js.map +0 -1
  140. package/dist-scalprum/static/exposed-PluginRoot.ed95fa78.chunk.js +0 -2
  141. package/dist-scalprum/static/exposed-PluginRoot.ed95fa78.chunk.js.map +0 -1
  142. /package/dist/components/{ApiKeysPage → ApiKeyApprovalPage}/index.esm.js.map +0 -0
  143. /package/dist-scalprum/static/{5010.0cd6c959.chunk.js.LICENSE.txt → 5010.4ef96c87.chunk.js.LICENSE.txt} +0 -0
  144. /package/dist-scalprum/static/{6763.d6cd937f.chunk.js.LICENSE.txt → 8563.46f1a3e1.chunk.js.LICENSE.txt} +0 -0
  145. /package/dist-scalprum/static/{2946.a35243f1.chunk.js.LICENSE.txt → 9370.2e9fe34b.chunk.js.LICENSE.txt} +0 -0
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { makeStyles, Box, Typography, Chip, Table, TableHead, TableRow, TableCell, TableBody, Grid } from '@material-ui/core';
3
3
  import { Link } from '@backstage/core-components';
4
+ import { getLifecycleChipStyle } from '../../utils/styles.esm.js';
4
5
 
5
6
  const useStyles = makeStyles((theme) => ({
6
7
  label: {
@@ -42,7 +43,8 @@ const useStyles = makeStyles((theme) => ({
42
43
  const ApiProductDetails = ({
43
44
  product,
44
45
  showStatus = true,
45
- showCatalogLink = true
46
+ showCatalogLink = true,
47
+ httpRouteHostnames
46
48
  }) => {
47
49
  const classes = useStyles();
48
50
  const publishStatus = product.spec?.publishStatus || "Draft";
@@ -53,7 +55,7 @@ const ApiProductDetails = ({
53
55
  const hasApiKey = schemeObjects.some(
54
56
  (scheme) => scheme.hasOwnProperty("apiKey")
55
57
  );
56
- return /* @__PURE__ */ React.createElement(React.Fragment, null, product.spec?.description && /* @__PURE__ */ React.createElement(Box, { mb: 3 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Description"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, product.spec.description)), /* @__PURE__ */ React.createElement(Box, { className: classes.infoGrid }, showStatus && /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Status"), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
58
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, product.spec?.description && /* @__PURE__ */ React.createElement(Box, { mb: 3 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Description"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, product.spec.description)), /* @__PURE__ */ React.createElement(Box, { className: classes.infoGrid }, showStatus && /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Publish Status"), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
57
59
  Chip,
58
60
  {
59
61
  label: publishStatus,
@@ -61,6 +63,14 @@ const ApiProductDetails = ({
61
63
  className: isPublished ? classes.statusChipPublished : classes.statusChipDraft,
62
64
  "data-testid": "publish-status-chip"
63
65
  }
66
+ ))), product.metadata.labels?.lifecycle && /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Lifecycle"), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
67
+ Chip,
68
+ {
69
+ label: product.metadata.labels.lifecycle,
70
+ size: "small",
71
+ style: getLifecycleChipStyle(product.metadata.labels.lifecycle),
72
+ "data-testid": "lifecycle-chip"
73
+ }
64
74
  ))), /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Version"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, product.spec?.version || "v1")), /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Namespace"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, product.metadata.namespace)), hasApiKey && /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "API Key Approval"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, product.spec?.approvalMode === "automatic" ? "Automatic" : "Need manual approval")), product.spec?.tags && product.spec.tags.length > 0 && /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Tags"), /* @__PURE__ */ React.createElement(Box, null, product.spec.tags.map((tag) => /* @__PURE__ */ React.createElement(
65
75
  Chip,
66
76
  {
@@ -77,7 +87,7 @@ const ApiProductDetails = ({
77
87
  className: classes.apiLink
78
88
  },
79
89
  product.metadata.name
80
- ) : /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, product.metadata.name)), /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Route"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, product.spec?.targetRef?.name || "-"))), tiers.length > 0 && /* @__PURE__ */ React.createElement(Box, { mb: 3 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Available Tiers"), /* @__PURE__ */ React.createElement(Table, { size: "small" }, /* @__PURE__ */ React.createElement(TableHead, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, null, "Tier"), /* @__PURE__ */ React.createElement(TableCell, null, "Rate Limits"))), /* @__PURE__ */ React.createElement(TableBody, null, tiers.map((plan) => /* @__PURE__ */ React.createElement(TableRow, { key: plan.tier }, /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement(Chip, { label: plan.tier, size: "small" })), /* @__PURE__ */ React.createElement(TableCell, null, plan.limits && Object.entries(plan.limits).map(([key, value]) => /* @__PURE__ */ React.createElement(Typography, { key, variant: "body2" }, String(value), " per ", key)))))))), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, (product.spec?.contact?.email || product.spec?.contact?.team) && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Contact Information"), /* @__PURE__ */ React.createElement(Box, { mt: 1 }, product.spec.contact.team && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "Team:"), " ", product.spec.contact.team), product.spec.contact.email && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "Email:"), " ", /* @__PURE__ */ React.createElement(Link, { to: `mailto:${product.spec.contact.email}` }, product.spec.contact.email)))), (product.spec?.documentation?.docsURL || product.spec?.documentation?.openAPISpecURL) && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Documentation"), /* @__PURE__ */ React.createElement(Box, { mt: 1 }, product.spec.documentation.docsURL && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "Docs:"), " ", /* @__PURE__ */ React.createElement(Link, { to: product.spec.documentation.docsURL, target: "_blank" }, "View Documentation")), product.spec.documentation.openAPISpecURL && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "OpenAPI Spec:"), " ", /* @__PURE__ */ React.createElement(
90
+ ) : /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, product.metadata.name)), /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Route"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, product.spec?.targetRef?.name || "-")), httpRouteHostnames && httpRouteHostnames.length > 0 && /* @__PURE__ */ React.createElement(Box, { className: classes.infoItem }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, httpRouteHostnames.length > 1 ? "Hostnames" : "Hostname"), httpRouteHostnames.map((hostname, index) => /* @__PURE__ */ React.createElement(Typography, { key: index, variant: "body2" }, hostname)))), tiers.length > 0 && /* @__PURE__ */ React.createElement(Box, { mb: 3 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Available Tiers"), /* @__PURE__ */ React.createElement(Table, { size: "small" }, /* @__PURE__ */ React.createElement(TableHead, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, null, "Tier"), /* @__PURE__ */ React.createElement(TableCell, null, "Rate Limits"))), /* @__PURE__ */ React.createElement(TableBody, null, tiers.map((plan) => /* @__PURE__ */ React.createElement(TableRow, { key: plan.tier }, /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement(Chip, { label: plan.tier, size: "small" })), /* @__PURE__ */ React.createElement(TableCell, null, plan.limits && Object.entries(plan.limits).map(([key, value]) => /* @__PURE__ */ React.createElement(Typography, { key, variant: "body2" }, String(value), " per ", key)))))))), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, (product.spec?.contact?.email || product.spec?.contact?.team) && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Contact Information"), /* @__PURE__ */ React.createElement(Box, { mt: 1 }, product.spec.contact.team && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "Team:"), " ", product.spec.contact.team), product.spec.contact.email && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "Email:"), " ", /* @__PURE__ */ React.createElement(Link, { to: `mailto:${product.spec.contact.email}` }, product.spec.contact.email)))), (product.spec?.documentation?.docsURL || product.spec?.documentation?.openAPISpecURL) && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React.createElement(Typography, { variant: "caption", className: classes.label }, "Documentation"), /* @__PURE__ */ React.createElement(Box, { mt: 1 }, product.spec.documentation.docsURL && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "Docs:"), " ", /* @__PURE__ */ React.createElement(Link, { to: product.spec.documentation.docsURL, target: "_blank" }, "View Documentation")), product.spec.documentation.openAPISpecURL && /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, /* @__PURE__ */ React.createElement("strong", null, "OpenAPI Spec:"), " ", /* @__PURE__ */ React.createElement(
81
91
  Link,
82
92
  {
83
93
  to: product.spec.documentation.openAPISpecURL,
@@ -1 +1 @@
1
- {"version":3,"file":"ApiProductDetails.esm.js","sources":["../../../src/components/ApiProductDetails/ApiProductDetails.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n Box,\n Typography,\n Chip,\n makeStyles,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Grid,\n} from \"@material-ui/core\";\nimport { Link } from \"@backstage/core-components\";\nimport { APIProduct, Plan } from \"../../types/api-management\";\n\nconst useStyles = makeStyles((theme) => ({\n label: {\n fontWeight: 600,\n color: theme.palette.text.secondary,\n marginBottom: theme.spacing(0.5),\n fontSize: \"0.75rem\",\n textTransform: \"uppercase\",\n },\n tierChip: {\n marginRight: theme.spacing(0.5),\n marginBottom: theme.spacing(0.5),\n },\n statusChipPublished: {\n backgroundColor: theme.palette.primary.main,\n color: theme.palette.primary.contrastText,\n },\n statusChipDraft: {\n backgroundColor: theme.palette.grey[600],\n color: theme.palette.common.white,\n },\n infoGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fill, minmax(180px, 1fr))\",\n gap: theme.spacing(3),\n marginBottom: theme.spacing(3),\n },\n infoItem: {\n minWidth: 0,\n },\n apiLink: {\n color: theme.palette.primary.main,\n textDecoration: \"none\",\n \"&:hover\": {\n textDecoration: \"underline\",\n },\n },\n}));\n\ninterface ApiProductDetailsProps {\n product: APIProduct;\n showStatus?: boolean;\n showCatalogLink?: boolean;\n}\n\nexport const ApiProductDetails = ({\n product,\n showStatus = true,\n showCatalogLink = true,\n}: ApiProductDetailsProps) => {\n const classes = useStyles();\n\n const publishStatus = product.spec?.publishStatus || \"Draft\";\n const isPublished = publishStatus === \"Published\";\n const tiers = product.status?.discoveredPlans || [];\n\n // check if product has API key auth\n const authSchemes = product.status?.discoveredAuthScheme?.authentication || {};\n const schemeObjects = Object.values(authSchemes);\n const hasApiKey = schemeObjects.some(\n (scheme: any) => scheme.hasOwnProperty(\"apiKey\"),\n );\n\n return (\n <>\n {product.spec?.description && (\n <Box mb={3}>\n <Typography variant=\"caption\" className={classes.label}>\n Description\n </Typography>\n <Typography variant=\"body1\">{product.spec.description}</Typography>\n </Box>\n )}\n\n <Box className={classes.infoGrid}>\n {showStatus && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Status\n </Typography>\n <Box>\n <Chip\n label={publishStatus}\n size=\"small\"\n className={\n isPublished\n ? classes.statusChipPublished\n : classes.statusChipDraft\n }\n data-testid=\"publish-status-chip\"\n />\n </Box>\n </Box>\n )}\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Version\n </Typography>\n <Typography variant=\"body2\">\n {product.spec?.version || \"v1\"}\n </Typography>\n </Box>\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Namespace\n </Typography>\n <Typography variant=\"body2\">{product.metadata.namespace}</Typography>\n </Box>\n {hasApiKey && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n API Key Approval\n </Typography>\n <Typography variant=\"body2\">\n {product.spec?.approvalMode === \"automatic\"\n ? \"Automatic\"\n : \"Need manual approval\"}\n </Typography>\n </Box>\n )}\n {product.spec?.tags && product.spec.tags.length > 0 && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Tags\n </Typography>\n <Box>\n {product.spec.tags.map((tag) => (\n <Chip\n key={tag}\n label={tag}\n size=\"small\"\n variant=\"outlined\"\n className={classes.tierChip}\n />\n ))}\n </Box>\n </Box>\n )}\n </Box>\n\n <Box className={classes.infoGrid}>\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n API\n </Typography>\n <br />\n {showCatalogLink ? (\n <Link\n to={`/catalog/default/api/${product.metadata.name}`}\n className={classes.apiLink}\n >\n {product.metadata.name}\n </Link>\n ) : (\n <Typography variant=\"body2\">{product.metadata.name}</Typography>\n )}\n </Box>\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Route\n </Typography>\n <Typography variant=\"body2\">\n {product.spec?.targetRef?.name || \"-\"}\n </Typography>\n </Box>\n </Box>\n\n {tiers.length > 0 && (\n <Box mb={3}>\n <Typography variant=\"caption\" className={classes.label}>\n Available Tiers\n </Typography>\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>Tier</TableCell>\n <TableCell>Rate Limits</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {tiers.map((plan: Plan) => (\n <TableRow key={plan.tier}>\n <TableCell>\n <Chip label={plan.tier} size=\"small\" />\n </TableCell>\n <TableCell>\n {plan.limits &&\n Object.entries(plan.limits).map(([key, value]) => (\n <Typography key={key} variant=\"body2\">\n {String(value)} per {key}\n </Typography>\n ))}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </Box>\n )}\n\n <Grid container spacing={3}>\n {(product.spec?.contact?.email || product.spec?.contact?.team) && (\n <Grid item xs={12} md={6}>\n <Typography variant=\"caption\" className={classes.label}>\n Contact Information\n </Typography>\n <Box mt={1}>\n {product.spec.contact.team && (\n <Typography variant=\"body2\">\n <strong>Team:</strong> {product.spec.contact.team}\n </Typography>\n )}\n {product.spec.contact.email && (\n <Typography variant=\"body2\">\n <strong>Email:</strong>{\" \"}\n <Link to={`mailto:${product.spec.contact.email}`}>\n {product.spec.contact.email}\n </Link>\n </Typography>\n )}\n </Box>\n </Grid>\n )}\n\n {(product.spec?.documentation?.docsURL ||\n product.spec?.documentation?.openAPISpecURL) && (\n <Grid item xs={12} md={6}>\n <Typography variant=\"caption\" className={classes.label}>\n Documentation\n </Typography>\n <Box mt={1}>\n {product.spec.documentation.docsURL && (\n <Typography variant=\"body2\">\n <strong>Docs:</strong>{\" \"}\n <Link to={product.spec.documentation.docsURL} target=\"_blank\">\n View Documentation\n </Link>\n </Typography>\n )}\n {product.spec.documentation.openAPISpecURL && (\n <Typography variant=\"body2\">\n <strong>OpenAPI Spec:</strong>{\" \"}\n <Link\n to={product.spec.documentation.openAPISpecURL}\n target=\"_blank\"\n >\n View Spec\n </Link>\n </Typography>\n )}\n </Box>\n </Grid>\n )}\n </Grid>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ApiProductDetails.esm.js","sources":["../../../src/components/ApiProductDetails/ApiProductDetails.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n Box,\n Typography,\n Chip,\n makeStyles,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Grid,\n} from \"@material-ui/core\";\nimport { Link } from \"@backstage/core-components\";\nimport { APIProduct, Plan } from \"../../types/api-management\";\nimport { getLifecycleChipStyle } 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 fontSize: \"0.75rem\",\n textTransform: \"uppercase\",\n },\n tierChip: {\n marginRight: theme.spacing(0.5),\n marginBottom: theme.spacing(0.5),\n },\n statusChipPublished: {\n backgroundColor: theme.palette.primary.main,\n color: theme.palette.primary.contrastText,\n },\n statusChipDraft: {\n backgroundColor: theme.palette.grey[600],\n color: theme.palette.common.white,\n },\n infoGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fill, minmax(180px, 1fr))\",\n gap: theme.spacing(3),\n marginBottom: theme.spacing(3),\n },\n infoItem: {\n minWidth: 0,\n },\n apiLink: {\n color: theme.palette.primary.main,\n textDecoration: \"none\",\n \"&:hover\": {\n textDecoration: \"underline\",\n },\n },\n}));\n\ninterface ApiProductDetailsProps {\n product: APIProduct;\n showStatus?: boolean;\n showCatalogLink?: boolean;\n httpRouteHostnames?: string[] | null;\n}\n\nexport const ApiProductDetails = ({\n product,\n showStatus = true,\n showCatalogLink = true,\n httpRouteHostnames,\n}: ApiProductDetailsProps) => {\n const classes = useStyles();\n\n const publishStatus = product.spec?.publishStatus || \"Draft\";\n const isPublished = publishStatus === \"Published\";\n const tiers = product.status?.discoveredPlans || [];\n\n // check if product has API key auth\n const authSchemes = product.status?.discoveredAuthScheme?.authentication || {};\n const schemeObjects = Object.values(authSchemes);\n const hasApiKey = schemeObjects.some(\n (scheme: any) => scheme.hasOwnProperty(\"apiKey\"),\n );\n\n return (\n <>\n {product.spec?.description && (\n <Box mb={3}>\n <Typography variant=\"caption\" className={classes.label}>\n Description\n </Typography>\n <Typography variant=\"body1\">{product.spec.description}</Typography>\n </Box>\n )}\n\n <Box className={classes.infoGrid}>\n {showStatus && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Publish Status\n </Typography>\n <Box>\n <Chip\n label={publishStatus}\n size=\"small\"\n className={\n isPublished\n ? classes.statusChipPublished\n : classes.statusChipDraft\n }\n data-testid=\"publish-status-chip\"\n />\n </Box>\n </Box>\n )}\n {product.metadata.labels?.lifecycle && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Lifecycle\n </Typography>\n <Box>\n <Chip\n label={product.metadata.labels.lifecycle}\n size=\"small\"\n style={getLifecycleChipStyle(product.metadata.labels.lifecycle)}\n data-testid=\"lifecycle-chip\"\n />\n </Box>\n </Box>\n )}\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Version\n </Typography>\n <Typography variant=\"body2\">\n {product.spec?.version || \"v1\"}\n </Typography>\n </Box>\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Namespace\n </Typography>\n <Typography variant=\"body2\">{product.metadata.namespace}</Typography>\n </Box>\n {hasApiKey && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n API Key Approval\n </Typography>\n <Typography variant=\"body2\">\n {product.spec?.approvalMode === \"automatic\"\n ? \"Automatic\"\n : \"Need manual approval\"}\n </Typography>\n </Box>\n )}\n {product.spec?.tags && product.spec.tags.length > 0 && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Tags\n </Typography>\n <Box>\n {product.spec.tags.map((tag) => (\n <Chip\n key={tag}\n label={tag}\n size=\"small\"\n variant=\"outlined\"\n className={classes.tierChip}\n />\n ))}\n </Box>\n </Box>\n )}\n </Box>\n\n <Box className={classes.infoGrid}>\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n API\n </Typography>\n <br />\n {showCatalogLink ? (\n <Link\n to={`/catalog/default/api/${product.metadata.name}`}\n className={classes.apiLink}\n >\n {product.metadata.name}\n </Link>\n ) : (\n <Typography variant=\"body2\">{product.metadata.name}</Typography>\n )}\n </Box>\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n Route\n </Typography>\n <Typography variant=\"body2\">\n {product.spec?.targetRef?.name || \"-\"}\n </Typography>\n </Box>\n {httpRouteHostnames && httpRouteHostnames.length > 0 && (\n <Box className={classes.infoItem}>\n <Typography variant=\"caption\" className={classes.label}>\n {httpRouteHostnames.length > 1 ? \"Hostnames\" : \"Hostname\"}\n </Typography>\n {httpRouteHostnames.map((hostname, index) => (\n <Typography key={index} variant=\"body2\">\n {hostname}\n </Typography>\n ))}\n </Box>\n )}\n </Box>\n\n {tiers.length > 0 && (\n <Box mb={3}>\n <Typography variant=\"caption\" className={classes.label}>\n Available Tiers\n </Typography>\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>Tier</TableCell>\n <TableCell>Rate Limits</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {tiers.map((plan: Plan) => (\n <TableRow key={plan.tier}>\n <TableCell>\n <Chip label={plan.tier} size=\"small\" />\n </TableCell>\n <TableCell>\n {plan.limits &&\n Object.entries(plan.limits).map(([key, value]) => (\n <Typography key={key} variant=\"body2\">\n {String(value)} per {key}\n </Typography>\n ))}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </Box>\n )}\n\n <Grid container spacing={3}>\n {(product.spec?.contact?.email || product.spec?.contact?.team) && (\n <Grid item xs={12} md={6}>\n <Typography variant=\"caption\" className={classes.label}>\n Contact Information\n </Typography>\n <Box mt={1}>\n {product.spec.contact.team && (\n <Typography variant=\"body2\">\n <strong>Team:</strong> {product.spec.contact.team}\n </Typography>\n )}\n {product.spec.contact.email && (\n <Typography variant=\"body2\">\n <strong>Email:</strong>{\" \"}\n <Link to={`mailto:${product.spec.contact.email}`}>\n {product.spec.contact.email}\n </Link>\n </Typography>\n )}\n </Box>\n </Grid>\n )}\n\n {(product.spec?.documentation?.docsURL ||\n product.spec?.documentation?.openAPISpecURL) && (\n <Grid item xs={12} md={6}>\n <Typography variant=\"caption\" className={classes.label}>\n Documentation\n </Typography>\n <Box mt={1}>\n {product.spec.documentation.docsURL && (\n <Typography variant=\"body2\">\n <strong>Docs:</strong>{\" \"}\n <Link to={product.spec.documentation.docsURL} target=\"_blank\">\n View Documentation\n </Link>\n </Typography>\n )}\n {product.spec.documentation.openAPISpecURL && (\n <Typography variant=\"body2\">\n <strong>OpenAPI Spec:</strong>{\" \"}\n <Link\n to={product.spec.documentation.openAPISpecURL}\n target=\"_blank\"\n >\n View Spec\n </Link>\n </Typography>\n )}\n </Box>\n </Grid>\n )}\n </Grid>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { useEntity } from '@backstage/plugin-catalog-react';
3
- import { useApi, configApiRef, fetchApiRef, identityApiRef } from '@backstage/core-plugin-api';
3
+ import { useApi, identityApiRef } from '@backstage/core-plugin-api';
4
4
  import { InfoCard, Progress, ResponseErrorPanel } from '@backstage/core-components';
5
5
  import { makeStyles, Typography, Box } from '@material-ui/core';
6
6
  import useAsync from 'react-use/lib/useAsync';
@@ -8,6 +8,7 @@ import { useKuadrantPermission } from '../../utils/permissions.esm.js';
8
8
  import { kuadrantApiProductReadAllPermission } from '../../permissions.esm.js';
9
9
  import { ApiProductDetails } from '../ApiProductDetails/ApiProductDetails.esm.js';
10
10
  import { OidcProviderCard } from '../OidcProviderCard/OidcProviderCard.esm.js';
11
+ import { kuadrantApiRef } from '../../api.esm.js';
11
12
 
12
13
  const useStyles = makeStyles((theme) => ({
13
14
  label: {
@@ -21,10 +22,8 @@ const useStyles = makeStyles((theme) => ({
21
22
  const ApiProductInfoCard = () => {
22
23
  const classes = useStyles();
23
24
  const { entity } = useEntity();
24
- const config = useApi(configApiRef);
25
- const fetchApi = useApi(fetchApiRef);
25
+ const kuadrantApi = useApi(kuadrantApiRef);
26
26
  const identityApi = useApi(identityApiRef);
27
- const backendUrl = config.getString("backend.baseUrl");
28
27
  const { allowed: canReadAll, loading: permLoading } = useKuadrantPermission(
29
28
  kuadrantApiProductReadAllPermission
30
29
  );
@@ -38,15 +37,8 @@ const ApiProductInfoCard = () => {
38
37
  if (!namespace || !apiProductName) {
39
38
  return null;
40
39
  }
41
- const productResponse = await fetchApi.fetch(
42
- `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${apiProductName}`
43
- );
44
- if (!productResponse.ok) {
45
- const errorData = await productResponse.json();
46
- throw new Error(errorData.error || `Failed to fetch API product: ${productResponse.status}`);
47
- }
48
- return productResponse.json();
49
- }, [backendUrl, fetchApi, namespace, apiProductName]);
40
+ return kuadrantApi.getApiProduct(namespace, apiProductName);
41
+ }, [kuadrantApi, namespace, apiProductName]);
50
42
  const owner = apiProduct?.metadata?.annotations?.["backstage.io/owner"];
51
43
  const ownerUserId = owner?.split("/")[1];
52
44
  const canView = canReadAll || currentUserId && ownerUserId === currentUserId;
@@ -1 +1 @@
1
- {"version":3,"file":"ApiProductInfoCard.esm.js","sources":["../../../src/components/ApiProductInfoCard/ApiProductInfoCard.tsx"],"sourcesContent":["import React from 'react';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { useApi, configApiRef, fetchApiRef, identityApiRef } from '@backstage/core-plugin-api';\nimport { InfoCard, Progress, ResponseErrorPanel } from '@backstage/core-components';\nimport { Typography, Box, makeStyles } from '@material-ui/core';\nimport useAsync from 'react-use/lib/useAsync';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { kuadrantApiProductReadAllPermission } from '../../permissions';\nimport { ApiProductDetails } from '../ApiProductDetails';\nimport { OidcProviderCard } from '../OidcProviderCard';\n\nconst useStyles = makeStyles((theme) => ({\n label: {\n fontWeight: 600,\n color: theme.palette.text.secondary,\n marginBottom: theme.spacing(0.5),\n fontSize: '0.75rem',\n textTransform: 'uppercase',\n },\n}));\n\nexport const ApiProductInfoCard = () => {\n const classes = useStyles();\n const { entity } = useEntity();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const identityApi = useApi(identityApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n\n const { allowed: canReadAll, loading: permLoading } = useKuadrantPermission(\n kuadrantApiProductReadAllPermission\n );\n\n const namespace = entity.metadata.annotations?.['kuadrant.io/namespace'];\n const apiProductName = entity.metadata.annotations?.['kuadrant.io/apiproduct'];\n\n const { value: currentUserId } = useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n return identity.userEntityRef.split('/')[1] || 'guest';\n }, [identityApi]);\n\n const { value: apiProduct, loading, error } = useAsync(async () => {\n if (!namespace || !apiProductName) {\n return null;\n }\n\n const productResponse = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${apiProductName}`\n );\n\n if (!productResponse.ok) {\n const errorData = await productResponse.json();\n throw new Error(errorData.error || `Failed to fetch API product: ${productResponse.status}`);\n }\n\n return productResponse.json();\n }, [backendUrl, fetchApi, namespace, apiProductName]);\n\n // check if user has permission to view this api product\n const owner = apiProduct?.metadata?.annotations?.['backstage.io/owner'];\n const ownerUserId = owner?.split('/')[1];\n const canView = canReadAll || (currentUserId && ownerUserId === currentUserId);\n\n if (!namespace || !apiProductName) {\n return (\n <InfoCard title=\"API Product Information\">\n <Typography>No APIProduct linked to this API entity</Typography>\n </InfoCard>\n );\n }\n\n if (loading || permLoading) {\n return (\n <InfoCard title=\"API Product Information\">\n <Progress />\n </InfoCard>\n );\n }\n\n // show permission message if user doesn't have permission\n if (apiProduct && !canView) {\n return (\n <InfoCard title=\"API Product Information\">\n <Box p={2}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n You don't have permission to view this API product's details. Only the API owner or users with admin permissions can view this information.\n </Typography>\n </Box>\n </InfoCard>\n );\n }\n\n // also show permission message if we got a permission error from the backend\n if (error && error.message.includes('you can only read your own')) {\n return (\n <InfoCard title=\"API Product Information\">\n <Box p={2}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n You don't have permission to view this API product's details. Only the API owner or users with admin permissions can view this information.\n </Typography>\n </Box>\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title=\"API Product Information\">\n <ResponseErrorPanel error={error} />\n </InfoCard>\n );\n }\n\n if (!apiProduct) {\n return (\n <InfoCard title=\"API Product Information\">\n <Typography>APIProduct not found</Typography>\n </InfoCard>\n );\n }\n\n // check for OIDC auth scheme\n const authSchemes = apiProduct.status?.discoveredAuthScheme?.authentication || {};\n const schemeObjects = Object.values(authSchemes);\n const jwtScheme = schemeObjects.find((scheme: any) => scheme.hasOwnProperty('jwt'));\n const hasOidc = Boolean(jwtScheme);\n const jwtIssuer = (jwtScheme as any)?.jwt?.issuerUrl;\n const jwtTokenEndpoint = apiProduct.status?.oidcDiscovery?.tokenEndpoint;\n\n return (\n <>\n <InfoCard title=\"API Product Details\">\n <Box mb={2}>\n <Typography variant=\"caption\" className={classes.label}>\n Product Name\n </Typography>\n <Typography variant=\"h6\">\n {apiProduct.spec?.displayName || apiProductName}\n </Typography>\n </Box>\n <ApiProductDetails\n product={apiProduct}\n showStatus={false}\n showCatalogLink={false}\n />\n </InfoCard>\n {hasOidc && jwtIssuer && (\n <Box mt={2}>\n <OidcProviderCard\n issuerUrl={jwtIssuer}\n tokenEndpoint={jwtTokenEndpoint}\n />\n </Box>\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ApiProductInfoCard.esm.js","sources":["../../../src/components/ApiProductInfoCard/ApiProductInfoCard.tsx"],"sourcesContent":["import React from 'react';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { useApi, identityApiRef } from '@backstage/core-plugin-api';\nimport { InfoCard, Progress, ResponseErrorPanel } from '@backstage/core-components';\nimport { Typography, Box, makeStyles } from '@material-ui/core';\nimport useAsync from 'react-use/lib/useAsync';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { kuadrantApiProductReadAllPermission } from '../../permissions';\nimport { ApiProductDetails } from '../ApiProductDetails';\nimport { OidcProviderCard } from '../OidcProviderCard';\nimport { kuadrantApiRef } from '../../api';\n\nconst useStyles = makeStyles((theme) => ({\n label: {\n fontWeight: 600,\n color: theme.palette.text.secondary,\n marginBottom: theme.spacing(0.5),\n fontSize: '0.75rem',\n textTransform: 'uppercase',\n },\n}));\n\nexport const ApiProductInfoCard = () => {\n const classes = useStyles();\n const { entity } = useEntity();\n const kuadrantApi = useApi(kuadrantApiRef);\n const identityApi = useApi(identityApiRef);\n\n const { allowed: canReadAll, loading: permLoading } = useKuadrantPermission(\n kuadrantApiProductReadAllPermission\n );\n\n const namespace = entity.metadata.annotations?.['kuadrant.io/namespace'];\n const apiProductName = entity.metadata.annotations?.['kuadrant.io/apiproduct'];\n\n const { value: currentUserId } = useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n return identity.userEntityRef.split('/')[1] || 'guest';\n }, [identityApi]);\n\n const { value: apiProduct, loading, error } = useAsync(async () => {\n if (!namespace || !apiProductName) {\n return null;\n }\n\n return kuadrantApi.getApiProduct(namespace, apiProductName);\n }, [kuadrantApi, namespace, apiProductName]);\n\n // check if user has permission to view this api product\n const owner = apiProduct?.metadata?.annotations?.['backstage.io/owner'];\n const ownerUserId = owner?.split('/')[1];\n const canView = canReadAll || (currentUserId && ownerUserId === currentUserId);\n\n if (!namespace || !apiProductName) {\n return (\n <InfoCard title=\"API Product Information\">\n <Typography>No APIProduct linked to this API entity</Typography>\n </InfoCard>\n );\n }\n\n if (loading || permLoading) {\n return (\n <InfoCard title=\"API Product Information\">\n <Progress />\n </InfoCard>\n );\n }\n\n // show permission message if user doesn't have permission\n if (apiProduct && !canView) {\n return (\n <InfoCard title=\"API Product Information\">\n <Box p={2}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n You don't have permission to view this API product's details. Only the API owner or users with admin permissions can view this information.\n </Typography>\n </Box>\n </InfoCard>\n );\n }\n\n // also show permission message if we got a permission error from the backend\n if (error && error.message.includes('you can only read your own')) {\n return (\n <InfoCard title=\"API Product Information\">\n <Box p={2}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n You don't have permission to view this API product's details. Only the API owner or users with admin permissions can view this information.\n </Typography>\n </Box>\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title=\"API Product Information\">\n <ResponseErrorPanel error={error} />\n </InfoCard>\n );\n }\n\n if (!apiProduct) {\n return (\n <InfoCard title=\"API Product Information\">\n <Typography>APIProduct not found</Typography>\n </InfoCard>\n );\n }\n\n // check for OIDC auth scheme\n const authSchemes = apiProduct.status?.discoveredAuthScheme?.authentication || {};\n const schemeObjects = Object.values(authSchemes);\n const jwtScheme = schemeObjects.find((scheme: any) => scheme.hasOwnProperty('jwt'));\n const hasOidc = Boolean(jwtScheme);\n const jwtIssuer = (jwtScheme as any)?.jwt?.issuerUrl;\n const jwtTokenEndpoint = apiProduct.status?.oidcDiscovery?.tokenEndpoint;\n\n return (\n <>\n <InfoCard title=\"API Product Details\">\n <Box mb={2}>\n <Typography variant=\"caption\" className={classes.label}>\n Product Name\n </Typography>\n <Typography variant=\"h6\">\n {apiProduct.spec?.displayName || apiProductName}\n </Typography>\n </Box>\n <ApiProductDetails\n product={apiProduct}\n showStatus={false}\n showCatalogLink={false}\n />\n </InfoCard>\n {hasOidc && jwtIssuer && (\n <Box mt={2}>\n <OidcProviderCard\n issuerUrl={jwtIssuer}\n tokenEndpoint={jwtTokenEndpoint}\n />\n </Box>\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,30 +1,27 @@
1
1
  import React from 'react';
2
2
  import { useEntity } from '@backstage/plugin-catalog-react';
3
- import { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';
3
+ import { useApi } from '@backstage/core-plugin-api';
4
4
  import { Link } from '@backstage/core-components';
5
5
  import { Box, Typography } from '@material-ui/core';
6
6
  import { Alert } from '@material-ui/lab';
7
7
  import useAsync from 'react-use/lib/useAsync';
8
+ import { kuadrantApiRef } from '../../api.esm.js';
8
9
 
9
10
  const ApiProductOpenApiAlert = () => {
10
11
  const { entity } = useEntity();
11
- const config = useApi(configApiRef);
12
- const fetchApi = useApi(fetchApiRef);
13
- const backendUrl = config.getString("backend.baseUrl");
12
+ const kuadrantApi = useApi(kuadrantApiRef);
14
13
  const namespace = entity.metadata.annotations?.["kuadrant.io/namespace"];
15
14
  const apiProductName = entity.metadata.annotations?.["kuadrant.io/apiproduct"];
16
15
  const { value: apiProduct, loading, error } = useAsync(async () => {
17
16
  if (!namespace || !apiProductName) {
18
17
  return null;
19
18
  }
20
- const response = await fetchApi.fetch(
21
- `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${apiProductName}`
22
- );
23
- if (!response.ok) {
19
+ try {
20
+ return await kuadrantApi.getApiProduct(namespace, apiProductName);
21
+ } catch {
24
22
  return null;
25
23
  }
26
- return await response.json();
27
- }, [backendUrl, fetchApi, namespace, apiProductName]);
24
+ }, [kuadrantApi, namespace, apiProductName]);
28
25
  if (!namespace || !apiProductName || loading || error || !apiProduct) {
29
26
  return null;
30
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ApiProductOpenApiAlert.esm.js","sources":["../../../src/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.tsx"],"sourcesContent":["import React from \"react\";\nimport { useEntity } from \"@backstage/plugin-catalog-react\";\nimport { useApi, configApiRef, fetchApiRef } from \"@backstage/core-plugin-api\";\nimport { Link } from \"@backstage/core-components\";\nimport { Box, Typography } from \"@material-ui/core\";\nimport { Alert } from \"@material-ui/lab\";\nimport useAsync from \"react-use/lib/useAsync\";\n\n// Displays alerts for OpenAPI spec issues.\nexport const ApiProductOpenApiAlert = () => {\n const { entity } = useEntity();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString(\"backend.baseUrl\");\n\n // Get APIProduct reference from entity annotations\n const namespace = entity.metadata.annotations?.[\"kuadrant.io/namespace\"];\n const apiProductName =\n entity.metadata.annotations?.[\"kuadrant.io/apiproduct\"];\n\n // Fetch the full APIProduct resource to check status conditions\n const {value: apiProduct,loading,error,} = useAsync(async () => {\n if (!namespace || !apiProductName) {\n return null;\n }\n\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${apiProductName}`,\n );\n\n if (!response.ok) {\n return null;\n }\n\n return await response.json();\n }, [backendUrl, fetchApi, namespace, apiProductName]);\n\n // Don't render anything if data is missing or still loading\n if (!namespace || !apiProductName || loading || error || !apiProduct) {\n return null;\n }\n\n const { spec, status } = apiProduct;\n\n const openAPICondition = status?.conditions?.find(\n (c: any) => c.type === \"OpenAPISpecReady\" && c.status === \"False\",\n );\n\n if (!openAPICondition) {\n return null;\n }\n\n return (\n <Box mb={2}>\n <Alert severity=\"warning\">\n <Typography variant=\"body2\" gutterBottom>\n <strong>OpenAPI Spec Issue</strong>\n </Typography>\n <Typography variant=\"body2\" gutterBottom>\n {openAPICondition.message}\n </Typography>\n {spec.documentation?.openAPISpecURL && (\n <Typography variant=\"body2\">\n Spec URL:{\" \"}\n <Link to={spec.documentation.openAPISpecURL} target=\"_blank\">\n {spec.documentation.openAPISpecURL}\n </Link>\n </Typography>\n )}\n </Alert>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AASO,MAAM,yBAAyB,MAAM;AAC1C,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,SAAU,EAAA;AAC7B,EAAM,MAAA,MAAA,GAAS,OAAO,YAAY,CAAA;AAClC,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAM,MAAA,UAAA,GAAa,MAAO,CAAA,SAAA,CAAU,iBAAiB,CAAA;AAGrD,EAAA,MAAM,SAAY,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,uBAAuB,CAAA;AACvE,EAAA,MAAM,cACJ,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,wBAAwB,CAAA;AAGtD,EAAA,MAAM,EAAC,KAAO,EAAA,UAAA,EAAW,SAAQ,KAAM,EAAA,GAAI,SAAS,YAAY;AAChE,IAAI,IAAA,CAAC,SAAa,IAAA,CAAC,cAAgB,EAAA;AACjC,MAAO,OAAA,IAAA;AAAA;AAGT,IAAM,MAAA,QAAA,GAAW,MAAM,QAAS,CAAA,KAAA;AAAA,MAC9B,CAAG,EAAA,UAAU,CAA6B,0BAAA,EAAA,SAAS,IAAI,cAAc,CAAA;AAAA,KACvE;AAEA,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAO,OAAA,IAAA;AAAA;AAGT,IAAO,OAAA,MAAM,SAAS,IAAK,EAAA;AAAA,KAC1B,CAAC,UAAA,EAAY,QAAU,EAAA,SAAA,EAAW,cAAc,CAAC,CAAA;AAGpD,EAAA,IAAI,CAAC,SAAa,IAAA,CAAC,kBAAkB,OAAW,IAAA,KAAA,IAAS,CAAC,UAAY,EAAA;AACpE,IAAO,OAAA,IAAA;AAAA;AAGT,EAAM,MAAA,EAAE,IAAM,EAAA,MAAA,EAAW,GAAA,UAAA;AAEzB,EAAM,MAAA,gBAAA,GAAmB,QAAQ,UAAY,EAAA,IAAA;AAAA,IAC3C,CAAC,CAAW,KAAA,CAAA,CAAE,IAAS,KAAA,kBAAA,IAAsB,EAAE,MAAW,KAAA;AAAA,GAC5D;AAEA,EAAA,IAAI,CAAC,gBAAkB,EAAA;AACrB,IAAO,OAAA,IAAA;AAAA;AAGT,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAA,sCACN,KAAM,EAAA,EAAA,QAAA,EAAS,SACd,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,YAAY,EAAA,IAAA,EAAA,kBACrC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAA,EAAO,oBAAkB,CAC5B,mBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,YAAY,EAAA,IAAA,EAAA,EACrC,iBAAiB,OACpB,CAAA,EACC,KAAK,aAAe,EAAA,cAAA,wCAClB,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,EAAA,WAAA,EAChB,GACV,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,EAAI,EAAA,IAAA,CAAK,aAAc,CAAA,cAAA,EAAgB,MAAO,EAAA,QAAA,EAAA,EACjD,KAAK,aAAc,CAAA,cACtB,CACF,CAEJ,CACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"ApiProductOpenApiAlert.esm.js","sources":["../../../src/components/ApiProductOpenApiAlert/ApiProductOpenApiAlert.tsx"],"sourcesContent":["import React from \"react\";\nimport { useEntity } from \"@backstage/plugin-catalog-react\";\nimport { useApi } from \"@backstage/core-plugin-api\";\nimport { Link } from \"@backstage/core-components\";\nimport { Box, Typography } from \"@material-ui/core\";\nimport { Alert } from \"@material-ui/lab\";\nimport useAsync from \"react-use/lib/useAsync\";\nimport { kuadrantApiRef } from \"../../api\";\n\n// Displays alerts for OpenAPI spec issues.\nexport const ApiProductOpenApiAlert = () => {\n const { entity } = useEntity();\n const kuadrantApi = useApi(kuadrantApiRef);\n\n // Get APIProduct reference from entity annotations\n const namespace = entity.metadata.annotations?.[\"kuadrant.io/namespace\"];\n const apiProductName =\n entity.metadata.annotations?.[\"kuadrant.io/apiproduct\"];\n\n // Fetch the full APIProduct resource to check status conditions\n const { value: apiProduct, loading, error } = useAsync(async () => {\n if (!namespace || !apiProductName) {\n return null;\n }\n\n try {\n return await kuadrantApi.getApiProduct(namespace, apiProductName);\n } catch {\n return null;\n }\n }, [kuadrantApi, namespace, apiProductName]);\n\n // Don't render anything if data is missing or still loading\n if (!namespace || !apiProductName || loading || error || !apiProduct) {\n return null;\n }\n\n const { spec, status } = apiProduct;\n\n const openAPICondition = status?.conditions?.find(\n (c: any) => c.type === \"OpenAPISpecReady\" && c.status === \"False\",\n );\n\n if (!openAPICondition) {\n return null;\n }\n\n return (\n <Box mb={2}>\n <Alert severity=\"warning\">\n <Typography variant=\"body2\" gutterBottom>\n <strong>OpenAPI Spec Issue</strong>\n </Typography>\n <Typography variant=\"body2\" gutterBottom>\n {openAPICondition.message}\n </Typography>\n {spec.documentation?.openAPISpecURL && (\n <Typography variant=\"body2\">\n Spec URL:{\" \"}\n <Link to={spec.documentation.openAPISpecURL} target=\"_blank\">\n {spec.documentation.openAPISpecURL}\n </Link>\n </Typography>\n )}\n </Alert>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAUO,MAAM,yBAAyB,MAAM;AAC1C,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,SAAU,EAAA;AAC7B,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AAGzC,EAAA,MAAM,SAAY,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,uBAAuB,CAAA;AACvE,EAAA,MAAM,cACJ,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,wBAAwB,CAAA;AAGxD,EAAA,MAAM,EAAE,KAAO,EAAA,UAAA,EAAY,SAAS,KAAM,EAAA,GAAI,SAAS,YAAY;AACjE,IAAI,IAAA,CAAC,SAAa,IAAA,CAAC,cAAgB,EAAA;AACjC,MAAO,OAAA,IAAA;AAAA;AAGT,IAAI,IAAA;AACF,MAAA,OAAO,MAAM,WAAA,CAAY,aAAc,CAAA,SAAA,EAAW,cAAc,CAAA;AAAA,KAC1D,CAAA,MAAA;AACN,MAAO,OAAA,IAAA;AAAA;AACT,GACC,EAAA,CAAC,WAAa,EAAA,SAAA,EAAW,cAAc,CAAC,CAAA;AAG3C,EAAA,IAAI,CAAC,SAAa,IAAA,CAAC,kBAAkB,OAAW,IAAA,KAAA,IAAS,CAAC,UAAY,EAAA;AACpE,IAAO,OAAA,IAAA;AAAA;AAGT,EAAM,MAAA,EAAE,IAAM,EAAA,MAAA,EAAW,GAAA,UAAA;AAEzB,EAAM,MAAA,gBAAA,GAAmB,QAAQ,UAAY,EAAA,IAAA;AAAA,IAC3C,CAAC,CAAW,KAAA,CAAA,CAAE,IAAS,KAAA,kBAAA,IAAsB,EAAE,MAAW,KAAA;AAAA,GAC5D;AAEA,EAAA,IAAI,CAAC,gBAAkB,EAAA;AACrB,IAAO,OAAA,IAAA;AAAA;AAGT,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAA,sCACN,KAAM,EAAA,EAAA,QAAA,EAAS,SACd,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,YAAY,EAAA,IAAA,EAAA,kBACrC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAA,EAAO,oBAAkB,CAC5B,mBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAQ,YAAY,EAAA,IAAA,EAAA,EACrC,iBAAiB,OACpB,CAAA,EACC,KAAK,aAAe,EAAA,cAAA,wCAClB,UAAW,EAAA,EAAA,OAAA,EAAQ,OAAQ,EAAA,EAAA,WAAA,EAChB,GACV,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,EAAI,EAAA,IAAA,CAAK,aAAc,CAAA,cAAA,EAAgB,MAAO,EAAA,QAAA,EAAA,EACjD,KAAK,aAAc,CAAA,cACtB,CACF,CAEJ,CACF,CAAA;AAEJ;;;;"}
@@ -1,5 +1,6 @@
1
1
  import React, { useState, useMemo } from 'react';
2
- import { useApi, configApiRef, fetchApiRef, identityApiRef, alertApiRef } from '@backstage/core-plugin-api';
2
+ import { useApi, identityApiRef, alertApiRef } from '@backstage/core-plugin-api';
3
+ import { kuadrantApiRef } from '../../api.esm.js';
3
4
  import { useAsync } from 'react-use';
4
5
  import { Progress, ResponseErrorPanel, Table, Link } from '@backstage/core-components';
5
6
  import { kuadrantApiKeyUpdateAllPermission, kuadrantApiKeyUpdateOwnPermission } from '../../permissions.esm.js';
@@ -8,8 +9,7 @@ import { makeStyles, Box, Typography, Button, Dialog, DialogTitle, DialogContent
8
9
  import CheckCircleIcon from '@material-ui/icons/CheckCircle';
9
10
  import CancelIcon from '@material-ui/icons/Cancel';
10
11
  import { FilterPanel } from '../FilterPanel/FilterPanel.esm.js';
11
- import { getStatusChipStyle } from '../../utils/styles.esm.js';
12
- import { handleFetchError } from '../../utils/errors.esm.js';
12
+ import { getApprovalQueueStatusChipStyle } from '../../utils/styles.esm.js';
13
13
 
14
14
  const useStyles = makeStyles((theme) => ({
15
15
  container: {
@@ -249,11 +249,9 @@ const BulkAlertDialog = ({
249
249
  };
250
250
  const ApprovalQueueTable = () => {
251
251
  const classes = useStyles();
252
- const config = useApi(configApiRef);
253
- const fetchApi = useApi(fetchApiRef);
254
252
  const identityApi = useApi(identityApiRef);
255
253
  const alertApi = useApi(alertApiRef);
256
- const backendUrl = config.getString("backend.baseUrl");
254
+ const kuadrantApi = useApi(kuadrantApiRef);
257
255
  const [refresh, setRefresh] = useState(0);
258
256
  const [selectedRequests, setSelectedRequests] = useState([]);
259
257
  const [dialogState, setDialogState] = useState({
@@ -293,23 +291,28 @@ const ApprovalQueueTable = () => {
293
291
  const { value, loading, error } = useAsync(async () => {
294
292
  const identity = await identityApi.getBackstageIdentity();
295
293
  const reviewedBy = identity.userEntityRef;
296
- const [requestsResponse, apiProductsResponse] = await Promise.all([
297
- fetchApi.fetch(`${backendUrl}/api/kuadrant/requests`),
298
- fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`)
299
- ]);
300
- if (!requestsResponse.ok) {
301
- return {
302
- allRequests: [],
303
- reviewedBy,
304
- ownedApiProducts: /* @__PURE__ */ new Set()
305
- };
306
- }
307
- const contentType = requestsResponse.headers.get("content-type");
308
- if (!contentType?.includes("application/json")) {
294
+ try {
295
+ const [apiKeyRequests, apiProducts] = await Promise.all([
296
+ kuadrantApi.getAllRequests(),
297
+ kuadrantApi.getApiProducts()
298
+ ]);
299
+ const allRequests = apiKeyRequests.items || [];
300
+ const ownedApiProducts = /* @__PURE__ */ new Set();
301
+ for (const product of apiProducts.items || []) {
302
+ const owner = product.metadata?.annotations?.["backstage.io/owner"];
303
+ if (owner === reviewedBy) {
304
+ ownedApiProducts.add(
305
+ `${product.metadata.namespace}/${product.metadata.name}`
306
+ );
307
+ }
308
+ }
309
+ return { allRequests, reviewedBy, ownedApiProducts };
310
+ } catch (err) {
311
+ const errorMessage = err instanceof Error ? err.message : "unknown error occurred";
309
312
  alertApi.post({
310
- message: "Unexpected content-type from the server response.",
313
+ message: `Failed to get resources. ${errorMessage}`,
311
314
  display: "transient",
312
- severity: "warning"
315
+ severity: "error"
313
316
  });
314
317
  return {
315
318
  allRequests: [],
@@ -317,22 +320,7 @@ const ApprovalQueueTable = () => {
317
320
  ownedApiProducts: /* @__PURE__ */ new Set()
318
321
  };
319
322
  }
320
- const data = await requestsResponse.json();
321
- const allRequests = data.items || [];
322
- const ownedApiProducts = /* @__PURE__ */ new Set();
323
- if (apiProductsResponse.ok) {
324
- const apiProductsData = await apiProductsResponse.json();
325
- for (const product of apiProductsData.items || []) {
326
- const owner = product.metadata?.annotations?.["backstage.io/owner"];
327
- if (owner === reviewedBy) {
328
- ownedApiProducts.add(
329
- `${product.metadata.namespace}/${product.metadata.name}`
330
- );
331
- }
332
- }
333
- }
334
- return { allRequests, reviewedBy, ownedApiProducts };
335
- }, [backendUrl, fetchApi, identityApi, refresh]);
323
+ }, [kuadrantApi, identityApi, refresh]);
336
324
  const filterSections = useMemo(() => {
337
325
  if (!value?.allRequests) return [];
338
326
  const statusCounts = { Approved: 0, Pending: 0, Rejected: 0 };
@@ -427,17 +415,9 @@ const ApprovalQueueTable = () => {
427
415
  const handleConfirm = async () => {
428
416
  if (!dialogState.request || !value) return;
429
417
  setDialogState((prev) => ({ ...prev, processing: true }));
430
- const endpoint = dialogState.action === "approve" ? `${backendUrl}/api/kuadrant/requests/${dialogState.request.metadata.namespace}/${dialogState.request.metadata.name}/approve` : `${backendUrl}/api/kuadrant/requests/${dialogState.request.metadata.namespace}/${dialogState.request.metadata.name}/reject`;
418
+ const apikeyRequestFn = dialogState.action === "approve" ? (ns, n, r) => kuadrantApi.approveRequest(ns, n, r) : (ns, n, r) => kuadrantApi.rejectRequest(ns, n, r);
431
419
  try {
432
- const response = await fetchApi.fetch(endpoint, {
433
- method: "POST",
434
- headers: { "Content-Type": "application/json" },
435
- body: JSON.stringify({ reviewedBy: value.reviewedBy })
436
- });
437
- if (!response.ok) {
438
- const err = await handleFetchError(response);
439
- throw new Error(err);
440
- }
420
+ await apikeyRequestFn(dialogState.request.metadata.namespace, dialogState.request.metadata.name, value.reviewedBy);
441
421
  setDialogState({
442
422
  open: false,
443
423
  request: null,
@@ -490,25 +470,13 @@ const ApprovalQueueTable = () => {
490
470
  setBulkDialogState((prev) => ({ ...prev, processing: true }));
491
471
  setBulkAlertDialogState({ open: false, results: [], isApprove: true });
492
472
  const isApprove = bulkDialogState.action === "approve";
493
- const endpoint = isApprove ? `${backendUrl}/api/kuadrant/requests/bulk-approve` : `${backendUrl}/api/kuadrant/requests/bulk-reject`;
473
+ const apiKeyRequestsFn = isApprove ? (req, rb) => kuadrantApi.bulkApproveRequests(req, rb) : (req, rb) => kuadrantApi.bulkRejectRequests(req, rb);
494
474
  try {
495
- const response = await fetchApi.fetch(endpoint, {
496
- method: "POST",
497
- headers: { "Content-Type": "application/json" },
498
- body: JSON.stringify({
499
- requests: bulkDialogState.requests.map((r) => ({
500
- namespace: r.metadata.namespace,
501
- name: r.metadata.name
502
- })),
503
- reviewedBy: value.reviewedBy
504
- })
505
- });
506
- if (!response.ok) {
507
- const err = await handleFetchError(response);
508
- throw new Error(err);
509
- }
510
- const bulkResponseRaw = await response.json();
511
- const bulkResponse = bulkResponseRaw.results || [];
475
+ const requests = bulkDialogState.requests.map((r) => ({
476
+ namespace: r.metadata.namespace,
477
+ name: r.metadata.name
478
+ }));
479
+ const bulkResponse = await apiKeyRequestsFn(requests, value.reviewedBy) || [];
512
480
  const successfulItems = bulkResponse.filter((res) => res.success);
513
481
  const failedItems = bulkResponse.filter((res) => !res.success);
514
482
  const totalSuccess = failedItems.length === 0;
@@ -571,7 +539,7 @@ const ApprovalQueueTable = () => {
571
539
  field: "status.phase",
572
540
  render: (row) => {
573
541
  const phase = row.status?.phase || "Pending";
574
- return /* @__PURE__ */ React.createElement(Chip, { label: phase, size: "small", style: getStatusChipStyle(phase) });
542
+ return /* @__PURE__ */ React.createElement(Chip, { label: phase, size: "small", style: getApprovalQueueStatusChipStyle(phase) });
575
543
  }
576
544
  },
577
545
  {