openvsx-webui-test 0.19.0-dev.2 → 0.20.0-dev.1

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 (361) hide show
  1. package/lib/components/banner.js +1 -2
  2. package/lib/components/banner.js.map +1 -1
  3. package/lib/components/delayed-load-indicator.js +2 -4
  4. package/lib/components/delayed-load-indicator.js.map +1 -1
  5. package/lib/components/generate-token-dialog.d.ts +22 -0
  6. package/lib/components/generate-token-dialog.d.ts.map +1 -0
  7. package/lib/components/generate-token-dialog.js +91 -0
  8. package/lib/components/generate-token-dialog.js.map +1 -0
  9. package/lib/components/rate-limiting/customer/general-details.d.ts +20 -0
  10. package/lib/components/rate-limiting/customer/general-details.d.ts.map +1 -0
  11. package/lib/components/rate-limiting/customer/general-details.js +8 -0
  12. package/lib/components/rate-limiting/customer/general-details.js.map +1 -0
  13. package/lib/components/rate-limiting/customer/index.d.ts +17 -0
  14. package/lib/components/rate-limiting/customer/index.d.ts.map +1 -0
  15. package/lib/components/rate-limiting/customer/index.js +15 -0
  16. package/lib/components/rate-limiting/customer/index.js.map +1 -0
  17. package/lib/components/rate-limiting/customer/usage-stats.d.ts +24 -0
  18. package/lib/components/rate-limiting/customer/usage-stats.d.ts.map +1 -0
  19. package/lib/components/rate-limiting/customer/usage-stats.js +6 -0
  20. package/lib/components/rate-limiting/customer/usage-stats.js.map +1 -0
  21. package/lib/{pages/admin-dashboard → components/rate-limiting}/usage-stats/usage-stats-chart.d.ts +5 -2
  22. package/lib/components/rate-limiting/usage-stats/usage-stats-chart.d.ts.map +1 -0
  23. package/lib/{pages/admin-dashboard → components/rate-limiting}/usage-stats/usage-stats-chart.js +32 -22
  24. package/lib/components/rate-limiting/usage-stats/usage-stats-chart.js.map +1 -0
  25. package/lib/components/rate-limiting/usage-stats/usage-stats-utils.d.ts +15 -0
  26. package/lib/components/rate-limiting/usage-stats/usage-stats-utils.d.ts.map +1 -0
  27. package/{src/pages/admin-dashboard/usage-stats/usage-stats-utils.ts → lib/components/rate-limiting/usage-stats/usage-stats-utils.js} +4 -3
  28. package/lib/components/rate-limiting/usage-stats/usage-stats-utils.js.map +1 -0
  29. package/lib/components/rate-limiting/usage-stats/use-usage-stats.d.ts +22 -0
  30. package/lib/components/rate-limiting/usage-stats/use-usage-stats.d.ts.map +1 -0
  31. package/lib/components/rate-limiting/usage-stats/use-usage-stats.js +58 -0
  32. package/lib/components/rate-limiting/usage-stats/use-usage-stats.js.map +1 -0
  33. package/lib/components/scan-admin/common/conditional-tooltip.js +4 -16
  34. package/lib/components/scan-admin/common/conditional-tooltip.js.map +1 -1
  35. package/lib/components/scan-admin/common/file-table.js +24 -13
  36. package/lib/components/scan-admin/common/file-table.js.map +1 -1
  37. package/lib/components/scan-admin/dialogs/quarantine-dialog.js +4 -8
  38. package/lib/components/scan-admin/dialogs/quarantine-dialog.js.map +1 -1
  39. package/lib/components/scan-admin/scan-card/scan-card-content.js +2 -2
  40. package/lib/components/scan-admin/scan-card/scan-card-content.js.map +1 -1
  41. package/lib/components/scan-admin/scan-card/scan-card-expand-strip-badges.js +21 -16
  42. package/lib/components/scan-admin/scan-card/scan-card-expand-strip-badges.js.map +1 -1
  43. package/lib/components/scan-admin/scan-card/scan-card-expanded-content.js +1 -2
  44. package/lib/components/scan-admin/scan-card/scan-card-expanded-content.js.map +1 -1
  45. package/lib/components/scan-admin/scan-card/scan-card-header.js +10 -5
  46. package/lib/components/scan-admin/scan-card/scan-card-header.js.map +1 -1
  47. package/lib/components/scan-admin/scan-card/utils.js +1 -2
  48. package/lib/components/scan-admin/scan-card/utils.js.map +1 -1
  49. package/lib/components/scan-admin/tab-contents/quarantined-tab-content.js +4 -6
  50. package/lib/components/scan-admin/tab-contents/quarantined-tab-content.js.map +1 -1
  51. package/lib/components/sidepanel/drawer-header.d.ts +14 -0
  52. package/lib/components/sidepanel/drawer-header.d.ts.map +1 -0
  53. package/lib/components/sidepanel/drawer-header.js +22 -0
  54. package/lib/components/sidepanel/drawer-header.js.map +1 -0
  55. package/lib/components/sidepanel/navigation-item.d.ts.map +1 -1
  56. package/lib/components/sidepanel/navigation-item.js +3 -3
  57. package/lib/components/sidepanel/navigation-item.js.map +1 -1
  58. package/lib/components/sidepanel/sidepanel.d.ts +7 -1
  59. package/lib/components/sidepanel/sidepanel.d.ts.map +1 -1
  60. package/lib/components/sidepanel/sidepanel.js +12 -13
  61. package/lib/components/sidepanel/sidepanel.js.map +1 -1
  62. package/lib/components/text-divider.js +1 -2
  63. package/lib/components/text-divider.js.map +1 -1
  64. package/lib/components/timestamp.js +2 -3
  65. package/lib/components/timestamp.js.map +1 -1
  66. package/lib/context/scan-admin/scan-api-actions.js +7 -16
  67. package/lib/context/scan-admin/scan-api-actions.js.map +1 -1
  68. package/lib/context/scan-admin/scan-api-effects.js +77 -93
  69. package/lib/context/scan-admin/scan-api-effects.js.map +1 -1
  70. package/lib/context/scan-admin/scan-context.d.ts.map +1 -1
  71. package/lib/context/scan-admin/scan-context.js +1 -0
  72. package/lib/context/scan-admin/scan-context.js.map +1 -1
  73. package/lib/context/scan-admin/scan-reducer.js +134 -53
  74. package/lib/context/scan-admin/scan-reducer.js.map +1 -1
  75. package/lib/default/default-app.d.ts +1 -1
  76. package/lib/default/default-app.d.ts.map +1 -1
  77. package/lib/default/default-app.js +11 -22
  78. package/lib/default/default-app.js.map +1 -1
  79. package/lib/default/menu-content.d.ts +1 -1
  80. package/lib/default/menu-content.d.ts.map +1 -1
  81. package/lib/default/menu-content.js +7 -3
  82. package/lib/default/menu-content.js.map +1 -1
  83. package/lib/default/page-settings.js +13 -18
  84. package/lib/default/page-settings.js.map +1 -1
  85. package/lib/extension-registry-service.d.ts +17 -1
  86. package/lib/extension-registry-service.d.ts.map +1 -1
  87. package/lib/extension-registry-service.js +659 -629
  88. package/lib/extension-registry-service.js.map +1 -1
  89. package/lib/extension-registry-types.d.ts +13 -0
  90. package/lib/extension-registry-types.d.ts.map +1 -1
  91. package/lib/hooks/scan-admin/use-auto-rejected-tab.js +5 -7
  92. package/lib/hooks/scan-admin/use-auto-rejected-tab.js.map +1 -1
  93. package/lib/hooks/scan-admin/use-quarantined-tab.js +5 -7
  94. package/lib/hooks/scan-admin/use-quarantined-tab.js.map +1 -1
  95. package/lib/main.d.ts.map +1 -1
  96. package/lib/main.js +8 -16
  97. package/lib/main.js.map +1 -1
  98. package/lib/other-pages.d.ts +12 -0
  99. package/lib/other-pages.d.ts.map +1 -1
  100. package/lib/other-pages.js +25 -12
  101. package/lib/other-pages.js.map +1 -1
  102. package/lib/pages/admin-dashboard/admin-dashboard.d.ts +0 -12
  103. package/lib/pages/admin-dashboard/admin-dashboard.d.ts.map +1 -1
  104. package/lib/pages/admin-dashboard/admin-dashboard.js +126 -49
  105. package/lib/pages/admin-dashboard/admin-dashboard.js.map +1 -1
  106. package/lib/pages/admin-dashboard/admin-routes.d.ts +25 -0
  107. package/lib/pages/admin-dashboard/admin-routes.d.ts.map +1 -0
  108. package/lib/pages/admin-dashboard/admin-routes.js +27 -0
  109. package/lib/pages/admin-dashboard/admin-routes.js.map +1 -0
  110. package/lib/pages/admin-dashboard/components/data-grid-filter-operators.d.ts +1 -9
  111. package/lib/pages/admin-dashboard/components/data-grid-filter-operators.d.ts.map +1 -1
  112. package/lib/pages/admin-dashboard/components/data-grid-filter-operators.js +17 -15
  113. package/lib/pages/admin-dashboard/components/data-grid-filter-operators.js.map +1 -1
  114. package/lib/pages/admin-dashboard/components/data-grid-filter.d.ts +22 -0
  115. package/lib/pages/admin-dashboard/components/data-grid-filter.d.ts.map +1 -0
  116. package/lib/pages/admin-dashboard/components/data-grid-filter.js +13 -0
  117. package/lib/pages/admin-dashboard/components/data-grid-filter.js.map +1 -0
  118. package/lib/pages/admin-dashboard/components/index.d.ts +2 -1
  119. package/lib/pages/admin-dashboard/components/index.d.ts.map +1 -1
  120. package/lib/pages/admin-dashboard/components/index.js +2 -1
  121. package/lib/pages/admin-dashboard/components/index.js.map +1 -1
  122. package/lib/pages/admin-dashboard/{usage-stats/usage-stats-utils.d.ts → customers/customer-details.d.ts} +3 -2
  123. package/lib/pages/admin-dashboard/customers/customer-details.d.ts.map +1 -0
  124. package/lib/pages/admin-dashboard/customers/customer-details.js +78 -0
  125. package/lib/pages/admin-dashboard/customers/customer-details.js.map +1 -0
  126. package/lib/pages/admin-dashboard/customers/customer-form-dialog.d.ts +1 -1
  127. package/lib/pages/admin-dashboard/customers/customer-form-dialog.d.ts.map +1 -1
  128. package/lib/pages/admin-dashboard/customers/customer-form-dialog.js +33 -34
  129. package/lib/pages/admin-dashboard/customers/customer-form-dialog.js.map +1 -1
  130. package/lib/pages/admin-dashboard/customers/customer-member-list.d.ts +19 -0
  131. package/lib/pages/admin-dashboard/customers/customer-member-list.d.ts.map +1 -0
  132. package/lib/pages/admin-dashboard/customers/customer-member-list.js +88 -0
  133. package/lib/pages/admin-dashboard/customers/customer-member-list.js.map +1 -0
  134. package/lib/pages/admin-dashboard/customers/customer-token-list.d.ts +19 -0
  135. package/lib/pages/admin-dashboard/customers/customer-token-list.d.ts.map +1 -0
  136. package/lib/pages/admin-dashboard/customers/customer-token-list.js +70 -0
  137. package/lib/pages/admin-dashboard/customers/customer-token-list.js.map +1 -0
  138. package/lib/pages/admin-dashboard/customers/customers.d.ts +1 -1
  139. package/lib/pages/admin-dashboard/customers/customers.js +20 -29
  140. package/lib/pages/admin-dashboard/customers/customers.js.map +1 -1
  141. package/lib/pages/admin-dashboard/customers/delete-customer-dialog.js +4 -14
  142. package/lib/pages/admin-dashboard/customers/delete-customer-dialog.js.map +1 -1
  143. package/lib/pages/admin-dashboard/extension-admin.js +7 -16
  144. package/lib/pages/admin-dashboard/extension-admin.js.map +1 -1
  145. package/lib/pages/admin-dashboard/extension-remove-dialog.js +3 -12
  146. package/lib/pages/admin-dashboard/extension-remove-dialog.js.map +1 -1
  147. package/lib/pages/admin-dashboard/extension-version-container.js +3 -5
  148. package/lib/pages/admin-dashboard/extension-version-container.js.map +1 -1
  149. package/lib/pages/admin-dashboard/logs/logs.d.ts.map +1 -1
  150. package/lib/pages/admin-dashboard/logs/logs.js +6 -24
  151. package/lib/pages/admin-dashboard/logs/logs.js.map +1 -1
  152. package/lib/pages/admin-dashboard/namespace-admin.js +7 -16
  153. package/lib/pages/admin-dashboard/namespace-admin.js.map +1 -1
  154. package/lib/pages/admin-dashboard/namespace-change-dialog.js +3 -12
  155. package/lib/pages/admin-dashboard/namespace-change-dialog.js.map +1 -1
  156. package/lib/pages/admin-dashboard/namespace-input.js +1 -1
  157. package/lib/pages/admin-dashboard/namespace-input.js.map +1 -1
  158. package/lib/pages/admin-dashboard/publisher-admin.d.ts.map +1 -1
  159. package/lib/pages/admin-dashboard/publisher-admin.js +28 -22
  160. package/lib/pages/admin-dashboard/publisher-admin.js.map +1 -1
  161. package/lib/pages/admin-dashboard/publisher-revoke-dialog.js +5 -15
  162. package/lib/pages/admin-dashboard/publisher-revoke-dialog.js.map +1 -1
  163. package/lib/pages/admin-dashboard/publisher-revoke-tokens-button.js +3 -12
  164. package/lib/pages/admin-dashboard/publisher-revoke-tokens-button.js.map +1 -1
  165. package/lib/pages/admin-dashboard/tiers/delete-tier-dialog.js +4 -13
  166. package/lib/pages/admin-dashboard/tiers/delete-tier-dialog.js.map +1 -1
  167. package/lib/pages/admin-dashboard/tiers/tier-form-dialog.js +34 -23
  168. package/lib/pages/admin-dashboard/tiers/tier-form-dialog.js.map +1 -1
  169. package/lib/pages/admin-dashboard/tiers/tiers.js +12 -21
  170. package/lib/pages/admin-dashboard/tiers/tiers.js.map +1 -1
  171. package/lib/pages/admin-dashboard/usage-stats/usage-stats-search.js +3 -14
  172. package/lib/pages/admin-dashboard/usage-stats/usage-stats-search.js.map +1 -1
  173. package/lib/pages/admin-dashboard/usage-stats/usage-stats.d.ts.map +1 -1
  174. package/lib/pages/admin-dashboard/usage-stats/usage-stats.js +11 -45
  175. package/lib/pages/admin-dashboard/usage-stats/usage-stats.js.map +1 -1
  176. package/lib/pages/admin-dashboard/usage-stats/use-usage-stats.d.ts +22 -0
  177. package/lib/pages/admin-dashboard/usage-stats/use-usage-stats.d.ts.map +1 -0
  178. package/lib/pages/admin-dashboard/usage-stats/use-usage-stats.js +58 -0
  179. package/lib/pages/admin-dashboard/usage-stats/use-usage-stats.js.map +1 -0
  180. package/lib/pages/admin-dashboard/welcome.js +1 -1
  181. package/lib/pages/admin-dashboard/welcome.js.map +1 -1
  182. package/lib/pages/extension-detail/extension-detail-changes.js +3 -12
  183. package/lib/pages/extension-detail/extension-detail-changes.js.map +1 -1
  184. package/lib/pages/extension-detail/extension-detail-overview.js +6 -16
  185. package/lib/pages/extension-detail/extension-detail-overview.js.map +1 -1
  186. package/lib/pages/extension-detail/extension-detail-reviews.js +12 -24
  187. package/lib/pages/extension-detail/extension-detail-reviews.js.map +1 -1
  188. package/lib/pages/extension-detail/extension-detail-routes.d.ts +32 -0
  189. package/lib/pages/extension-detail/extension-detail-routes.d.ts.map +1 -0
  190. package/lib/pages/extension-detail/extension-detail-routes.js +35 -0
  191. package/lib/pages/extension-detail/extension-detail-routes.js.map +1 -0
  192. package/lib/pages/extension-detail/extension-detail.d.ts +0 -19
  193. package/lib/pages/extension-detail/extension-detail.d.ts.map +1 -1
  194. package/lib/pages/extension-detail/extension-detail.js +28 -50
  195. package/lib/pages/extension-detail/extension-detail.js.map +1 -1
  196. package/lib/pages/extension-detail/extension-rating-stars.js +1 -2
  197. package/lib/pages/extension-detail/extension-rating-stars.js.map +1 -1
  198. package/lib/pages/extension-detail/extension-review-dialog.js +4 -14
  199. package/lib/pages/extension-detail/extension-review-dialog.js.map +1 -1
  200. package/lib/pages/extension-list/extension-list-container.d.ts +0 -3
  201. package/lib/pages/extension-list/extension-list-container.d.ts.map +1 -1
  202. package/lib/pages/extension-list/extension-list-container.js +5 -10
  203. package/lib/pages/extension-list/extension-list-container.js.map +1 -1
  204. package/lib/pages/extension-list/extension-list-header.js +3 -6
  205. package/lib/pages/extension-list/extension-list-header.js.map +1 -1
  206. package/lib/pages/extension-list/extension-list-item.js +7 -17
  207. package/lib/pages/extension-list/extension-list-item.js.map +1 -1
  208. package/lib/pages/extension-list/extension-list-routes.d.ts +16 -0
  209. package/lib/pages/extension-list/extension-list-routes.d.ts.map +1 -0
  210. package/lib/pages/extension-list/extension-list-routes.js +18 -0
  211. package/lib/pages/extension-list/extension-list-routes.js.map +1 -0
  212. package/lib/pages/extension-list/extension-list-searchfield.js +4 -7
  213. package/lib/pages/extension-list/extension-list-searchfield.js.map +1 -1
  214. package/lib/pages/extension-list/extension-list.js +8 -19
  215. package/lib/pages/extension-list/extension-list.js.map +1 -1
  216. package/lib/pages/namespace-detail/namespace-detail-routes.d.ts +20 -0
  217. package/lib/pages/namespace-detail/namespace-detail-routes.d.ts.map +1 -0
  218. package/lib/pages/namespace-detail/namespace-detail-routes.js +23 -0
  219. package/lib/pages/namespace-detail/namespace-detail-routes.js.map +1 -0
  220. package/lib/pages/namespace-detail/namespace-detail.d.ts +0 -7
  221. package/lib/pages/namespace-detail/namespace-detail.d.ts.map +1 -1
  222. package/lib/pages/namespace-detail/namespace-detail.js +4 -24
  223. package/lib/pages/namespace-detail/namespace-detail.js.map +1 -1
  224. package/lib/pages/user/add-namespace-member-dialog.d.ts.map +1 -1
  225. package/lib/pages/user/add-namespace-member-dialog.js +8 -67
  226. package/lib/pages/user/add-namespace-member-dialog.js.map +1 -1
  227. package/lib/pages/user/add-user-dialog.d.ts +25 -0
  228. package/lib/pages/user/add-user-dialog.d.ts.map +1 -0
  229. package/lib/pages/user/add-user-dialog.js +66 -0
  230. package/lib/pages/user/add-user-dialog.js.map +1 -0
  231. package/lib/pages/user/avatar.js +3 -3
  232. package/lib/pages/user/avatar.js.map +1 -1
  233. package/lib/pages/user/create-namespace-dialog.js +3 -12
  234. package/lib/pages/user/create-namespace-dialog.js.map +1 -1
  235. package/lib/pages/user/{generate-token-dialog.d.ts → generate-access-token-dialog.d.ts} +2 -2
  236. package/lib/pages/user/generate-access-token-dialog.d.ts.map +1 -0
  237. package/lib/pages/user/generate-access-token-dialog.js +33 -0
  238. package/lib/pages/user/generate-access-token-dialog.js.map +1 -0
  239. package/lib/pages/user/logout.js +3 -12
  240. package/lib/pages/user/logout.js.map +1 -1
  241. package/lib/pages/user/publish-extension-dialog.js +12 -21
  242. package/lib/pages/user/publish-extension-dialog.js.map +1 -1
  243. package/lib/pages/user/user-namespace-details.js +29 -42
  244. package/lib/pages/user/user-namespace-details.js.map +1 -1
  245. package/lib/pages/user/user-namespace-extension-list-item.js +6 -8
  246. package/lib/pages/user/user-namespace-extension-list-item.js.map +1 -1
  247. package/lib/pages/user/user-namespace-extension-list.js +6 -15
  248. package/lib/pages/user/user-namespace-extension-list.js.map +1 -1
  249. package/lib/pages/user/user-namespace-member-component.js +1 -1
  250. package/lib/pages/user/user-namespace-member-component.js.map +1 -1
  251. package/lib/pages/user/user-namespace-member-list.js +9 -18
  252. package/lib/pages/user/user-namespace-member-list.js.map +1 -1
  253. package/lib/pages/user/user-publisher-agreement.js +8 -18
  254. package/lib/pages/user/user-publisher-agreement.js.map +1 -1
  255. package/lib/pages/user/user-setting-tabs.d.ts.map +1 -1
  256. package/lib/pages/user/user-setting-tabs.js +2 -2
  257. package/lib/pages/user/user-setting-tabs.js.map +1 -1
  258. package/lib/pages/user/user-settings-customer-detail.d.ts +19 -0
  259. package/lib/pages/user/user-settings-customer-detail.d.ts.map +1 -0
  260. package/lib/pages/user/user-settings-customer-detail.js +9 -0
  261. package/lib/pages/user/user-settings-customer-detail.js.map +1 -0
  262. package/lib/pages/user/user-settings-customers.d.ts +15 -0
  263. package/lib/pages/user/user-settings-customers.d.ts.map +1 -0
  264. package/lib/pages/user/user-settings-customers.js +66 -0
  265. package/lib/pages/user/user-settings-customers.js.map +1 -0
  266. package/lib/pages/user/user-settings-delete-extension.js +8 -17
  267. package/lib/pages/user/user-settings-delete-extension.js.map +1 -1
  268. package/lib/pages/user/user-settings-extensions.js +3 -12
  269. package/lib/pages/user/user-settings-extensions.js.map +1 -1
  270. package/lib/pages/user/user-settings-namespace-detail.d.ts.map +1 -1
  271. package/lib/pages/user/user-settings-namespace-detail.js +4 -12
  272. package/lib/pages/user/user-settings-namespace-detail.js.map +1 -1
  273. package/lib/pages/user/user-settings-namespaces.js +6 -15
  274. package/lib/pages/user/user-settings-namespaces.js.map +1 -1
  275. package/lib/pages/user/user-settings-profile.js +1 -2
  276. package/lib/pages/user/user-settings-profile.js.map +1 -1
  277. package/lib/pages/user/user-settings-routes.d.ts +23 -0
  278. package/lib/pages/user/user-settings-routes.d.ts.map +1 -0
  279. package/lib/pages/user/user-settings-routes.js +25 -0
  280. package/lib/pages/user/user-settings-routes.js.map +1 -0
  281. package/lib/pages/user/user-settings-tokens.d.ts +0 -7
  282. package/lib/pages/user/user-settings-tokens.d.ts.map +1 -1
  283. package/lib/pages/user/user-settings-tokens.js +15 -25
  284. package/lib/pages/user/user-settings-tokens.js.map +1 -1
  285. package/lib/pages/user/user-settings.d.ts +0 -9
  286. package/lib/pages/user/user-settings.d.ts.map +1 -1
  287. package/lib/pages/user/user-settings.js +4 -12
  288. package/lib/pages/user/user-settings.js.map +1 -1
  289. package/lib/server-request.js +64 -76
  290. package/lib/server-request.js.map +1 -1
  291. package/lib/utils.js +2 -4
  292. package/lib/utils.js.map +1 -1
  293. package/package.json +9 -7
  294. package/src/components/generate-token-dialog.tsx +167 -0
  295. package/src/components/rate-limiting/customer/general-details.tsx +106 -0
  296. package/src/components/rate-limiting/customer/index.ts +18 -0
  297. package/src/components/rate-limiting/customer/usage-stats.tsx +50 -0
  298. package/src/{pages/admin-dashboard → components/rate-limiting}/usage-stats/usage-stats-chart.tsx +57 -31
  299. package/{lib/pages/admin-dashboard/usage-stats/usage-stats-utils.js → src/components/rate-limiting/usage-stats/usage-stats-utils.ts} +4 -2
  300. package/src/components/rate-limiting/usage-stats/use-usage-stats.ts +70 -0
  301. package/src/components/scan-admin/scan-card/scan-card-header.tsx +2 -2
  302. package/src/components/sidepanel/drawer-header.tsx +23 -0
  303. package/src/components/sidepanel/navigation-item.tsx +3 -2
  304. package/src/components/sidepanel/sidepanel.tsx +29 -17
  305. package/src/context/scan-admin/scan-context.tsx +1 -0
  306. package/src/default/default-app.tsx +1 -1
  307. package/src/default/menu-content.tsx +6 -2
  308. package/src/default/page-settings.tsx +1 -1
  309. package/src/extension-registry-service.ts +153 -26
  310. package/src/extension-registry-types.ts +16 -0
  311. package/src/main.tsx +2 -1
  312. package/src/other-pages.tsx +21 -4
  313. package/src/pages/admin-dashboard/admin-dashboard.tsx +250 -83
  314. package/src/pages/admin-dashboard/admin-routes.ts +27 -0
  315. package/src/pages/admin-dashboard/components/data-grid-filter-operators.tsx +1 -31
  316. package/src/pages/admin-dashboard/components/data-grid-filter.tsx +45 -0
  317. package/src/pages/admin-dashboard/components/index.ts +1 -1
  318. package/src/pages/admin-dashboard/customers/customer-details.tsx +133 -0
  319. package/src/pages/admin-dashboard/customers/customer-form-dialog.tsx +3 -4
  320. package/src/pages/admin-dashboard/customers/customer-member-list.tsx +174 -0
  321. package/src/pages/admin-dashboard/customers/customer-token-list.tsx +135 -0
  322. package/src/pages/admin-dashboard/customers/customers.tsx +8 -8
  323. package/src/pages/admin-dashboard/logs/logs.tsx +1 -10
  324. package/src/pages/admin-dashboard/publisher-admin.tsx +29 -11
  325. package/src/pages/admin-dashboard/usage-stats/usage-stats.tsx +10 -39
  326. package/src/pages/admin-dashboard/usage-stats/use-usage-stats.ts +70 -0
  327. package/src/pages/admin-dashboard/welcome.tsx +1 -1
  328. package/src/pages/extension-detail/extension-detail-overview.tsx +2 -2
  329. package/src/pages/extension-detail/extension-detail-routes.ts +35 -0
  330. package/src/pages/extension-detail/extension-detail.tsx +3 -23
  331. package/src/pages/extension-list/extension-list-container.tsx +1 -5
  332. package/src/pages/extension-list/extension-list-item.tsx +1 -1
  333. package/src/pages/extension-list/extension-list-routes.ts +18 -0
  334. package/src/pages/namespace-detail/namespace-detail-routes.ts +23 -0
  335. package/src/pages/namespace-detail/namespace-detail.tsx +0 -10
  336. package/src/pages/user/add-namespace-member-dialog.tsx +17 -116
  337. package/src/pages/user/add-user-dialog.tsx +141 -0
  338. package/src/pages/user/avatar.tsx +2 -2
  339. package/src/pages/user/generate-access-token-dialog.tsx +49 -0
  340. package/src/pages/user/user-namespace-extension-list-item.tsx +2 -2
  341. package/src/pages/user/user-setting-tabs.tsx +2 -1
  342. package/src/pages/user/user-settings-customer-detail.tsx +39 -0
  343. package/src/pages/user/user-settings-customers.tsx +120 -0
  344. package/src/pages/user/user-settings-delete-extension.tsx +1 -1
  345. package/src/pages/user/user-settings-namespace-detail.tsx +3 -1
  346. package/src/pages/user/user-settings-routes.ts +25 -0
  347. package/src/pages/user/user-settings-tokens.tsx +3 -10
  348. package/src/pages/user/user-settings.tsx +4 -12
  349. package/lib/components/copy-to-clipboard.d.ts +0 -21
  350. package/lib/components/copy-to-clipboard.d.ts.map +0 -1
  351. package/lib/components/copy-to-clipboard.js +0 -26
  352. package/lib/components/copy-to-clipboard.js.map +0 -1
  353. package/lib/pages/admin-dashboard/usage-stats/usage-stats-chart.d.ts.map +0 -1
  354. package/lib/pages/admin-dashboard/usage-stats/usage-stats-chart.js.map +0 -1
  355. package/lib/pages/admin-dashboard/usage-stats/usage-stats-utils.d.ts.map +0 -1
  356. package/lib/pages/admin-dashboard/usage-stats/usage-stats-utils.js.map +0 -1
  357. package/lib/pages/user/generate-token-dialog.d.ts.map +0 -1
  358. package/lib/pages/user/generate-token-dialog.js +0 -88
  359. package/lib/pages/user/generate-token-dialog.js.map +0 -1
  360. package/src/components/copy-to-clipboard.tsx +0 -50
  361. package/src/pages/user/generate-token-dialog.tsx +0 -157
