openvsx-webui-test 0.17.1 → 0.18.0-dev.0

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 (337) hide show
  1. package/lib/components/button-with-progress.d.ts +1 -0
  2. package/lib/components/button-with-progress.d.ts.map +1 -1
  3. package/lib/components/button-with-progress.js +1 -1
  4. package/lib/components/button-with-progress.js.map +1 -1
  5. package/lib/components/sanitized-markdown.d.ts.map +1 -1
  6. package/lib/components/sanitized-markdown.js +79 -1
  7. package/lib/components/sanitized-markdown.js.map +1 -1
  8. package/lib/components/scan-admin/common/auto-refresh.d.ts +21 -0
  9. package/lib/components/scan-admin/common/auto-refresh.d.ts.map +1 -0
  10. package/lib/components/scan-admin/common/auto-refresh.js +45 -0
  11. package/lib/components/scan-admin/common/auto-refresh.js.map +1 -0
  12. package/lib/components/scan-admin/common/conditional-tooltip.d.ts +24 -0
  13. package/lib/components/scan-admin/common/conditional-tooltip.d.ts.map +1 -0
  14. package/lib/components/scan-admin/common/conditional-tooltip.js +63 -0
  15. package/lib/components/scan-admin/common/conditional-tooltip.js.map +1 -0
  16. package/lib/components/scan-admin/common/file-table.d.ts +23 -0
  17. package/lib/components/scan-admin/common/file-table.d.ts.map +1 -0
  18. package/lib/components/scan-admin/common/file-table.js +350 -0
  19. package/lib/components/scan-admin/common/file-table.js.map +1 -0
  20. package/lib/components/scan-admin/common/index.d.ts +18 -0
  21. package/lib/components/scan-admin/common/index.d.ts.map +1 -0
  22. package/lib/components/scan-admin/common/index.js +18 -0
  23. package/lib/components/scan-admin/common/index.js.map +1 -0
  24. package/lib/components/scan-admin/common/tab-panel.d.ts +25 -0
  25. package/lib/components/scan-admin/common/tab-panel.d.ts.map +1 -0
  26. package/lib/components/scan-admin/common/tab-panel.js +22 -0
  27. package/lib/components/scan-admin/common/tab-panel.js.map +1 -0
  28. package/lib/components/scan-admin/common/utils.d.ts +15 -0
  29. package/lib/components/scan-admin/common/utils.d.ts.map +1 -0
  30. package/lib/components/scan-admin/common/utils.js +46 -0
  31. package/lib/components/scan-admin/common/utils.js.map +1 -0
  32. package/lib/components/scan-admin/dialogs/file-dialog.d.ts +19 -0
  33. package/lib/components/scan-admin/dialogs/file-dialog.d.ts.map +1 -0
  34. package/lib/components/scan-admin/dialogs/file-dialog.js +85 -0
  35. package/lib/components/scan-admin/dialogs/file-dialog.js.map +1 -0
  36. package/lib/components/scan-admin/dialogs/index.d.ts +15 -0
  37. package/lib/components/scan-admin/dialogs/index.d.ts.map +1 -0
  38. package/lib/components/scan-admin/dialogs/index.js +15 -0
  39. package/lib/components/scan-admin/dialogs/index.js.map +1 -0
  40. package/lib/components/scan-admin/dialogs/quarantine-dialog.d.ts +23 -0
  41. package/lib/components/scan-admin/dialogs/quarantine-dialog.d.ts.map +1 -0
  42. package/lib/components/scan-admin/dialogs/quarantine-dialog.js +192 -0
  43. package/lib/components/scan-admin/dialogs/quarantine-dialog.js.map +1 -0
  44. package/lib/components/scan-admin/index.d.ts +20 -0
  45. package/lib/components/scan-admin/index.d.ts.map +1 -0
  46. package/lib/components/scan-admin/index.js +25 -0
  47. package/lib/components/scan-admin/index.js.map +1 -0
  48. package/lib/components/scan-admin/scan-card/index.d.ts +20 -0
  49. package/lib/components/scan-admin/scan-card/index.d.ts.map +1 -0
  50. package/lib/components/scan-admin/scan-card/index.js +20 -0
  51. package/lib/components/scan-admin/scan-card/index.js.map +1 -0
  52. package/lib/components/scan-admin/scan-card/scan-card-content.d.ts +30 -0
  53. package/lib/components/scan-admin/scan-card/scan-card-content.d.ts.map +1 -0
  54. package/lib/components/scan-admin/scan-card/scan-card-content.js +232 -0
  55. package/lib/components/scan-admin/scan-card/scan-card-content.js.map +1 -0
  56. package/lib/components/scan-admin/scan-card/scan-card-expand-strip-badges.d.ts +26 -0
  57. package/lib/components/scan-admin/scan-card/scan-card-expand-strip-badges.d.ts.map +1 -0
  58. package/lib/components/scan-admin/scan-card/scan-card-expand-strip-badges.js +121 -0
  59. package/lib/components/scan-admin/scan-card/scan-card-expand-strip-badges.js.map +1 -0
  60. package/lib/components/scan-admin/scan-card/scan-card-expand-strip.d.ts +27 -0
  61. package/lib/components/scan-admin/scan-card/scan-card-expand-strip.d.ts.map +1 -0
  62. package/lib/components/scan-admin/scan-card/scan-card-expand-strip.js +66 -0
  63. package/lib/components/scan-admin/scan-card/scan-card-expand-strip.js.map +1 -0
  64. package/lib/components/scan-admin/scan-card/scan-card-expanded-content.d.ts +26 -0
  65. package/lib/components/scan-admin/scan-card/scan-card-expanded-content.d.ts.map +1 -0
  66. package/lib/components/scan-admin/scan-card/scan-card-expanded-content.js +151 -0
  67. package/lib/components/scan-admin/scan-card/scan-card-expanded-content.js.map +1 -0
  68. package/lib/components/scan-admin/scan-card/scan-card-header.d.ts +26 -0
  69. package/lib/components/scan-admin/scan-card/scan-card-header.d.ts.map +1 -0
  70. package/lib/components/scan-admin/scan-card/scan-card-header.js +101 -0
  71. package/lib/components/scan-admin/scan-card/scan-card-header.js.map +1 -0
  72. package/lib/components/scan-admin/scan-card/scan-card.d.ts +34 -0
  73. package/lib/components/scan-admin/scan-card/scan-card.d.ts.map +1 -0
  74. package/lib/components/scan-admin/scan-card/scan-card.js +90 -0
  75. package/lib/components/scan-admin/scan-card/scan-card.js.map +1 -0
  76. package/lib/components/scan-admin/scan-card/scan-detail-card.d.ts +38 -0
  77. package/lib/components/scan-admin/scan-card/scan-detail-card.d.ts.map +1 -0
  78. package/lib/components/scan-admin/scan-card/scan-detail-card.js +72 -0
  79. package/lib/components/scan-admin/scan-card/scan-detail-card.js.map +1 -0
  80. package/lib/components/scan-admin/scan-card/utils.d.ts +48 -0
  81. package/lib/components/scan-admin/scan-card/utils.d.ts.map +1 -0
  82. package/lib/components/scan-admin/scan-card/utils.js +166 -0
  83. package/lib/components/scan-admin/scan-card/utils.js.map +1 -0
  84. package/lib/components/scan-admin/tab-contents/allow-list-tab-content.d.ts +19 -0
  85. package/lib/components/scan-admin/tab-contents/allow-list-tab-content.d.ts.map +1 -0
  86. package/lib/components/scan-admin/tab-contents/allow-list-tab-content.js +55 -0
  87. package/lib/components/scan-admin/tab-contents/allow-list-tab-content.js.map +1 -0
  88. package/lib/components/scan-admin/tab-contents/auto-rejected-tab-content.d.ts +19 -0
  89. package/lib/components/scan-admin/tab-contents/auto-rejected-tab-content.d.ts.map +1 -0
  90. package/lib/components/scan-admin/tab-contents/auto-rejected-tab-content.js +43 -0
  91. package/lib/components/scan-admin/tab-contents/auto-rejected-tab-content.js.map +1 -0
  92. package/lib/components/scan-admin/tab-contents/block-list-tab-content.d.ts +19 -0
  93. package/lib/components/scan-admin/tab-contents/block-list-tab-content.d.ts.map +1 -0
  94. package/lib/components/scan-admin/tab-contents/block-list-tab-content.js +55 -0
  95. package/lib/components/scan-admin/tab-contents/block-list-tab-content.js.map +1 -0
  96. package/lib/components/scan-admin/tab-contents/index.d.ts +18 -0
  97. package/lib/components/scan-admin/tab-contents/index.d.ts.map +1 -0
  98. package/lib/components/scan-admin/tab-contents/index.js +18 -0
  99. package/lib/components/scan-admin/tab-contents/index.js.map +1 -0
  100. package/lib/components/scan-admin/tab-contents/quarantined-tab-content.d.ts +19 -0
  101. package/lib/components/scan-admin/tab-contents/quarantined-tab-content.d.ts.map +1 -0
  102. package/lib/components/scan-admin/tab-contents/quarantined-tab-content.js +78 -0
  103. package/lib/components/scan-admin/tab-contents/quarantined-tab-content.js.map +1 -0
  104. package/lib/components/scan-admin/tab-contents/scans-tab-content.d.ts +19 -0
  105. package/lib/components/scan-admin/tab-contents/scans-tab-content.d.ts.map +1 -0
  106. package/lib/components/scan-admin/tab-contents/scans-tab-content.js +52 -0
  107. package/lib/components/scan-admin/tab-contents/scans-tab-content.js.map +1 -0
  108. package/lib/components/scan-admin/toolbars/counts-toolbar.d.ts +35 -0
  109. package/lib/components/scan-admin/toolbars/counts-toolbar.d.ts.map +1 -0
  110. package/lib/components/scan-admin/toolbars/counts-toolbar.js +132 -0
  111. package/lib/components/scan-admin/toolbars/counts-toolbar.js.map +1 -0
  112. package/lib/components/scan-admin/toolbars/index.d.ts +16 -0
  113. package/lib/components/scan-admin/toolbars/index.d.ts.map +1 -0
  114. package/lib/components/scan-admin/toolbars/index.js +16 -0
  115. package/lib/components/scan-admin/toolbars/index.js.map +1 -0
  116. package/lib/components/scan-admin/toolbars/search-toolbar.d.ts +43 -0
  117. package/lib/components/scan-admin/toolbars/search-toolbar.d.ts.map +1 -0
  118. package/lib/components/scan-admin/toolbars/search-toolbar.js +106 -0
  119. package/lib/components/scan-admin/toolbars/search-toolbar.js.map +1 -0
  120. package/lib/components/scan-admin/toolbars/tab-toolbar.d.ts +25 -0
  121. package/lib/components/scan-admin/toolbars/tab-toolbar.d.ts.map +1 -0
  122. package/lib/components/scan-admin/toolbars/tab-toolbar.js +33 -0
  123. package/lib/components/scan-admin/toolbars/tab-toolbar.js.map +1 -0
  124. package/lib/context/scan-admin/index.d.ts +21 -0
  125. package/lib/context/scan-admin/index.d.ts.map +1 -0
  126. package/lib/context/scan-admin/index.js +27 -0
  127. package/lib/context/scan-admin/index.js.map +1 -0
  128. package/lib/context/scan-admin/scan-actions.d.ts +19 -0
  129. package/lib/context/scan-admin/scan-actions.d.ts.map +1 -0
  130. package/lib/context/scan-admin/scan-actions.js +64 -0
  131. package/lib/context/scan-admin/scan-actions.js.map +1 -0
  132. package/lib/context/scan-admin/scan-api-actions.d.ts +26 -0
  133. package/lib/context/scan-admin/scan-api-actions.d.ts.map +1 -0
  134. package/lib/context/scan-admin/scan-api-actions.js +118 -0
  135. package/lib/context/scan-admin/scan-api-actions.js.map +1 -0
  136. package/lib/context/scan-admin/scan-api-effects.d.ts +40 -0
  137. package/lib/context/scan-admin/scan-api-effects.d.ts.map +1 -0
  138. package/lib/context/scan-admin/scan-api-effects.js +446 -0
  139. package/lib/context/scan-admin/scan-api-effects.js.map +1 -0
  140. package/lib/context/scan-admin/scan-context-types.d.ts +69 -0
  141. package/lib/context/scan-admin/scan-context-types.d.ts.map +1 -0
  142. package/lib/context/scan-admin/scan-context-types.js +14 -0
  143. package/lib/context/scan-admin/scan-context-types.js.map +1 -0
  144. package/lib/context/scan-admin/scan-context.d.ts +17 -0
  145. package/lib/context/scan-admin/scan-context.d.ts.map +1 -0
  146. package/lib/context/scan-admin/scan-context.js +90 -0
  147. package/lib/context/scan-admin/scan-context.js.map +1 -0
  148. package/lib/context/scan-admin/scan-helpers.d.ts +28 -0
  149. package/lib/context/scan-admin/scan-helpers.d.ts.map +1 -0
  150. package/lib/context/scan-admin/scan-helpers.js +56 -0
  151. package/lib/context/scan-admin/scan-helpers.js.map +1 -0
  152. package/lib/context/scan-admin/scan-reducer.d.ts +18 -0
  153. package/lib/context/scan-admin/scan-reducer.d.ts.map +1 -0
  154. package/lib/context/scan-admin/scan-reducer.js +194 -0
  155. package/lib/context/scan-admin/scan-reducer.js.map +1 -0
  156. package/lib/context/scan-admin/scan-types.d.ts +292 -0
  157. package/lib/context/scan-admin/scan-types.d.ts.map +1 -0
  158. package/lib/context/scan-admin/scan-types.js +67 -0
  159. package/lib/context/scan-admin/scan-types.js.map +1 -0
  160. package/lib/default/page-settings.d.ts.map +1 -1
  161. package/lib/default/page-settings.js +3 -0
  162. package/lib/default/page-settings.js.map +1 -1
  163. package/lib/default/theme.d.ts +50 -12
  164. package/lib/default/theme.d.ts.map +1 -1
  165. package/lib/default/theme.js +42 -0
  166. package/lib/default/theme.js.map +1 -1
  167. package/lib/extension-registry-service.d.ts +85 -1
  168. package/lib/extension-registry-service.d.ts.map +1 -1
  169. package/lib/extension-registry-service.js +197 -0
  170. package/lib/extension-registry-service.js.map +1 -1
  171. package/lib/extension-registry-types.d.ts +140 -0
  172. package/lib/extension-registry-types.d.ts.map +1 -1
  173. package/lib/extension-registry-types.js.map +1 -1
  174. package/lib/hooks/scan-admin/index.d.ts +34 -0
  175. package/lib/hooks/scan-admin/index.d.ts.map +1 -0
  176. package/lib/hooks/scan-admin/index.js +28 -0
  177. package/lib/hooks/scan-admin/index.js.map +1 -0
  178. package/lib/hooks/scan-admin/use-auto-rejected-tab.d.ts +76 -0
  179. package/lib/hooks/scan-admin/use-auto-rejected-tab.d.ts.map +1 -0
  180. package/lib/hooks/scan-admin/use-auto-rejected-tab.js +79 -0
  181. package/lib/hooks/scan-admin/use-auto-rejected-tab.js.map +1 -0
  182. package/lib/hooks/scan-admin/use-dialogs.d.ts +43 -0
  183. package/lib/hooks/scan-admin/use-dialogs.d.ts.map +1 -0
  184. package/lib/hooks/scan-admin/use-dialogs.js +55 -0
  185. package/lib/hooks/scan-admin/use-dialogs.js.map +1 -0
  186. package/lib/hooks/scan-admin/use-file-list-tab.d.ts +208 -0
  187. package/lib/hooks/scan-admin/use-file-list-tab.d.ts.map +1 -0
  188. package/lib/hooks/scan-admin/use-file-list-tab.js +125 -0
  189. package/lib/hooks/scan-admin/use-file-list-tab.js.map +1 -0
  190. package/lib/hooks/scan-admin/use-pagination.d.ts +36 -0
  191. package/lib/hooks/scan-admin/use-pagination.d.ts.map +1 -0
  192. package/lib/hooks/scan-admin/use-pagination.js +79 -0
  193. package/lib/hooks/scan-admin/use-pagination.js.map +1 -0
  194. package/lib/hooks/scan-admin/use-quarantined-tab.d.ts +92 -0
  195. package/lib/hooks/scan-admin/use-quarantined-tab.d.ts.map +1 -0
  196. package/lib/hooks/scan-admin/use-quarantined-tab.js +125 -0
  197. package/lib/hooks/scan-admin/use-quarantined-tab.js.map +1 -0
  198. package/lib/hooks/scan-admin/use-scan-card-state.d.ts +29 -0
  199. package/lib/hooks/scan-admin/use-scan-card-state.d.ts.map +1 -0
  200. package/lib/hooks/scan-admin/use-scan-card-state.js +50 -0
  201. package/lib/hooks/scan-admin/use-scan-card-state.js.map +1 -0
  202. package/lib/hooks/scan-admin/use-scan-filters.d.ts +53 -0
  203. package/lib/hooks/scan-admin/use-scan-filters.d.ts.map +1 -0
  204. package/lib/hooks/scan-admin/use-scan-filters.js +75 -0
  205. package/lib/hooks/scan-admin/use-scan-filters.js.map +1 -0
  206. package/lib/hooks/scan-admin/use-scans-tab.d.ts +85 -0
  207. package/lib/hooks/scan-admin/use-scans-tab.d.ts.map +1 -0
  208. package/lib/hooks/scan-admin/use-scans-tab.js +87 -0
  209. package/lib/hooks/scan-admin/use-scans-tab.js.map +1 -0
  210. package/lib/hooks/scan-admin/use-search.d.ts +32 -0
  211. package/lib/hooks/scan-admin/use-search.d.ts.map +1 -0
  212. package/lib/hooks/scan-admin/use-search.js +48 -0
  213. package/lib/hooks/scan-admin/use-search.js.map +1 -0
  214. package/lib/hooks/scan-admin/use-tab-navigation.d.ts +96 -0
  215. package/lib/hooks/scan-admin/use-tab-navigation.d.ts.map +1 -0
  216. package/lib/hooks/scan-admin/use-tab-navigation.js +70 -0
  217. package/lib/hooks/scan-admin/use-tab-navigation.js.map +1 -0
  218. package/lib/hooks/scan-admin/use-url-sync.d.ts +22 -0
  219. package/lib/hooks/scan-admin/use-url-sync.d.ts.map +1 -0
  220. package/lib/hooks/scan-admin/use-url-sync.js +252 -0
  221. package/lib/hooks/scan-admin/use-url-sync.js.map +1 -0
  222. package/lib/page-settings.d.ts +4 -0
  223. package/lib/page-settings.d.ts.map +1 -1
  224. package/lib/pages/admin-dashboard/admin-dashboard.d.ts +1 -0
  225. package/lib/pages/admin-dashboard/admin-dashboard.d.ts.map +1 -1
  226. package/lib/pages/admin-dashboard/admin-dashboard.js +23 -3
  227. package/lib/pages/admin-dashboard/admin-dashboard.js.map +1 -1
  228. package/lib/pages/admin-dashboard/publisher-admin.js +1 -1
  229. package/lib/pages/admin-dashboard/publisher-admin.js.map +1 -1
  230. package/lib/pages/admin-dashboard/publisher-revoke-dialog.d.ts.map +1 -1
  231. package/lib/pages/admin-dashboard/publisher-revoke-dialog.js +1 -1
  232. package/lib/pages/admin-dashboard/publisher-revoke-dialog.js.map +1 -1
  233. package/lib/pages/admin-dashboard/scan-admin.d.ts +20 -0
  234. package/lib/pages/admin-dashboard/scan-admin.d.ts.map +1 -0
  235. package/lib/pages/admin-dashboard/scan-admin.js +66 -0
  236. package/lib/pages/admin-dashboard/scan-admin.js.map +1 -0
  237. package/lib/pages/admin-dashboard/welcome.d.ts.map +1 -1
  238. package/lib/pages/admin-dashboard/welcome.js +2 -1
  239. package/lib/pages/admin-dashboard/welcome.js.map +1 -1
  240. package/lib/pages/extension-detail/extension-detail-overview.d.ts.map +1 -1
  241. package/lib/pages/extension-detail/extension-detail-overview.js +9 -1
  242. package/lib/pages/extension-detail/extension-detail-overview.js.map +1 -1
  243. package/lib/pages/extension-detail/extension-detail-reviews.d.ts.map +1 -1
  244. package/lib/pages/extension-detail/extension-detail-reviews.js +67 -18
  245. package/lib/pages/extension-detail/extension-detail-reviews.js.map +1 -1
  246. package/lib/pages/extension-detail/extension-detail.js +2 -2
  247. package/lib/pages/extension-detail/extension-detail.js.map +1 -1
  248. package/lib/pages/extension-detail/extension-rating-stars.d.ts +2 -2
  249. package/lib/pages/extension-detail/extension-rating-stars.d.ts.map +1 -1
  250. package/lib/pages/extension-detail/extension-rating-stars.js +1 -1
  251. package/lib/pages/extension-detail/extension-rating-stars.js.map +1 -1
  252. package/lib/pages/extension-list/extension-list-item.js +2 -2
  253. package/lib/pages/extension-list/extension-list-item.js.map +1 -1
  254. package/lib/pages/user/user-namespace-extension-list-item.d.ts.map +1 -1
  255. package/lib/pages/user/user-namespace-extension-list-item.js +23 -9
  256. package/lib/pages/user/user-namespace-extension-list-item.js.map +1 -1
  257. package/lib/pages/user/user-publisher-agreement.d.ts.map +1 -1
  258. package/lib/pages/user/user-publisher-agreement.js +34 -13
  259. package/lib/pages/user/user-publisher-agreement.js.map +1 -1
  260. package/lib/pages/user/user-settings-profile.d.ts.map +1 -1
  261. package/lib/pages/user/user-settings-profile.js +10 -5
  262. package/lib/pages/user/user-settings-profile.js.map +1 -1
  263. package/lib/pages/user/user-settings-tokens.d.ts.map +1 -1
  264. package/lib/pages/user/user-settings-tokens.js +13 -5
  265. package/lib/pages/user/user-settings-tokens.js.map +1 -1
  266. package/package.json +10 -9
  267. package/src/components/button-with-progress.tsx +2 -1
  268. package/src/components/sanitized-markdown.tsx +81 -1
  269. package/src/components/scan-admin/common/auto-refresh.tsx +79 -0
  270. package/src/components/scan-admin/common/conditional-tooltip.tsx +74 -0
  271. package/src/components/scan-admin/common/file-table.tsx +508 -0
  272. package/src/components/scan-admin/common/index.ts +18 -0
  273. package/src/components/scan-admin/common/tab-panel.tsx +42 -0
  274. package/src/components/scan-admin/common/utils.ts +48 -0
  275. package/src/components/scan-admin/dialogs/file-dialog.tsx +137 -0
  276. package/src/components/scan-admin/dialogs/index.ts +15 -0
  277. package/src/components/scan-admin/dialogs/quarantine-dialog.tsx +270 -0
  278. package/src/components/scan-admin/index.ts +52 -0
  279. package/src/components/scan-admin/scan-card/index.ts +20 -0
  280. package/src/components/scan-admin/scan-card/scan-card-content.tsx +457 -0
  281. package/src/components/scan-admin/scan-card/scan-card-expand-strip-badges.tsx +186 -0
  282. package/src/components/scan-admin/scan-card/scan-card-expand-strip.tsx +104 -0
  283. package/src/components/scan-admin/scan-card/scan-card-expanded-content.tsx +262 -0
  284. package/src/components/scan-admin/scan-card/scan-card-header.tsx +176 -0
  285. package/src/components/scan-admin/scan-card/scan-card.tsx +152 -0
  286. package/src/components/scan-admin/scan-card/scan-detail-card.tsx +144 -0
  287. package/src/components/scan-admin/scan-card/utils.ts +199 -0
  288. package/src/components/scan-admin/tab-contents/allow-list-tab-content.tsx +119 -0
  289. package/src/components/scan-admin/tab-contents/auto-rejected-tab-content.tsx +106 -0
  290. package/src/components/scan-admin/tab-contents/block-list-tab-content.tsx +119 -0
  291. package/src/components/scan-admin/tab-contents/index.ts +18 -0
  292. package/src/components/scan-admin/tab-contents/quarantined-tab-content.tsx +158 -0
  293. package/src/components/scan-admin/tab-contents/scans-tab-content.tsx +113 -0
  294. package/src/components/scan-admin/toolbars/counts-toolbar.tsx +262 -0
  295. package/src/components/scan-admin/toolbars/index.ts +16 -0
  296. package/src/components/scan-admin/toolbars/search-toolbar.tsx +255 -0
  297. package/src/components/scan-admin/toolbars/tab-toolbar.tsx +56 -0
  298. package/src/context/scan-admin/index.ts +43 -0
  299. package/src/context/scan-admin/scan-actions.ts +87 -0
  300. package/src/context/scan-admin/scan-api-actions.ts +137 -0
  301. package/src/context/scan-admin/scan-api-effects.ts +491 -0
  302. package/src/context/scan-admin/scan-context-types.ts +102 -0
  303. package/src/context/scan-admin/scan-context.tsx +123 -0
  304. package/src/context/scan-admin/scan-helpers.ts +63 -0
  305. package/src/context/scan-admin/scan-reducer.ts +321 -0
  306. package/src/context/scan-admin/scan-types.ts +337 -0
  307. package/src/default/page-settings.tsx +3 -0
  308. package/src/default/theme.tsx +102 -13
  309. package/src/extension-registry-service.ts +216 -1
  310. package/src/extension-registry-types.ts +157 -0
  311. package/src/hooks/scan-admin/index.ts +48 -0
  312. package/src/hooks/scan-admin/use-auto-rejected-tab.ts +85 -0
  313. package/src/hooks/scan-admin/use-dialogs.ts +83 -0
  314. package/src/hooks/scan-admin/use-file-list-tab.ts +149 -0
  315. package/src/hooks/scan-admin/use-pagination.ts +90 -0
  316. package/src/hooks/scan-admin/use-quarantined-tab.ts +138 -0
  317. package/src/hooks/scan-admin/use-scan-card-state.ts +73 -0
  318. package/src/hooks/scan-admin/use-scan-filters.ts +83 -0
  319. package/src/hooks/scan-admin/use-scans-tab.ts +92 -0
  320. package/src/hooks/scan-admin/use-search.ts +54 -0
  321. package/src/hooks/scan-admin/use-tab-navigation.ts +82 -0
  322. package/src/hooks/scan-admin/use-url-sync.ts +293 -0
  323. package/src/page-settings.ts +4 -0
  324. package/src/pages/admin-dashboard/admin-dashboard.tsx +26 -2
  325. package/src/pages/admin-dashboard/publisher-admin.tsx +1 -1
  326. package/src/pages/admin-dashboard/publisher-revoke-dialog.tsx +2 -1
  327. package/src/pages/admin-dashboard/scan-admin.tsx +109 -0
  328. package/src/pages/admin-dashboard/welcome.tsx +1 -0
  329. package/src/pages/extension-detail/extension-detail-overview.tsx +16 -2
  330. package/src/pages/extension-detail/extension-detail-reviews.tsx +116 -30
  331. package/src/pages/extension-detail/extension-detail.tsx +2 -2
  332. package/src/pages/extension-detail/extension-rating-stars.tsx +2 -2
  333. package/src/pages/extension-list/extension-list-item.tsx +2 -2
  334. package/src/pages/user/user-namespace-extension-list-item.tsx +38 -13
  335. package/src/pages/user/user-publisher-agreement.tsx +30 -11
  336. package/src/pages/user/user-settings-profile.tsx +10 -6
  337. package/src/pages/user/user-settings-tokens.tsx +15 -6