@@ -0,0 +1,174 @@
1
+ /******************************************************************************
2
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation.
3
+ *
4
+ * See the NOTICE file(s) distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ *
7
+ * This program and the accompanying materials are made available under the
8
+ * terms of the Eclipse Public License 2.0 which is available at
9
+ * https://www.eclipse.org/legal/epl-2.0.
10
+ *
11
+ * SPDX-License-Identifier: EPL-2.0
12
+ *****************************************************************************/
13
+
14
+ import { FunctionComponent, useEffect, useState, useContext, useRef } from 'react';
15
+ import {
16
+ Box,
17
+ Typography,
18
+ Button,
19
+ Divider,
20
+ List,
21
+ ListItem,
22
+ ListItemAvatar,
23
+ Avatar,
24
+ ListItemText, IconButton, type PaperProps, Paper
25
+ } from '@mui/material';
26
+ import { Link as RouterLink } from 'react-router-dom';
27
+ import { AdminDashboardRoutes } from '../admin-routes';
28
+ import { MainContext } from '../../../context';
29
+ import { CustomerMembership, Customer, UserData, isError } from '../../../extension-registry-types';
30
+ import { AddUserDialog } from '../../user/add-user-dialog';
31
+ import DeleteIcon from '@mui/icons-material/Delete';
32
+ import PersonAddIcon from '@mui/icons-material/PersonAdd';
33
+ import { createRoute } from '../../../utils';
34
+
35
+ const sectionPaperProps: PaperProps = { elevation: 1, sx: { p: 3, mb: 3 } };
36
+
37
+ export const CustomerMemberList: FunctionComponent<CustomerMemberListProps> = props => {
38
+ const { service, handleError } = useContext(MainContext);
39
+ const [members, setMembers] = useState<CustomerMembership[]>([]);
40
+ const [addDialogIsOpen, setAddDialogIsOpen] = useState(false);
41
+ const abortController = useRef<AbortController>(new AbortController());
42
+
43
+ const users = members.map(member => member.user);
44
+
45
+ useEffect(() => {
46
+ fetchMembers();
47
+ }, [props.customer]);
48
+
49
+ useEffect(() => {
50
+ return () => {
51
+ abortController.current.abort();
52
+ };
53
+ }, []);
54
+
55
+ const handleCloseAddDialog = async () => {
56
+ setAddDialogIsOpen(false);
57
+ fetchMembers();
58
+ };
59
+
60
+ const handleOpenAddDialog = async () => {
61
+ setAddDialogIsOpen(true);
62
+ };
63
+
64
+ const handleAddUser = async (user: UserData) => {
65
+ try {
66
+ const result = await service.admin.addCustomerMember(abortController.current, props.customer.name, user);
67
+ if (isError(result)) {
68
+ throw result;
69
+ }
70
+ await fetchMembers();
71
+ } catch (err) {
72
+ handleError(err);
73
+ }
74
+ };
75
+
76
+ const handleRemoveUser = async (user: UserData) => {
77
+ try {
78
+ const result = await service.admin.removeCustomerMember(abortController.current, props.customer.name, user);
79
+ if (isError(result)) {
80
+ throw result;
81
+ }
82
+ await fetchMembers();
83
+ } catch (err) {
84
+ handleError(err);
85
+ }
86
+ };
87
+
88
+ const fetchMembers = async () => {
89
+ try {
90
+ const membershipList = await service.admin.getCustomerMembers(abortController.current, props.customer.name);
91
+ const members = membershipList.customerMemberships;
92
+ setMembers(members);
93
+ } catch (err) {
94
+ handleError(err);
95
+ }
96
+ };
97
+
98
+ return <Paper {...sectionPaperProps}>
99
+ <Box
100
+ sx={{
101
+ display: 'flex',
102
+ justifyContent: 'space-between',
103
+ alignItems: 'center',
104
+ mb: 1,
105
+ flexDirection: { xs: 'column', sm: 'column', md: 'row', lg: 'row', xl: 'row' }
106
+ }}
107
+ >
108
+ <Typography variant='h6'>Members</Typography>
109
+ <Button size='small' startIcon={<PersonAddIcon />} onClick={handleOpenAddDialog}>
110
+ Add Member
111
+ </Button>
112
+ </Box>
113
+ <Divider sx={{ mb: 1 }} />
114
+ {members.length === 0 ? (
115
+ <Typography variant='body2' color='text.secondary' sx={{ py: 1 }}>
116
+ No members assigned to this customer.
117
+ </Typography>
118
+ ) : (
119
+ <List dense disablePadding>
120
+ {users.map(user => (
121
+ <ListItem
122
+ key={`${user.loginName}-${user.provider}`}
123
+ secondaryAction={
124
+ <IconButton edge='end' size='small' color='error' onClick={() => handleRemoveUser(user)} title='Remove member'>
125
+ <DeleteIcon fontSize='small' />
126
+ </IconButton>
127
+ }
128
+ >
129
+ <ListItemAvatar>
130
+ <Avatar src={user.avatarUrl} sx={{ width: 32, height: 32 }} />
131
+ </ListItemAvatar>
132
+ <ListItemText
133
+ primary={
134
+ <RouterLink style={{ color: 'inherit' }} to={createRoute([AdminDashboardRoutes.PUBLISHER_ADMIN, user.loginName])}>
135
+ {user.loginName}
136
+ </RouterLink>
137
+ }
138
+ secondary={user.fullName}
139
+ />
140
+ </ListItem>
141
+ ))}
142
+ </List>
143
+ )}
144
+
145
+
146
+
147
+
148
+ {/*{members.length ?*/}
149
+ {/* <Paper elevation={3}>*/}
150
+ {/* {members.map(member =>*/}
151
+ {/* <UserNamespaceMember*/}
152
+ {/* key={'nspcmbr-' + member.user.loginName + member.user.provider}*/}
153
+ {/* namespace={props.namespace}*/}
154
+ {/* member={member}*/}
155
+ {/* fixSelf={props.fixSelf}*/}
156
+ {/* onChangeRole={role => changeRole(member, role)}*/}
157
+ {/* onRemoveUser={() => changeRole(member, 'remove')} />)}*/}
158
+ {/* </Paper> :*/}
159
+ {/* <Typography variant='body1'>There are no members assigned yet.</Typography>}*/}
160
+
161
+ <AddUserDialog
162
+ open={addDialogIsOpen}
163
+ title='Add Member'
164
+ description='Search for a user by login name to add them to this customer.'
165
+ existingUsers={members.map(member => member.user)}
166
+ onClose={handleCloseAddDialog}
167
+ onAddUser={handleAddUser}
168
+ />
169
+ </Paper>;
170
+ };
171
+
172
+ export interface CustomerMemberListProps {
173
+ customer: Customer;
174
+ }
@@ -0,0 +1,135 @@
1
+ /******************************************************************************
2
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation.
3
+ *
4
+ * See the NOTICE file(s) distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ *
7
+ * This program and the accompanying materials are made available under the
8
+ * terms of the Eclipse Public License 2.0 which is available at
9
+ * https://www.eclipse.org/legal/epl-2.0.
10
+ *
11
+ * SPDX-License-Identifier: EPL-2.0
12
+ *****************************************************************************/
13
+
14
+ import { FunctionComponent, useEffect, useState, useContext, useRef } from 'react';
15
+ import {
16
+ Box,
17
+ Typography,
18
+ Divider,
19
+ List,
20
+ ListItem,
21
+ ListItemText,
22
+ IconButton,
23
+ Paper,
24
+ Button,
25
+ type PaperProps
26
+ } from '@mui/material';
27
+ import DeleteIcon from '@mui/icons-material/Delete';
28
+ import AddIcon from '@mui/icons-material/Add';
29
+ import { MainContext } from '../../../context';
30
+ import { Customer, isError, RateLimitToken } from '../../../extension-registry-types';
31
+ import { GenerateTokenDialog } from '../../../components/generate-token-dialog';
32
+ import { Timestamp } from "../../../components/timestamp";
33
+
34
+ const sectionPaperProps: PaperProps = { elevation: 1, sx: { p: 3, mb: 3 } };
35
+
36
+ export const CustomerTokenList: FunctionComponent<CustomerTokenListProps> = props => {
37
+ const { service, handleError } = useContext(MainContext);
38
+ const [tokens, setTokens] = useState<RateLimitToken[]>([]);
39
+ const [dialogOpen, setDialogOpen] = useState(false);
40
+ const abortController = useRef<AbortController>(new AbortController());
41
+
42
+ useEffect(() => {
43
+ fetchTokens();
44
+ }, [props.customer]);
45
+
46
+ useEffect(() => {
47
+ return () => {
48
+ abortController.current.abort();
49
+ };
50
+ }, []);
51
+
52
+ const fetchTokens = async () => {
53
+ try {
54
+ const result = await service.admin.getCustomerRateLimitTokens(abortController.current, props.customer.name);
55
+ setTokens([...result]);
56
+ } catch (err) {
57
+ handleError(err);
58
+ }
59
+ };
60
+
61
+ const handleGenerate = async (description: string): Promise<string> => {
62
+ const token = await service.admin.createCustomerRateLimitToken(abortController.current, props.customer.name, description);
63
+ await fetchTokens();
64
+ return token.value ?? '';
65
+ };
66
+
67
+ const handleDelete = async (tokenId: number) => {
68
+ try {
69
+ const result = await service.admin.deleteCustomerRateLimitToken(abortController.current, props.customer.name, tokenId);
70
+ if (isError(result)) {
71
+ throw result;
72
+ }
73
+ await fetchTokens();
74
+ } catch (err) {
75
+ handleError(err);
76
+ }
77
+ };
78
+
79
+ return <Paper {...sectionPaperProps}>
80
+ <Box
81
+ sx={{
82
+ display: 'flex',
83
+ justifyContent: 'space-between',
84
+ alignItems: 'center',
85
+ mb: 1,
86
+ flexDirection: { xs: 'column', sm: 'column', md: 'row', lg: 'row', xl: 'row' }
87
+ }}
88
+ >
89
+ <Typography variant='h6'>Tokens</Typography>
90
+ <Button size='small' startIcon={<AddIcon />} onClick={() => setDialogOpen(true)}>
91
+ Generate Token
92
+ </Button>
93
+ </Box>
94
+ <Divider sx={{ mb: 1 }} />
95
+ {tokens.length === 0 ? (
96
+ <Typography variant='body2' color='text.secondary' sx={{ py: 1 }}>
97
+ No rate limiting tokens for this customer.
98
+ </Typography>
99
+ ) : (
100
+ <List dense disablePadding>
101
+ {tokens.map(token => (
102
+ <ListItem
103
+ key={token.id}
104
+ secondaryAction={
105
+ <IconButton edge='end' size='small' color='error' onClick={() => handleDelete(token.id)} title='Delete token'>
106
+ <DeleteIcon fontSize='small' />
107
+ </IconButton>
108
+ }
109
+ >
110
+ <ListItemText
111
+ primary={
112
+ <Typography sx={{ fontWeight: 'bold', overflow: 'hidden', textOverflow: 'ellipsis' }}>{token.description || 'N/A'}</Typography>
113
+ }
114
+ secondary={
115
+ <Typography variant='body2'>Created: <Timestamp value={token.createdTimestamp}/></Typography>
116
+ }
117
+ />
118
+ </ListItem>
119
+ ))}
120
+ </List>
121
+ )}
122
+
123
+ <GenerateTokenDialog
124
+ open={dialogOpen}
125
+ onClose={() => setDialogOpen(false)}
126
+ onGenerate={handleGenerate}
127
+ onError={handleError}
128
+ title='Generate token'
129
+ />
130
+ </Paper>;
131
+ };
132
+
133
+ export interface CustomerTokenListProps {
134
+ customer: Customer;
135
+ }
@@ -11,7 +11,7 @@
11
11
  * SPDX-License-Identifier: EPL-2.0
12
12
  *****************************************************************************/
13
13
 
14
- import { FC, useContext, useState, useEffect, useRef, useCallback, useMemo } from "react";
14
+ import { FC, useContext, useState, useEffect, useRef, useCallback, useMemo } from 'react';
15
15
  import {
16
16
  Box,
17
17
  Button,
@@ -27,14 +27,14 @@ import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
27
27
  import EditIcon from "@mui/icons-material/Edit";
28
28
  import DeleteIcon from "@mui/icons-material/Delete";
29
29
  import AddIcon from "@mui/icons-material/Add";
30
- import BarChartIcon from "@mui/icons-material/BarChart";
30
+ import VisibilityIcon from "@mui/icons-material/Visibility";
31
31
  import { MainContext } from "../../../context";
32
32
  import type { Customer } from "../../../extension-registry-types";
33
33
  import { CustomerFormDialog } from "./customer-form-dialog";
34
34
  import { DeleteCustomerDialog } from "./delete-customer-dialog";
35
- import { handleError } from "../../../utils";
35
+ import { createRoute, handleError } from "../../../utils";
36
36
  import { createMultiSelectFilterOperators, createArrayContainsFilterOperators } from "../components";
37
- import { AdminDashboardRoutes } from "../admin-dashboard";
37
+ import { AdminDashboardRoutes } from "../admin-routes";
38
38
  import { Link } from "react-router-dom";
39
39
 
40
40
  export const Customers: FC = () => {
@@ -181,10 +181,10 @@ export const Customers: FC = () => {
181
181
  <IconButton
182
182
  size='small'
183
183
  component={Link}
184
- to={`${AdminDashboardRoutes.USAGE_STATS}/${params.row.name}`}
185
- title='View Usage Stats'
184
+ to={createRoute([AdminDashboardRoutes.CUSTOMERS, params.row.name])}
185
+ title='View Details'
186
186
  >
187
- <BarChartIcon />
187
+ <VisibilityIcon />
188
188
  </IconButton>
189
189
  <IconButton
190
190
  size='small'
@@ -207,7 +207,7 @@ export const Customers: FC = () => {
207
207
  ];
208
208
 
209
209
  return (
210
- <Box sx={{ p: 3, height: '100%', display: 'flex', flexDirection: 'column' }}>
210
+ <Box sx={{ p: 2, height: '100%', display: 'flex', flexDirection: 'column' }}>
211
211
  <Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", mb: 3 }}>
212
212
  <Typography variant='h4' component='h1'>
213
213
  Customer Management
@@ -136,16 +136,7 @@ export const Logs: FC = () => {
136
136
  ];
137
137
 
138
138
  return (
139
- <Box sx={{
140
- width: 'min(1500px, 100vw - 280px)',
141
- maxWidth: 'none',
142
- mx: 'auto',
143
- px: 2,
144
- pb: 3,
145
- position: 'relative',
146
- left: '50%',
147
- transform: 'translateX(-50%)',
148
- }}>
139
+ <Box sx={{ p: 3, height: '100%', display: 'flex', flexDirection: 'column' }}>
149
140
  <Box sx={{
150
141
  display: "flex",
151
142
  justifyContent: "space-between",
@@ -8,16 +8,22 @@
8
8
  * SPDX-License-Identifier: EPL-2.0
9
9
  ********************************************************************************/
10
10
 
11
- import { FunctionComponent, useState, useContext, createContext, useEffect, useRef, ReactNode } from 'react';
11
+ import { FunctionComponent, useState, useContext, createContext, useEffect, useRef, useCallback, ReactNode } from 'react';
12
12
  import { Typography, Box } from '@mui/material';
13
+ import { useParams, useNavigate } from 'react-router-dom';
13
14
  import { PublisherInfo } from '../../extension-registry-types';
14
15
  import { MainContext } from '../../context';
15
16
  import { StyledInput } from './namespace-input';
16
17
  import { SearchListContainer } from './search-list-container';
17
18
  import { PublisherDetails } from './publisher-details';
19
+ import { AdminDashboardRoutes } from './admin-routes';
18
20
 
21
+ // eslint-disable-next-line react-refresh/only-export-components
19
22
  export const UpdateContext = createContext({ handleUpdate: () => { } });
23
+
20
24
  export const PublisherAdmin: FunctionComponent = () => {
25
+ const { publisher: publisherParam } = useParams<{ publisher: string }>();
26
+ const navigate = useNavigate();
21
27
  const { pageSettings, service, user, handleError } = useContext(MainContext);
22
28
 
23
29
  const abortController = useRef<AbortController>(new AbortController());
@@ -28,24 +34,20 @@ export const PublisherAdmin: FunctionComponent = () => {
28
34
  }, []);
29
35
 
30
36
  const [loading, setLoading] = useState(false);
31
- const [inputValue, setInputValue] = useState('');
32
- const onChangeInput = (name: string) => {
33
- setInputValue(name);
34
- };
35
37
 
36
38
  const [publisher, setPublisher] = useState<PublisherInfo | undefined>();
37
39
  const [notFound, setNotFound] = useState('');
38
- const fetchPublisher = async () => {
39
- const publisherName = inputValue;
40
+
41
+ const fetchPublisher = useCallback(async (publisherName: string) => {
40
42
  try {
41
43
  setLoading(true);
42
44
  if (publisherName === '') {
43
45
  setNotFound('');
44
46
  setPublisher(undefined);
45
47
  } else {
46
- const publisher = await service.admin.getPublisherInfo(abortController.current, 'github', publisherName);
48
+ const pub = await service.admin.getPublisherInfo(abortController.current, 'github', publisherName);
47
49
  setNotFound('');
48
- setPublisher(publisher);
50
+ setPublisher(pub);
49
51
  }
50
52
  setLoading(false);
51
53
  } catch (err) {
@@ -57,10 +59,26 @@ export const PublisherAdmin: FunctionComponent = () => {
57
59
  }
58
60
  setLoading(false);
59
61
  }
62
+ }, [service, handleError]);
63
+
64
+ useEffect(() => {
65
+ if (publisherParam) {
66
+ fetchPublisher(publisherParam);
67
+ }
68
+ }, [publisherParam, fetchPublisher]);
69
+
70
+ const handleSubmit = (inputValue: string) => {
71
+ if (inputValue) {
72
+ navigate(`${AdminDashboardRoutes.PUBLISHER_ADMIN}/${inputValue}`);
73
+ } else {
74
+ navigate(AdminDashboardRoutes.PUBLISHER_ADMIN);
75
+ }
60
76
  };
61
77
 
62
78
  const handleUpdate = () => {
63
- fetchPublisher();
79
+ if (publisherParam) {
80
+ fetchPublisher(publisherParam);
81
+ }
64
82
  };
65
83
 
66
84
  let listContainer: ReactNode = '';
@@ -78,7 +96,7 @@ export const PublisherAdmin: FunctionComponent = () => {
78
96
 
79
97
  return <SearchListContainer
80
98
  searchContainer={
81
- [<StyledInput placeholder='Publisher Name' key='pi' onSubmit={fetchPublisher} onChange={onChangeInput} />]
99
+ [<StyledInput placeholder='Publisher Name' key='pi' value={publisherParam || ''} onSubmit={handleSubmit} onChange={() => {}} />]
82
100
  }
83
101
  listContainer={listContainer}
84
102
  loading={loading}
@@ -11,17 +11,17 @@
11
11
  * SPDX-License-Identifier: EPL-2.0
12
12
  *****************************************************************************/
13
13
 
14
- import { FC, useContext, useState, useEffect, useRef, useMemo, useCallback } from "react";
14
+ import { FC, useContext, useState, useEffect, useRef, useMemo } from "react";
15
15
  import { Box, Alert } from "@mui/material";
16
16
  import { useParams, useNavigate } from "react-router-dom";
17
17
  import { MainContext } from "../../../context";
18
- import type { UsageStats, Customer } from "../../../extension-registry-types";
18
+ import type { Customer } from "../../../extension-registry-types";
19
19
  import { handleError } from "../../../utils";
20
- import { AdminDashboardRoutes } from "../admin-dashboard";
20
+ import { AdminDashboardRoutes } from "../admin-routes";
21
21
  import { SearchListContainer } from "../search-list-container";
22
22
  import { CustomerSearch } from "./usage-stats-search";
23
- import { UsageStatsChart } from "./usage-stats-chart";
24
- import { getDefaultStartDate } from "./usage-stats-utils";
23
+ import { UsageStatsChart } from "../../../components/rate-limiting/usage-stats/usage-stats-chart";
24
+ import { useAdminUsageStats } from "./use-usage-stats";
25
25
 
26
26
  export const UsageStatsView: FC = () => {
27
27
  const { customer } = useParams<{ customer: string }>();
@@ -31,10 +31,9 @@ export const UsageStatsView: FC = () => {
31
31
 
32
32
  const [customers, setCustomers] = useState<Customer[]>([]);
33
33
  const [customersLoading, setCustomersLoading] = useState(true);
34
- const [usageStats, setUsageStats] = useState<readonly UsageStats[]>([]);
35
- const [loading, setLoading] = useState(false);
36
- const [error, setError] = useState<string | null>(null);
37
- const [startDate, setStartDate] = useState<Date>(getDefaultStartDate);
34
+ const [customersError, setCustomersError] = useState<string | null>(null);
35
+
36
+ const { usageStats, loading, error: statsError, startDate, setStartDate } = useAdminUsageStats(customer);
38
37
 
39
38
  // Load customers for autocomplete
40
39
  useEffect(() => {
@@ -44,7 +43,7 @@ export const UsageStatsView: FC = () => {
44
43
  const data = await service.admin.getCustomers(abortController.current);
45
44
  setCustomers(data.customers);
46
45
  } catch (err) {
47
- setError(handleError(err as Error));
46
+ setCustomersError(handleError(err as Error));
48
47
  } finally {
49
48
  setCustomersLoading(false);
50
49
  }
@@ -66,35 +65,7 @@ export const UsageStatsView: FC = () => {
66
65
  }
67
66
  };
68
67
 
69
- const loadUsageStats = useCallback(async () => {
70
- if (!customer) {
71
- setUsageStats([]);
72
- setLoading(false);
73
- return;
74
- }
75
-
76
- try {
77
- setLoading(true);
78
- setError(null);
79
- const data = await service.admin.getUsageStats(
80
- abortController.current,
81
- customer,
82
- startDate
83
- );
84
- setUsageStats(data.stats);
85
- } catch (err) {
86
- setError(handleError(err as Error));
87
- } finally {
88
- setLoading(false);
89
- }
90
- }, [service, customer, startDate]);
91
-
92
- useEffect(() => {
93
- if (customer) {
94
- loadUsageStats();
95
- }
96
- }, [loadUsageStats, customer]);
97
-
68
+ const error = customersError || statsError;
98
69
  if (error) {
99
70
  return <Alert severity='error'>{error}</Alert>;
100
71
  }
@@ -0,0 +1,70 @@
1
+ /******************************************************************************
2
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation.
3
+ *
4
+ * See the NOTICE file(s) distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ *
7
+ * This program and the accompanying materials are made available under the
8
+ * terms of the Eclipse Public License 2.0 which is available at
9
+ * https://www.eclipse.org/legal/epl-2.0.
10
+ *
11
+ * SPDX-License-Identifier: EPL-2.0
12
+ *****************************************************************************/
13
+
14
+ import { useContext, useState, useEffect, useRef, useCallback } from "react";
15
+ import { MainContext } from "../../../context";
16
+ import type { UsageStats } from "../../../extension-registry-types";
17
+ import { handleError } from "../../../utils";
18
+ import { getDefaultStartDate } from "../../../components/rate-limiting/usage-stats/usage-stats-utils";
19
+ import { DateTime } from "luxon";
20
+
21
+ export const useAdminUsageStats = (customerName: string | undefined) => {
22
+ const abortController = useRef(new AbortController());
23
+ const { service } = useContext(MainContext);
24
+
25
+ const [usageStats, setUsageStats] = useState<readonly UsageStats[]>([]);
26
+ const [loading, setLoading] = useState(false);
27
+ const [error, setError] = useState<string | null>(null);
28
+ const [internalStartDate, setInternalStartDate] = useState<DateTime>(getDefaultStartDate);
29
+
30
+ const startDateRef = useRef(internalStartDate);
31
+ startDateRef.current = internalStartDate;
32
+
33
+ const fetchUsageStats = useCallback(async (date: DateTime) => {
34
+ if (!customerName) {
35
+ setUsageStats([]);
36
+ setLoading(false);
37
+ return;
38
+ }
39
+
40
+ try {
41
+ setLoading(true);
42
+ setError(null);
43
+ const data = await service.admin.getUsageStats(
44
+ abortController.current,
45
+ customerName,
46
+ date.toJSDate()
47
+ );
48
+ setUsageStats(data.stats);
49
+ } catch (err) {
50
+ setError(handleError(err as Error));
51
+ } finally {
52
+ setLoading(false);
53
+ }
54
+ }, [service, customerName]);
55
+
56
+ const setStartDate = useCallback((date: DateTime) => {
57
+ setInternalStartDate(date);
58
+ fetchUsageStats(date);
59
+ }, [fetchUsageStats]);
60
+
61
+ useEffect(() => {
62
+ fetchUsageStats(startDateRef.current);
63
+ return () => {
64
+ abortController.current.abort();
65
+ abortController.current = new AbortController();
66
+ };
67
+ }, [fetchUsageStats]);
68
+
69
+ return { usageStats, loading, error, startDate: internalStartDate, setStartDate };
70
+ };
@@ -12,7 +12,7 @@ import { FunctionComponent } from 'react';
12
12
  import { Typography, Grid, Paper } from '@mui/material';
13
13
  import { styled, Theme } from '@mui/material/styles';
14
14
  import { Link } from 'react-router-dom';
15
- import { AdminDashboardRoutes } from './admin-dashboard';
15
+ import { AdminDashboardRoutes } from './admin-routes';
16
16
 
17
17
  export const Welcome: FunctionComponent = props => {
18
18
  return <Grid container direction='column' spacing={2} sx={{ height: '100%' }}>
@@ -21,8 +21,8 @@ import { DelayedLoadIndicator } from '../../components/delayed-load-indicator';
21
21
  import { SanitizedMarkdown } from '../../components/sanitized-markdown';
22
22
  import { Timestamp } from '../../components/timestamp';
23
23
  import { Extension, ExtensionReference, VERSION_ALIASES } from '../../extension-registry-types';
24
- import { ExtensionListRoutes } from '../extension-list/extension-list-container';
25
- import { ExtensionDetailRoutes } from './extension-detail';
24
+ import { ExtensionListRoutes } from '../extension-list/extension-list-routes';
25
+ import { ExtensionDetailRoutes } from './extension-detail-routes';
26
26
  import { ExtensionDetailDownloadsMenu } from './extension-detail-downloads-menu';
27
27
 
28
28
  export const ExtensionDetailOverview: FunctionComponent<ExtensionDetailOverviewProps> = props => {