@@ -0,0 +1,457 @@
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 React from 'react';
15
+ import { Box, Typography, Link, IconButton, Tooltip } from '@mui/material';
16
+ import {
17
+ Check as CheckIcon,
18
+ Warning as WarningAmberIcon,
19
+ } from '@mui/icons-material';
20
+ import { ScanResult } from '../../../context/scan-admin';
21
+ import { ConditionalTooltip, formatDateTime, formatDuration } from '../common';
22
+ import { useTheme } from '@mui/material/styles';
23
+ import {
24
+ isRunning,
25
+ hasDownload,
26
+ getFileName,
27
+ } from './utils';
28
+
29
+ interface ScanCardContentProps {
30
+ scan: ScanResult;
31
+ showCheckbox?: boolean;
32
+ checked?: boolean;
33
+ onCheckboxChange?: (id: string, checked: boolean) => void;
34
+ liveDuration: string;
35
+ }
36
+
37
+ /**
38
+ * Content section of the ScanCard containing:
39
+ * - Publisher, Version, Download (Row 2)
40
+ * - Scan Start, Scan End, Duration, Decision Status (Row 3)
41
+ * - Checkbox for selection
42
+ */
43
+ export const ScanCardContent: React.FC<ScanCardContentProps> = ({
44
+ scan,
45
+ showCheckbox,
46
+ checked,
47
+ onCheckboxChange,
48
+ liveDuration,
49
+ }) => {
50
+ const theme = useTheme();
51
+ const [isCheckboxHovering, setIsCheckboxHovering] = React.useState(false);
52
+
53
+ return (
54
+ <>
55
+ {/* ROW 2 - Publisher, Version, Download, Checkbox */}
56
+ {/* Column 1: Empty (below icon) */}
57
+ <Box sx={{ gridRow: '2', gridColumn: '1' }} />
58
+
59
+ {/* Column 2: Publisher */}
60
+ <Box sx={{ gridRow: '2', gridColumn: '2', minWidth: 0 }}>
61
+ <Typography
62
+ variant='caption'
63
+ color='text.secondary'
64
+ display='block'
65
+ sx={{
66
+ overflow: 'hidden',
67
+ textOverflow: 'ellipsis',
68
+ whiteSpace: 'nowrap',
69
+ }}
70
+ >
71
+ Publisher
72
+ </Typography>
73
+ <ConditionalTooltip title={scan.publisher} arrow>
74
+ <Box
75
+ sx={{
76
+ overflow: 'hidden',
77
+ textOverflow: 'ellipsis',
78
+ whiteSpace: 'nowrap',
79
+ }}
80
+ >
81
+ <Link
82
+ href={scan.publisherUrl || undefined}
83
+ target='_blank'
84
+ rel='noopener noreferrer'
85
+ variant='body2'
86
+ sx={{
87
+ overflow: 'hidden',
88
+ textOverflow: 'ellipsis',
89
+ whiteSpace: 'nowrap',
90
+ display: 'block',
91
+ }}
92
+ >
93
+ {scan.publisher}
94
+ </Link>
95
+ </Box>
96
+ </ConditionalTooltip>
97
+ </Box>
98
+
99
+ {/* Column 3: Version */}
100
+ <Box sx={{ gridRow: '2', gridColumn: '3', minWidth: 0 }}>
101
+ <Typography
102
+ variant='caption'
103
+ color='text.secondary'
104
+ display='block'
105
+ sx={{
106
+ overflow: 'hidden',
107
+ textOverflow: 'ellipsis',
108
+ whiteSpace: 'nowrap',
109
+ }}
110
+ >
111
+ Version
112
+ </Typography>
113
+ <ConditionalTooltip title={scan.version} arrow>
114
+ <Typography
115
+ variant='body2'
116
+ sx={{
117
+ display: 'block',
118
+ overflow: 'hidden',
119
+ textOverflow: 'ellipsis',
120
+ whiteSpace: 'nowrap',
121
+ }}
122
+ >
123
+ {scan.version}
124
+ </Typography>
125
+ </ConditionalTooltip>
126
+ </Box>
127
+
128
+ {/* Column 4: Download */}
129
+ <Box sx={{ gridRow: '2', gridColumn: '4', minWidth: 0 }}>
130
+ <Typography
131
+ variant='caption'
132
+ color='text.secondary'
133
+ display='block'
134
+ sx={{
135
+ overflow: 'hidden',
136
+ textOverflow: 'ellipsis',
137
+ whiteSpace: 'nowrap',
138
+ }}
139
+ >
140
+ Download
141
+ </Typography>
142
+ {isRunning(scan.status) ? (
143
+ <Typography variant='body2' color='text.disabled'>
144
+ N/A
145
+ </Typography>
146
+ ) : hasDownload(scan) && scan.downloadUrl ? (
147
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, minWidth: 0 }}>
148
+ {scan.status === 'QUARANTINED' && (
149
+ <Tooltip
150
+ title='Potentially malicious'
151
+ arrow
152
+ disableInteractive
153
+ PopperProps={{
154
+ disablePortal: true,
155
+ sx: { pointerEvents: 'none' },
156
+ }}
157
+ >
158
+ <WarningAmberIcon
159
+ sx={{
160
+ fontSize: 16,
161
+ color: theme.palette.quarantined.dark,
162
+ flexShrink: 0,
163
+ }}
164
+ />
165
+ </Tooltip>
166
+ )}
167
+ <ConditionalTooltip title={getFileName(scan.downloadUrl)} arrow>
168
+ <Link
169
+ href={scan.downloadUrl}
170
+ variant='body2'
171
+ sx={{
172
+ overflow: 'hidden',
173
+ textOverflow: 'ellipsis',
174
+ whiteSpace: 'nowrap',
175
+ minWidth: 0,
176
+ display: 'block',
177
+ fontSize: '0.875rem',
178
+ }}
179
+ >
180
+ {getFileName(scan.downloadUrl)}
181
+ </Link>
182
+ </ConditionalTooltip>
183
+ </Box>
184
+ ) : (
185
+ <Typography variant='body2' color='text.disabled'>
186
+ N/A
187
+ </Typography>
188
+ )}
189
+ </Box>
190
+
191
+ {/* Column 5: Checkbox */}
192
+ <Box sx={{ gridRow: '2', gridColumn: '5', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', minWidth: 0 }}>
193
+ {showCheckbox && (
194
+ <IconButton
195
+ onClick={() => onCheckboxChange?.(scan.id, !checked)}
196
+ onMouseEnter={() => setIsCheckboxHovering(true)}
197
+ onMouseLeave={() => setIsCheckboxHovering(false)}
198
+ disableRipple
199
+ sx={{
200
+ padding: 0,
201
+ width: 36,
202
+ height: 36,
203
+ backgroundColor: 'transparent',
204
+ }}
205
+ >
206
+ <Box
207
+ className='checkbox-circle'
208
+ sx={{
209
+ position: 'relative',
210
+ width: 36,
211
+ height: 36,
212
+ display: 'flex',
213
+ alignItems: 'center',
214
+ justifyContent: 'center',
215
+ }}
216
+ >
217
+ <Box
218
+ className='checkbox-circle-outline'
219
+ sx={{
220
+ position: 'absolute',
221
+ width: 36,
222
+ height: 36,
223
+ borderRadius: '50%',
224
+ border: checked ? 'none' : `2px solid ${isCheckboxHovering ? theme.palette.selected.border : theme.palette.scanBackground.light}`,
225
+ backgroundColor: checked
226
+ ? 'secondary.main'
227
+ : isCheckboxHovering
228
+ ? theme.palette.selected.background
229
+ : 'transparent',
230
+ transition: 'border-color 0.2s, background-color 0.2s',
231
+ }}
232
+ />
233
+ <CheckIcon
234
+ className='checkbox-icon'
235
+ sx={{
236
+ fontSize: 24,
237
+ color: checked
238
+ ? 'white'
239
+ : isCheckboxHovering
240
+ ? theme.palette.selected.border
241
+ : theme.palette.scanBackground.light,
242
+ position: 'relative',
243
+ zIndex: 1,
244
+ transition: 'color 0.2s',
245
+ }}
246
+ />
247
+ </Box>
248
+ </IconButton>
249
+ )}
250
+ </Box>
251
+
252
+ {/* ROW 3 - Scan Start, Scan End, Scan Duration, Decision Status */}
253
+ {/* Column 1: Empty (below icon) */}
254
+ <Box sx={{ gridRow: '3', gridColumn: '1' }} />
255
+
256
+ {/* Column 2: Scan Start */}
257
+ <Box sx={{ gridRow: '3', gridColumn: '2', minWidth: 0 }}>
258
+ <Typography
259
+ variant='caption'
260
+ color='text.secondary'
261
+ display='block'
262
+ sx={{
263
+ overflow: 'hidden',
264
+ textOverflow: 'ellipsis',
265
+ whiteSpace: 'nowrap',
266
+ }}
267
+ >
268
+ Scan Start
269
+ </Typography>
270
+ <ConditionalTooltip title={formatDateTime(scan.dateScanStarted)} arrow>
271
+ <Typography
272
+ variant='body2'
273
+ sx={{
274
+ display: 'block',
275
+ fontSize: '0.8rem',
276
+ overflow: 'hidden',
277
+ textOverflow: 'ellipsis',
278
+ whiteSpace: 'nowrap',
279
+ }}
280
+ >
281
+ {formatDateTime(scan.dateScanStarted)}
282
+ </Typography>
283
+ </ConditionalTooltip>
284
+ </Box>
285
+
286
+ {/* Column 3: Scan End */}
287
+ <Box sx={{ gridRow: '3', gridColumn: '3', minWidth: 0 }}>
288
+ <Typography
289
+ variant='caption'
290
+ color='text.secondary'
291
+ display='block'
292
+ sx={{
293
+ overflow: 'hidden',
294
+ textOverflow: 'ellipsis',
295
+ whiteSpace: 'nowrap',
296
+ }}
297
+ >
298
+ Scan End
299
+ </Typography>
300
+ {isRunning(scan.status) ? (
301
+ <ConditionalTooltip title={`${scan.status}...`} arrow>
302
+ <Typography
303
+ variant='body2'
304
+ sx={{
305
+ display: 'block',
306
+ background: theme.palette.gray.gradient,
307
+ backgroundSize: '200% 100%',
308
+ backgroundClip: 'text',
309
+ WebkitBackgroundClip: 'text',
310
+ color: 'transparent',
311
+ animation: 'shimmer 2s infinite',
312
+ '@keyframes shimmer': {
313
+ '0%': { backgroundPosition: '200% 0' },
314
+ '100%': { backgroundPosition: '-200% 0' },
315
+ },
316
+ overflow: 'hidden',
317
+ textOverflow: 'ellipsis',
318
+ whiteSpace: 'nowrap',
319
+ }}
320
+ >
321
+ {scan.status}...
322
+ </Typography>
323
+ </ConditionalTooltip>
324
+ ) : scan.dateScanEnded ? (
325
+ <ConditionalTooltip title={formatDateTime(scan.dateScanEnded)} arrow>
326
+ <Typography
327
+ variant='body2'
328
+ sx={{
329
+ display: 'block',
330
+ fontSize: '0.8rem',
331
+ overflow: 'hidden',
332
+ textOverflow: 'ellipsis',
333
+ whiteSpace: 'nowrap',
334
+ }}
335
+ >
336
+ {formatDateTime(scan.dateScanEnded)}
337
+ </Typography>
338
+ </ConditionalTooltip>
339
+ ) : (
340
+ <Typography variant='body2' color='text.disabled'>
341
+ N/A
342
+ </Typography>
343
+ )}
344
+ </Box>
345
+
346
+ {/* Column 4: Scan Duration */}
347
+ <Box sx={{ gridRow: '3', gridColumn: '4', minWidth: 0 }}>
348
+ <Typography
349
+ variant='caption'
350
+ color='text.secondary'
351
+ display='block'
352
+ sx={{
353
+ overflow: 'hidden',
354
+ textOverflow: 'ellipsis',
355
+ whiteSpace: 'nowrap',
356
+ }}
357
+ >
358
+ Scan Duration
359
+ </Typography>
360
+ {isRunning(scan.status) ? (
361
+ <ConditionalTooltip title={liveDuration} arrow>
362
+ <Typography
363
+ variant='body2'
364
+ sx={{
365
+ display: 'block',
366
+ background: theme.palette.gray.gradient,
367
+ backgroundSize: '200% 100%',
368
+ backgroundClip: 'text',
369
+ WebkitBackgroundClip: 'text',
370
+ color: 'transparent',
371
+ animation: 'shimmer 2s infinite',
372
+ '@keyframes shimmer': {
373
+ '0%': { backgroundPosition: '200% 0' },
374
+ '100%': { backgroundPosition: '-200% 0' },
375
+ },
376
+ overflow: 'hidden',
377
+ textOverflow: 'ellipsis',
378
+ whiteSpace: 'nowrap',
379
+ }}
380
+ >
381
+ {liveDuration}
382
+ </Typography>
383
+ </ConditionalTooltip>
384
+ ) : (
385
+ <ConditionalTooltip title={formatDuration(scan.dateScanStarted, scan.dateScanEnded || undefined)} arrow>
386
+ <Typography
387
+ variant='body2'
388
+ sx={{
389
+ display: 'block',
390
+ overflow: 'hidden',
391
+ textOverflow: 'ellipsis',
392
+ whiteSpace: 'nowrap',
393
+ }}
394
+ >
395
+ {formatDuration(scan.dateScanStarted, scan.dateScanEnded || undefined)}
396
+ </Typography>
397
+ </ConditionalTooltip>
398
+ )}
399
+ </Box>
400
+
401
+ {/* Column 5: Decision Status */}
402
+ {scan.status === 'QUARANTINED' && scan.adminDecision && (
403
+ <Box sx={{
404
+ gridRow: '3',
405
+ gridColumn: '5',
406
+ display: 'flex',
407
+ justifyContent: 'flex-end',
408
+ alignSelf: 'end',
409
+ minWidth: 0,
410
+ }}>
411
+ <Tooltip
412
+ title={`Decided by ${scan.adminDecision.decidedBy} on ${formatDateTime(scan.adminDecision.dateDecided)}`}
413
+ arrow
414
+ disableInteractive
415
+ PopperProps={{
416
+ disablePortal: true,
417
+ sx: { pointerEvents: 'none' },
418
+ }}
419
+ >
420
+ <Typography
421
+ variant='h6'
422
+ sx={{
423
+ fontWeight: 700,
424
+ color: scan.adminDecision.decision.toLowerCase() === 'allowed' ? theme.palette.allowed : theme.palette.blocked,
425
+ whiteSpace: 'nowrap',
426
+ cursor: 'help',
427
+ }}
428
+ >
429
+ {scan.adminDecision.decision.toLowerCase() === 'allowed' ? 'ALLOWED' : 'BLOCKED'}
430
+ </Typography>
431
+ </Tooltip>
432
+ </Box>
433
+ )}
434
+ {scan.status === 'QUARANTINED' && !scan.adminDecision && (
435
+ <Box sx={{
436
+ gridRow: '3',
437
+ gridColumn: '5',
438
+ display: 'flex',
439
+ justifyContent: 'flex-end',
440
+ alignSelf: 'end',
441
+ minWidth: 0,
442
+ }}>
443
+ <Typography
444
+ variant='h6'
445
+ sx={{
446
+ fontWeight: 700,
447
+ color: theme.palette.review,
448
+ whiteSpace: 'nowrap',
449
+ }}
450
+ >
451
+ NEEDS REVIEW
452
+ </Typography>
453
+ </Box>
454
+ )}
455
+ </>
456
+ );
457
+ };
@@ -0,0 +1,186 @@
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 React, { useRef, useEffect, useState, useLayoutEffect } from 'react';
15
+ import { Box, Chip, Typography } from '@mui/material';
16
+ import { useTheme, alpha } from '@mui/material/styles';
17
+ import { DetailBadge } from './utils';
18
+
19
+ interface ScanCardExpandStripBadgesProps {
20
+ badges: DetailBadge[];
21
+ containerWidth: number;
22
+ maxWidthPercent?: number;
23
+ }
24
+
25
+ /**
26
+ * Renders badges with overflow handling - shows as many badges as fit
27
+ * within the available width, plus a "+ X more" indicator for hidden badges.
28
+ */
29
+ export const ScanCardExpandStripBadges: React.FC<ScanCardExpandStripBadgesProps> = ({
30
+ badges,
31
+ containerWidth,
32
+ maxWidthPercent = 0.45,
33
+ }) => {
34
+ const theme = useTheme();
35
+ const measureRef = useRef<HTMLDivElement>(null);
36
+ const [visibleCount, setVisibleCount] = useState<number | null>(null);
37
+
38
+ const calculateVisibleBadges = () => {
39
+ if (!measureRef.current || badges.length === 0 || containerWidth <= 0) {
40
+ return;
41
+ }
42
+
43
+ const availableWidth = containerWidth * maxWidthPercent;
44
+ const chips = measureRef.current.querySelectorAll('.measure-chip');
45
+
46
+ if (chips.length === 0) {
47
+ return;
48
+ }
49
+
50
+ // 65px width for "+ X more" text
51
+ const moreIndicatorWidth = 65;
52
+ const gap = 4; // 0.5 spacing unit = 4px
53
+
54
+ let totalWidth = 0;
55
+ let count = 0;
56
+
57
+ for (let index = 0; index < chips.length; index++) {
58
+ const chip = chips[index] as HTMLElement;
59
+ const chipWidth = chip.offsetWidth;
60
+ const widthWithGap = chipWidth + (index > 0 ? gap : 0);
61
+
62
+ // Check if this chip fits
63
+ // If not all badges fit, we need room for the "+ X more" indicator
64
+ const remainingBadges = badges.length - (index + 1);
65
+ const needsMoreIndicator = remainingBadges > 0;
66
+ const reservedWidth = needsMoreIndicator ? moreIndicatorWidth + gap : 0;
67
+
68
+ if (totalWidth + widthWithGap + reservedWidth <= availableWidth) {
69
+ totalWidth += widthWithGap;
70
+ count++;
71
+ } else {
72
+ break;
73
+ }
74
+ }
75
+
76
+ setVisibleCount(count);
77
+ };
78
+
79
+ // Use layoutEffect to measure before paint (to avoid flicker)
80
+ useLayoutEffect(() => {
81
+ calculateVisibleBadges();
82
+ }, [badges, containerWidth]);
83
+
84
+ // Recalculate when container width changes
85
+ useEffect(() => {
86
+ calculateVisibleBadges();
87
+ }, [containerWidth]);
88
+
89
+ // Use all badges until calculation completes
90
+ const effectiveVisibleCount = visibleCount ?? badges.length;
91
+ const visibleBadges = badges.slice(0, effectiveVisibleCount);
92
+ const hiddenCount = badges.length - effectiveVisibleCount;
93
+
94
+ const chipStyles = (badge: DetailBadge) => ({
95
+ height: '20px',
96
+ fontSize: '0.7rem',
97
+ flexShrink: 0,
98
+ ...(badge.type === 'error' ? {
99
+ // Error badges: solid grey for required, striped for optional
100
+ // Must set backgroundColor to 'transparent' when using striped background to override Chip defaults
101
+ backgroundColor: badge.isEnforced ? theme.palette.errorStatus.dark : 'transparent',
102
+ color: theme.palette.errorStatus.light,
103
+ background: !badge.isEnforced ? `${theme.palette.unenforced.stripe}, ${theme.palette.errorStatus.dark}` : undefined,
104
+ } : badge.type === 'threat' ? {
105
+ backgroundColor: badge.isEnforced ? theme.palette.quarantined.dark : 'transparent',
106
+ color: theme.palette.quarantined.light,
107
+ background: !badge.isEnforced ? `${theme.palette.unenforced.stripe}, ${theme.palette.quarantined.dark}` : undefined,
108
+ } : {
109
+ backgroundColor: badge.isEnforced ? theme.palette.rejected.dark : 'transparent',
110
+ color: theme.palette.rejected.light,
111
+ background: !badge.isEnforced ? `${theme.palette.unenforced.stripe}, ${theme.palette.rejected.dark}` : undefined,
112
+ }),
113
+ });
114
+
115
+ if (badges.length === 0) {
116
+ return null;
117
+ }
118
+
119
+ return (
120
+ <>
121
+ {/* Hidden measurement container - always renders all badges for measurement */}
122
+ <Box
123
+ ref={measureRef}
124
+ sx={{
125
+ position: 'absolute',
126
+ visibility: 'hidden',
127
+ pointerEvents: 'none',
128
+ display: 'flex',
129
+ alignItems: 'center',
130
+ gap: 0.5,
131
+ flexWrap: 'nowrap',
132
+ left: 0,
133
+ top: 0,
134
+ }}
135
+ aria-hidden='true'
136
+ >
137
+ {badges.map((badge, index) => (
138
+ <Chip
139
+ key={`measure-${badge.label}-${index}`}
140
+ className='measure-chip'
141
+ label={badge.label}
142
+ size='small'
143
+ sx={chipStyles(badge)}
144
+ />
145
+ ))}
146
+ </Box>
147
+
148
+ {/* Visible container - only shows badges that fit */}
149
+ <Box
150
+ sx={{
151
+ display: 'flex',
152
+ alignItems: 'center',
153
+ gap: 0.5,
154
+ flexWrap: 'nowrap',
155
+ overflow: 'hidden',
156
+ maxWidth: `${maxWidthPercent * 100}%`,
157
+ minWidth: 0,
158
+ }}
159
+ >
160
+ {visibleBadges.map((badge, index) => (
161
+ <Chip
162
+ key={`${badge.label}-${index}`}
163
+ label={badge.label}
164
+ size='small'
165
+ sx={chipStyles(badge)}
166
+ />
167
+ ))}
168
+ {hiddenCount > 0 && (
169
+ <Typography
170
+ variant='caption'
171
+ sx={{
172
+ flexShrink: 0,
173
+ color: alpha(theme.palette.text.secondary, 0.8),
174
+ fontSize: '0.7rem',
175
+ fontWeight: 500,
176
+ whiteSpace: 'nowrap',
177
+ ml: 0.5,
178
+ }}
179
+ >
180
+ + {hiddenCount} more
181
+ </Typography>
182
+ )}
183
+ </Box>
184
+ </>
185
+ );
186
+ };