@cccsaurora/howler-ui 2.19.0-cases.863 → 2.19.0-dev.1000

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 (397) hide show
  1. package/api/index.d.ts +0 -4
  2. package/api/index.js +2 -10
  3. package/api/search/facet/hit.d.ts +3 -1
  4. package/api/search/facet/index.d.ts +1 -3
  5. package/api/search/index.d.ts +1 -2
  6. package/api/search/index.js +1 -2
  7. package/commons/components/leftnav/LeftNavDrawer.js +1 -1
  8. package/components/app/App.d.ts +1 -0
  9. package/components/app/App.js +20 -42
  10. package/components/app/hooks/useMatchers.d.ts +1 -1
  11. package/components/app/hooks/useMatchers.js +11 -23
  12. package/components/app/hooks/useMatchers.test.js +22 -22
  13. package/components/app/hooks/useTitle.js +5 -5
  14. package/components/app/providers/FavouritesProvider.js +2 -6
  15. package/components/app/providers/HitProvider.d.ts +22 -0
  16. package/components/app/providers/{RecordProvider.js → HitProvider.js} +42 -42
  17. package/components/app/providers/{RecordSearchProvider.d.ts → HitSearchProvider.d.ts} +6 -6
  18. package/components/app/providers/{RecordSearchProvider.js → HitSearchProvider.js} +17 -12
  19. package/components/app/providers/{RecordSearchProvider.test.js → HitSearchProvider.test.js} +71 -52
  20. package/components/app/providers/ModalProvider.d.ts +1 -1
  21. package/components/app/providers/ModalProvider.js +5 -1
  22. package/components/app/providers/ParameterProvider.d.ts +2 -9
  23. package/components/app/providers/ParameterProvider.js +240 -165
  24. package/components/app/providers/ParameterProvider.test.js +94 -346
  25. package/components/app/providers/SocketProvider.d.ts +2 -11
  26. package/components/app/providers/SocketProvider.js +5 -18
  27. package/components/app/providers/UserListProvider.js +8 -28
  28. package/components/elements/PluginTypography.d.ts +1 -2
  29. package/components/elements/PluginTypography.js +2 -3
  30. package/components/elements/UserList.d.ts +2 -5
  31. package/components/elements/UserList.js +8 -18
  32. package/components/elements/addons/buttons/CustomButton.test.js +106 -0
  33. package/components/elements/addons/layout/FlexOne.test.js +30 -0
  34. package/components/elements/addons/lists/TuiListBase.js +4 -0
  35. package/components/elements/addons/lists/TuiListElement.js +6 -3
  36. package/components/elements/addons/lists/index.d.ts +1 -0
  37. package/components/elements/addons/search/SearchPagination.test.js +80 -0
  38. package/components/elements/addons/search/SearchTotal.test.js +45 -0
  39. package/components/elements/addons/search/phrase/Phrase.js +1 -1
  40. package/components/elements/display/ChipPopper.d.ts +1 -1
  41. package/components/elements/display/ChipPopper.js +5 -5
  42. package/components/elements/display/DocumentationButton.test.js +84 -0
  43. package/components/elements/display/DynamicTabs.test.js +93 -0
  44. package/components/elements/display/HowlerAvatar.js +2 -1
  45. package/components/elements/display/HowlerCard.js +1 -1
  46. package/components/elements/display/HowlerCard.test.js +55 -0
  47. package/components/elements/display/Image.test.js +79 -0
  48. package/components/elements/display/Markdown.js +9 -2
  49. package/components/elements/display/Modal.js +0 -2
  50. package/components/elements/display/QueryResultText.test.js +48 -0
  51. package/components/elements/display/TextDivider.test.js +43 -0
  52. package/components/elements/display/TypingIndicator.test.js +33 -0
  53. package/components/elements/display/icons/BundleButton.d.ts +6 -0
  54. package/components/elements/display/icons/BundleButton.js +32 -0
  55. package/components/elements/display/modals/ConfirmDeleteModal.d.ts +4 -0
  56. package/components/elements/display/modals/ConfirmDeleteModal.js +4 -2
  57. package/components/elements/hit/HitActions.js +4 -4
  58. package/components/elements/hit/HitBanner.d.ts +0 -1
  59. package/components/elements/hit/HitBanner.js +49 -31
  60. package/components/elements/hit/HitCard.d.ts +0 -2
  61. package/components/elements/hit/HitCard.js +7 -7
  62. package/components/elements/{record/RecordComments.d.ts → hit/HitComments.d.ts} +4 -5
  63. package/components/elements/{record/RecordComments.js → hit/HitComments.js} +28 -29
  64. package/components/elements/{ObjectDetails.js → hit/HitDetails.js} +17 -17
  65. package/components/elements/hit/HitLabels.js +2 -2
  66. package/components/elements/hit/HitOutline.d.ts +0 -1
  67. package/components/elements/hit/HitOutline.js +3 -3
  68. package/components/elements/hit/{HitPreview.d.ts → HitQuickSearch.d.ts} +3 -3
  69. package/components/elements/hit/{HitPreview.js → HitQuickSearch.js} +4 -10
  70. package/components/elements/hit/HitRelated.d.ts +6 -0
  71. package/components/elements/hit/HitRelated.js +7 -0
  72. package/components/elements/hit/HitSummary.d.ts +1 -2
  73. package/components/elements/hit/HitSummary.js +8 -8
  74. package/components/elements/{record/RecordWorklog.d.ts → hit/HitWorklog.d.ts} +3 -4
  75. package/components/elements/{record/RecordWorklog.js → hit/HitWorklog.js} +13 -15
  76. package/components/elements/hit/aggregate/HitGraph.js +8 -8
  77. package/components/elements/hit/elements/{Assigned.d.ts → HitUsers.d.ts} +5 -2
  78. package/components/elements/hit/elements/HitUsers.js +33 -0
  79. package/components/elements/hit/outlines/DefaultOutline.js +1 -1
  80. package/components/elements/view/ViewTitle.d.ts +0 -1
  81. package/components/elements/view/ViewTitle.js +2 -9
  82. package/components/hooks/useHitActions.d.ts +1 -1
  83. package/components/hooks/useHitActions.js +4 -4
  84. package/components/hooks/{useRecordSelection.d.ts → useHitSelection.d.ts} +2 -2
  85. package/components/hooks/{useRecordSelection.js → useHitSelection.js} +33 -12
  86. package/components/hooks/useMyPreferences.js +3 -11
  87. package/components/hooks/useMySearch.js +2 -2
  88. package/components/hooks/useMySitemap.js +1 -4
  89. package/components/hooks/useMyTheme.js +2 -9
  90. package/components/routes/403.test.js +27 -0
  91. package/components/routes/404.test.js +26 -0
  92. package/components/routes/ErrorBoundary.test.js +43 -0
  93. package/components/routes/ErrorOccured.test.js +35 -0
  94. package/components/routes/Logout.test.js +59 -0
  95. package/components/routes/action/edit/ActionEditor.js +2 -2
  96. package/components/routes/action/view/ActionDetails.js +4 -2
  97. package/components/routes/action/view/ActionSearch.js +12 -7
  98. package/components/routes/advanced/QueryBuilder.js +1 -1
  99. package/components/routes/advanced/QueryEditor.js +3 -3
  100. package/components/routes/advanced/historyCompletionProvider.js +3 -3
  101. package/components/routes/analytics/AnalyticDetails.js +12 -8
  102. package/components/routes/analytics/AnalyticSearch.js +1 -1
  103. package/components/routes/dossiers/DossierEditor.js +2 -2
  104. package/components/routes/dossiers/DossierEditor.test.js +1 -1
  105. package/components/routes/dossiers/Dossiers.js +15 -11
  106. package/components/routes/help/ApiDocumentation.js +1 -1
  107. package/components/routes/help/BundleDocumentation.d.ts +3 -0
  108. package/components/routes/help/BundleDocumentation.js +12 -0
  109. package/components/routes/help/HitBannerDocumentation.js +0 -1
  110. package/components/routes/help/HitDocumentation.js +3 -1
  111. package/components/routes/help/markdown/en/bundles.md.js +1 -0
  112. package/components/routes/help/markdown/en/client.md.js +1 -1
  113. package/components/routes/help/markdown/fr/bundles.md.js +1 -0
  114. package/components/routes/help/markdown/fr/client.md.js +1 -1
  115. package/components/routes/hits/search/BundleParentMenu.d.ts +6 -0
  116. package/components/routes/hits/search/BundleParentMenu.js +32 -0
  117. package/components/routes/hits/search/BundleScroller.d.ts +2 -0
  118. package/components/routes/hits/search/BundleScroller.js +6 -0
  119. package/components/routes/hits/search/{RecordBrowser.js → HitBrowser.js} +9 -9
  120. package/components/{elements/record/RecordContextMenu.d.ts → routes/hits/search/HitContextMenu.d.ts} +3 -3
  121. package/components/routes/hits/search/HitContextMenu.js +239 -0
  122. package/components/{elements/record/RecordContextMenu.test.js → routes/hits/search/HitContextMenu.test.js} +43 -98
  123. package/components/routes/hits/search/{RecordQuery.d.ts → HitQuery.d.ts} +2 -2
  124. package/components/routes/hits/search/{RecordQuery.js → HitQuery.js} +6 -6
  125. package/components/routes/hits/search/InformationPane.d.ts +0 -1
  126. package/components/routes/hits/search/InformationPane.js +63 -50
  127. package/components/routes/hits/search/LayoutSettings.js +3 -3
  128. package/components/routes/hits/search/QuerySettings.js +1 -2
  129. package/components/routes/hits/search/QuerySettings.test.js +9 -14
  130. package/components/routes/hits/search/SearchPane.js +49 -26
  131. package/components/routes/hits/search/ViewLink.js +3 -3
  132. package/components/routes/hits/search/ViewLink.test.js +8 -8
  133. package/components/routes/hits/search/grid/AddColumnModal.js +4 -5
  134. package/components/routes/hits/search/grid/EnhancedCell.d.ts +1 -2
  135. package/components/routes/hits/search/grid/EnhancedCell.js +2 -2
  136. package/components/routes/hits/search/grid/HitGrid.js +18 -20
  137. package/components/routes/hits/search/grid/{RecordRow.d.ts → HitRow.d.ts} +2 -3
  138. package/components/routes/hits/search/grid/{RecordRow.js → HitRow.js} +9 -11
  139. package/components/routes/hits/search/shared/CustomSpan.js +7 -7
  140. package/components/routes/hits/search/shared/CustomSpan.test.js +170 -0
  141. package/components/routes/hits/view/HitViewer.js +13 -12
  142. package/components/routes/home/AddNewCard.test.js +68 -0
  143. package/components/routes/home/ViewCard.js +41 -47
  144. package/components/routes/home/ViewRefresh.test.js +79 -0
  145. package/components/routes/overviews/OverviewCard.test.js +108 -0
  146. package/components/{elements/MarkdownEditor.js → routes/overviews/OverviewEditor.js} +3 -3
  147. package/components/routes/overviews/OverviewViewer.js +14 -10
  148. package/components/routes/overviews/Overviews.js +15 -11
  149. package/components/routes/settings/LocalSection.js +2 -1
  150. package/components/routes/settings/SettingsSection.test.js +19 -0
  151. package/components/routes/templates/TemplateCard.d.ts +3 -1
  152. package/components/routes/templates/TemplateCard.js +8 -4
  153. package/components/routes/templates/TemplateCard.test.d.ts +1 -0
  154. package/components/routes/templates/TemplateCard.test.js +115 -0
  155. package/components/routes/templates/TemplateViewer.js +57 -16
  156. package/components/routes/templates/Templates.js +23 -6
  157. package/components/routes/views/ViewComposer.js +19 -46
  158. package/components/routes/views/Views.js +8 -4
  159. package/locales/en/translation.json +17 -117
  160. package/locales/fr/translation.json +19 -119
  161. package/models/WithMetadata.d.ts +1 -2
  162. package/models/entities/generated/{ThreatEnrichment.d.ts → Enrichment.d.ts} +1 -1
  163. package/models/entities/generated/Hit.d.ts +1 -1
  164. package/models/entities/generated/Howler.d.ts +6 -0
  165. package/models/entities/generated/Rule.d.ts +9 -6
  166. package/models/entities/generated/Threat.d.ts +2 -2
  167. package/models/entities/generated/UserUser.d.ts +2 -0
  168. package/models/entities/generated/View.d.ts +0 -1
  169. package/package.json +112 -132
  170. package/plugins/clue/components/ClueTypography.js +2 -2
  171. package/plugins/clue/utils.d.ts +1 -2
  172. package/rest/FetchClient.test.d.ts +1 -0
  173. package/rest/FetchClient.test.js +81 -0
  174. package/setupTests.js +5 -0
  175. package/tests/mocks.d.ts +1 -11
  176. package/tests/mocks.js +7 -12
  177. package/tests/server-handlers.js +1 -6
  178. package/tests/utils.d.ts +0 -4
  179. package/tests/utils.js +0 -20
  180. package/utils/Throttler.test.d.ts +1 -0
  181. package/utils/Throttler.test.js +135 -0
  182. package/utils/actionUtils.test.d.ts +1 -0
  183. package/utils/actionUtils.test.js +140 -0
  184. package/utils/constants.d.ts +4 -4
  185. package/utils/constants.js +1 -6
  186. package/utils/hitFunctions.d.ts +1 -2
  187. package/utils/hitFunctions.js +4 -4
  188. package/utils/hitFunctions.test.d.ts +1 -0
  189. package/utils/hitFunctions.test.js +52 -0
  190. package/utils/localStorage.test.d.ts +1 -0
  191. package/utils/localStorage.test.js +96 -0
  192. package/utils/menuUtils.test.d.ts +1 -0
  193. package/utils/menuUtils.test.js +198 -0
  194. package/utils/sessionStorage.test.d.ts +1 -0
  195. package/utils/sessionStorage.test.js +81 -0
  196. package/utils/socketUtils.d.ts +0 -14
  197. package/utils/socketUtils.js +1 -17
  198. package/utils/socketUtils.test.js +16 -49
  199. package/utils/stringUtils.test.d.ts +1 -0
  200. package/utils/stringUtils.test.js +159 -0
  201. package/utils/utils.test.d.ts +1 -0
  202. package/utils/utils.test.js +292 -0
  203. package/utils/viewUtils.js +0 -3
  204. package/utils/viewUtils.test.d.ts +1 -0
  205. package/utils/viewUtils.test.js +45 -0
  206. package/utils/xsrf.test.d.ts +1 -0
  207. package/utils/xsrf.test.js +41 -0
  208. package/api/search/case.d.ts +0 -4
  209. package/api/search/case.js +0 -8
  210. package/api/socket/index.d.ts +0 -3
  211. package/api/socket/index.js +0 -6
  212. package/api/socket/viewers.d.ts +0 -2
  213. package/api/socket/viewers.js +0 -8
  214. package/api/socket/viewers.test.js +0 -44
  215. package/api/v2/case/index.d.ts +0 -9
  216. package/api/v2/case/index.js +0 -21
  217. package/api/v2/case/items.d.ts +0 -6
  218. package/api/v2/case/items.js +0 -18
  219. package/api/v2/case/rules.d.ts +0 -6
  220. package/api/v2/case/rules.js +0 -18
  221. package/api/v2/index.d.ts +0 -4
  222. package/api/v2/index.js +0 -6
  223. package/api/v2/search/facet.d.ts +0 -3
  224. package/api/v2/search/facet.js +0 -12
  225. package/api/v2/search/index.d.ts +0 -5
  226. package/api/v2/search/index.js +0 -24
  227. package/components/app/providers/RecordProvider.d.ts +0 -23
  228. package/components/elements/ContextMenu.d.ts +0 -56
  229. package/components/elements/ContextMenu.js +0 -109
  230. package/components/elements/ContextMenu.test.js +0 -215
  231. package/components/elements/ObjectDetails.d.ts +0 -6
  232. package/components/elements/case/CaseCard.d.ts +0 -12
  233. package/components/elements/case/CaseCard.js +0 -42
  234. package/components/elements/case/CasePreview.d.ts +0 -6
  235. package/components/elements/case/CasePreview.js +0 -17
  236. package/components/elements/case/StatusIcon.d.ts +0 -5
  237. package/components/elements/case/StatusIcon.js +0 -13
  238. package/components/elements/hit/elements/AnalyticLink.d.ts +0 -9
  239. package/components/elements/hit/elements/AnalyticLink.js +0 -22
  240. package/components/elements/hit/elements/Assigned.js +0 -34
  241. package/components/elements/hit/elements/Assigned.test.js +0 -65
  242. package/components/elements/hit/related/RelatedRecords.js +0 -63
  243. package/components/elements/observable/ObservableCard.d.ts +0 -6
  244. package/components/elements/observable/ObservableCard.js +0 -22
  245. package/components/elements/observable/ObservablePreview.d.ts +0 -6
  246. package/components/elements/observable/ObservablePreview.js +0 -12
  247. package/components/elements/record/RecordContextMenu.js +0 -268
  248. package/components/elements/record/RecordRelated.d.ts +0 -7
  249. package/components/elements/record/RecordRelated.js +0 -34
  250. package/components/hooks/useRelatedRecords.d.ts +0 -13
  251. package/components/hooks/useRelatedRecords.js +0 -32
  252. package/components/routes/cases/CaseViewer.d.ts +0 -2
  253. package/components/routes/cases/CaseViewer.js +0 -44
  254. package/components/routes/cases/CaseViewer.test.js +0 -133
  255. package/components/routes/cases/Cases.d.ts +0 -2
  256. package/components/routes/cases/Cases.js +0 -148
  257. package/components/routes/cases/constants.d.ts +0 -6
  258. package/components/routes/cases/constants.js +0 -6
  259. package/components/routes/cases/detail/AlertPanel.d.ts +0 -6
  260. package/components/routes/cases/detail/AlertPanel.js +0 -33
  261. package/components/routes/cases/detail/CaseAssets.d.ts +0 -11
  262. package/components/routes/cases/detail/CaseAssets.js +0 -104
  263. package/components/routes/cases/detail/CaseAssets.test.js +0 -167
  264. package/components/routes/cases/detail/CaseDashboard.d.ts +0 -7
  265. package/components/routes/cases/detail/CaseDashboard.js +0 -66
  266. package/components/routes/cases/detail/CaseDetails.d.ts +0 -6
  267. package/components/routes/cases/detail/CaseDetails.js +0 -70
  268. package/components/routes/cases/detail/CaseOverview.d.ts +0 -7
  269. package/components/routes/cases/detail/CaseOverview.js +0 -43
  270. package/components/routes/cases/detail/CaseRules.d.ts +0 -7
  271. package/components/routes/cases/detail/CaseRules.js +0 -57
  272. package/components/routes/cases/detail/CaseRules.test.js +0 -221
  273. package/components/routes/cases/detail/CaseSidebar.d.ts +0 -8
  274. package/components/routes/cases/detail/CaseSidebar.js +0 -107
  275. package/components/routes/cases/detail/CaseSidebar.test.js +0 -266
  276. package/components/routes/cases/detail/CaseTask.d.ts +0 -11
  277. package/components/routes/cases/detail/CaseTask.js +0 -66
  278. package/components/routes/cases/detail/CaseTimeline.d.ts +0 -12
  279. package/components/routes/cases/detail/CaseTimeline.js +0 -106
  280. package/components/routes/cases/detail/CaseTimeline.test.js +0 -320
  281. package/components/routes/cases/detail/CreateRuleDialog.d.ts +0 -9
  282. package/components/routes/cases/detail/CreateRuleDialog.js +0 -163
  283. package/components/routes/cases/detail/CreateRuleDialog.test.js +0 -259
  284. package/components/routes/cases/detail/ItemPage.d.ts +0 -6
  285. package/components/routes/cases/detail/ItemPage.js +0 -95
  286. package/components/routes/cases/detail/RelatedCasePanel.d.ts +0 -6
  287. package/components/routes/cases/detail/RelatedCasePanel.js +0 -34
  288. package/components/routes/cases/detail/TaskPanel.d.ts +0 -7
  289. package/components/routes/cases/detail/TaskPanel.js +0 -52
  290. package/components/routes/cases/detail/aggregates/CaseAggregate.d.ts +0 -11
  291. package/components/routes/cases/detail/aggregates/CaseAggregate.js +0 -24
  292. package/components/routes/cases/detail/aggregates/SourceAggregate.d.ts +0 -6
  293. package/components/routes/cases/detail/aggregates/SourceAggregate.js +0 -26
  294. package/components/routes/cases/detail/assets/Asset.d.ts +0 -14
  295. package/components/routes/cases/detail/assets/Asset.js +0 -12
  296. package/components/routes/cases/detail/assets/Asset.test.js +0 -72
  297. package/components/routes/cases/detail/sidebar/CaseFolder.d.ts +0 -20
  298. package/components/routes/cases/detail/sidebar/CaseFolder.js +0 -83
  299. package/components/routes/cases/detail/sidebar/CaseFolder.test.js +0 -295
  300. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.d.ts +0 -34
  301. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.js +0 -103
  302. package/components/routes/cases/detail/sidebar/CaseFolderContextMenu.test.js +0 -363
  303. package/components/routes/cases/detail/sidebar/FolderEntry.d.ts +0 -25
  304. package/components/routes/cases/detail/sidebar/FolderEntry.js +0 -88
  305. package/components/routes/cases/detail/sidebar/FolderEntry.test.js +0 -206
  306. package/components/routes/cases/detail/sidebar/RootDropZone.d.ts +0 -5
  307. package/components/routes/cases/detail/sidebar/RootDropZone.js +0 -33
  308. package/components/routes/cases/detail/sidebar/types.d.ts +0 -9
  309. package/components/routes/cases/detail/sidebar/utils.d.ts +0 -3
  310. package/components/routes/cases/detail/sidebar/utils.js +0 -29
  311. package/components/routes/cases/detail/sidebar/utils.test.js +0 -82
  312. package/components/routes/cases/hooks/useCase.d.ts +0 -13
  313. package/components/routes/cases/hooks/useCase.js +0 -69
  314. package/components/routes/cases/hooks/useCase.test.js +0 -141
  315. package/components/routes/cases/modals/AddToCaseModal.d.ts +0 -7
  316. package/components/routes/cases/modals/AddToCaseModal.js +0 -59
  317. package/components/routes/cases/modals/AddToCaseModal.test.js +0 -313
  318. package/components/routes/cases/modals/CaseRecordRow.d.ts +0 -9
  319. package/components/routes/cases/modals/CaseRecordRow.js +0 -15
  320. package/components/routes/cases/modals/CreateCaseModal.d.ts +0 -7
  321. package/components/routes/cases/modals/CreateCaseModal.js +0 -55
  322. package/components/routes/cases/modals/CreateCaseModal.test.js +0 -358
  323. package/components/routes/cases/modals/RenameItemModal.d.ts +0 -9
  324. package/components/routes/cases/modals/RenameItemModal.js +0 -48
  325. package/components/routes/cases/modals/ResolveModal.d.ts +0 -7
  326. package/components/routes/cases/modals/ResolveModal.js +0 -115
  327. package/components/routes/cases/modals/ResolveModal.test.js +0 -394
  328. package/components/routes/cases/modals/hooks.d.ts +0 -7
  329. package/components/routes/cases/modals/hooks.js +0 -44
  330. package/components/routes/cases/modals/types.d.ts +0 -5
  331. package/components/routes/cases/search/CaseAssigneeFilter.d.ts +0 -6
  332. package/components/routes/cases/search/CaseAssigneeFilter.js +0 -33
  333. package/components/routes/cases/search/CaseAssigneeFilter.test.js +0 -127
  334. package/components/routes/cases/search/CaseDateFilter.d.ts +0 -13
  335. package/components/routes/cases/search/CaseDateFilter.js +0 -26
  336. package/components/routes/cases/search/CaseDateFilter.test.js +0 -115
  337. package/components/routes/cases/search/CaseStatusFilter.d.ts +0 -6
  338. package/components/routes/cases/search/CaseStatusFilter.js +0 -13
  339. package/components/routes/cases/search/CaseStatusFilter.test.js +0 -86
  340. package/components/routes/hits/search/shared/IndexPicker.d.ts +0 -2
  341. package/components/routes/hits/search/shared/IndexPicker.js +0 -20
  342. package/components/routes/observables/ObservableViewer.d.ts +0 -7
  343. package/components/routes/observables/ObservableViewer.js +0 -27
  344. package/models/entities/generated/AttachmentsFile.d.ts +0 -12
  345. package/models/entities/generated/Case.d.ts +0 -28
  346. package/models/entities/generated/DestinationOriginal.d.ts +0 -19
  347. package/models/entities/generated/EmailAttachment.d.ts +0 -8
  348. package/models/entities/generated/EmailParent.d.ts +0 -19
  349. package/models/entities/generated/Enrichments.d.ts +0 -7
  350. package/models/entities/generated/EnrichmentsIndicator.d.ts +0 -21
  351. package/models/entities/generated/HttpResponse.d.ts +0 -11
  352. package/models/entities/generated/Item.d.ts +0 -9
  353. package/models/entities/generated/Observable.d.ts +0 -85
  354. package/models/entities/generated/ObservableCloud.d.ts +0 -20
  355. package/models/entities/generated/ObservableDestination.d.ts +0 -23
  356. package/models/entities/generated/ObservableEmail.d.ts +0 -30
  357. package/models/entities/generated/ObservableFile.d.ts +0 -36
  358. package/models/entities/generated/ObservableHowler.d.ts +0 -42
  359. package/models/entities/generated/ObservableHttp.d.ts +0 -11
  360. package/models/entities/generated/ObservableObserver.d.ts +0 -21
  361. package/models/entities/generated/ObservableOrganization.d.ts +0 -7
  362. package/models/entities/generated/ObservableProcess.d.ts +0 -34
  363. package/models/entities/generated/ObservableSource.d.ts +0 -23
  364. package/models/entities/generated/ObservableThreat.d.ts +0 -21
  365. package/models/entities/generated/ObservableTls.d.ts +0 -12
  366. package/models/entities/generated/ObserverIngress.d.ts +0 -9
  367. package/models/entities/generated/Task.d.ts +0 -10
  368. package/models/socket/CaseUpdate.d.ts +0 -5
  369. package/models/socket/ViewersUpdate.d.ts +0 -4
  370. package/utils/typeUtils.d.ts +0 -7
  371. package/utils/typeUtils.js +0 -27
  372. /package/{api/socket/viewers.test.d.ts → components/app/providers/HitSearchProvider.test.d.ts} +0 -0
  373. /package/components/{app/providers/RecordSearchProvider.test.d.ts → elements/addons/buttons/CustomButton.test.d.ts} +0 -0
  374. /package/components/elements/{ContextMenu.test.d.ts → addons/layout/FlexOne.test.d.ts} +0 -0
  375. /package/components/elements/{hit/elements/Assigned.test.d.ts → addons/search/SearchPagination.test.d.ts} +0 -0
  376. /package/components/elements/{record/RecordContextMenu.test.d.ts → addons/search/SearchTotal.test.d.ts} +0 -0
  377. /package/components/{routes/cases/CaseViewer.test.d.ts → elements/display/DocumentationButton.test.d.ts} +0 -0
  378. /package/components/{routes/cases/detail/CaseAssets.test.d.ts → elements/display/DynamicTabs.test.d.ts} +0 -0
  379. /package/components/{routes/cases/detail/CaseRules.test.d.ts → elements/display/HowlerCard.test.d.ts} +0 -0
  380. /package/components/{routes/cases/detail/CaseSidebar.test.d.ts → elements/display/Image.test.d.ts} +0 -0
  381. /package/components/{routes/cases/detail/CaseTimeline.test.d.ts → elements/display/QueryResultText.test.d.ts} +0 -0
  382. /package/components/{routes/cases/detail/CreateRuleDialog.test.d.ts → elements/display/TextDivider.test.d.ts} +0 -0
  383. /package/components/{routes/cases/detail/assets/Asset.test.d.ts → elements/display/TypingIndicator.test.d.ts} +0 -0
  384. /package/components/elements/hit/{related/RelatedRecords.d.ts → HitDetails.d.ts} +0 -0
  385. /package/components/routes/{cases/detail/sidebar/CaseFolder.test.d.ts → 403.test.d.ts} +0 -0
  386. /package/components/routes/{cases/detail/sidebar/CaseFolderContextMenu.test.d.ts → 404.test.d.ts} +0 -0
  387. /package/components/routes/{cases/detail/sidebar/FolderEntry.test.d.ts → ErrorBoundary.test.d.ts} +0 -0
  388. /package/components/routes/{cases/detail/sidebar/utils.test.d.ts → ErrorOccured.test.d.ts} +0 -0
  389. /package/components/routes/{cases/hooks/useCase.test.d.ts → Logout.test.d.ts} +0 -0
  390. /package/components/routes/hits/search/{RecordBrowser.d.ts → HitBrowser.d.ts} +0 -0
  391. /package/components/routes/{cases/modals/AddToCaseModal.test.d.ts → hits/search/HitContextMenu.test.d.ts} +0 -0
  392. /package/components/routes/{cases/modals/CreateCaseModal.test.d.ts → hits/search/shared/CustomSpan.test.d.ts} +0 -0
  393. /package/components/routes/{cases/modals/ResolveModal.test.d.ts → home/AddNewCard.test.d.ts} +0 -0
  394. /package/components/routes/{cases/search/CaseAssigneeFilter.test.d.ts → home/ViewRefresh.test.d.ts} +0 -0
  395. /package/components/routes/{cases/search/CaseDateFilter.test.d.ts → overviews/OverviewCard.test.d.ts} +0 -0
  396. /package/components/{elements/MarkdownEditor.d.ts → routes/overviews/OverviewEditor.d.ts} +0 -0
  397. /package/components/routes/{cases/search/CaseStatusFilter.test.d.ts → settings/SettingsSection.test.d.ts} +0 -0
@@ -48,18 +48,9 @@ interface SocketContextType {
48
48
  */
49
49
  reconnect: () => void;
50
50
  /**
51
- * Helper to tell if the socket is open
51
+ * Helper function to tell if the socket is open
52
52
  */
53
- open: boolean;
54
- /**
55
- * A map of entity IDs to their current viewers.
56
- */
57
- viewers: Record<string, string[]>;
58
- /**
59
- * Fetch the current viewers for an entity via REST, then keep in sync via socket.
60
- * @param entityId The entity ID to fetch viewers for
61
- */
62
- fetchViewers: (entityId: string) => Promise<void>;
53
+ isOpen: () => boolean;
63
54
  }
64
55
  export declare const SocketContext: import("react").Context<SocketContextType>;
65
56
  declare const SocketProvider: React.FC<PropsWithChildren>;
@@ -1,12 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /* eslint-disable no-console */
3
3
  import api from '@cccsaurora/howler-ui/api';
4
- import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
5
4
  import useMyLocalStorage from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
6
- import { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { createContext, useCallback, useEffect, useRef, useState } from 'react';
7
6
  import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
8
7
  import { getStored, setAxiosCache, setStored } from '@cccsaurora/howler-ui/utils/sessionStorage';
9
- import { isHitUpdate, isViewersUpdate } from '@cccsaurora/howler-ui/utils/socketUtils';
8
+ import { isHitUpdate } from '@cccsaurora/howler-ui/utils/socketUtils';
10
9
  /**
11
10
  * Enum to help track the status of the Websocket, since the corresponding websocket enums are directly on the object
12
11
  */
@@ -20,7 +19,6 @@ export var Status;
20
19
  export const SocketContext = createContext(null);
21
20
  const SocketProvider = ({ children }) => {
22
21
  const { get } = useMyLocalStorage();
23
- const { dispatchApi } = useMyApi();
24
22
  // In order to persist the connection through state changes, we use a ref
25
23
  const socket = useRef();
26
24
  // Due to react setState race conditions, listeners are also stored in a ref
@@ -33,8 +31,6 @@ const SocketProvider = ({ children }) => {
33
31
  const [retry, setRetry] = useState(true);
34
32
  // Track the number of failed attempts when connecting to the server
35
33
  const [failedAttempts, setFailedAttempts] = useState(0);
36
- // Track active viewers per entity ID
37
- const [viewers, setViewers] = useState({});
38
34
  const onClose = useCallback(e => {
39
35
  // https://www.rfc-editor.org/rfc/rfc6455:
40
36
  // 1006 is a reserved value and MUST NOT be set as a status code in a
@@ -187,7 +183,7 @@ const SocketProvider = ({ children }) => {
187
183
  const addListener = useCallback((key, callback) => {
188
184
  // If a listener with the same key already exists, remove it.
189
185
  if (listeners.current[key]) {
190
- socket.current?.removeEventListener('message', listeners.current[key]);
186
+ socket.current?.removeEventListener('message', listeners[key]);
191
187
  }
192
188
  // We wrap the callback so that all the listeners don't need to JSON.parse the data
193
189
  const wrapped = ev => {
@@ -204,9 +200,6 @@ const SocketProvider = ({ children }) => {
204
200
  api_status_code: parsedData.status
205
201
  });
206
202
  }
207
- if (isViewersUpdate(parsedData)) {
208
- setViewers(prev => ({ ...prev, [parsedData.id]: parsedData.viewers }));
209
- }
210
203
  callback(parsedData);
211
204
  };
212
205
  socket.current?.addEventListener('message', wrapped);
@@ -226,14 +219,8 @@ const SocketProvider = ({ children }) => {
226
219
  }
227
220
  socket.current?.send(data);
228
221
  }, [status]);
229
- const open = useMemo(() => status === Status.OPEN, [status]);
222
+ const isOpen = useCallback(() => status === Status.OPEN, [status]);
230
223
  const reconnect = useCallback(() => setRetry(true), []);
231
- const fetchViewers = useCallback(async (entityId) => {
232
- const result = await dispatchApi(api.socket.viewers.get(entityId), { throwError: false });
233
- if (result) {
234
- setViewers(prev => ({ ...prev, [entityId]: result }));
235
- }
236
- }, [dispatchApi]);
237
- return (_jsx(SocketContext.Provider, { value: { addListener, removeListener, emit, status, reconnect, open, viewers, fetchViewers }, children: children }));
224
+ return (_jsx(SocketContext.Provider, { value: { addListener, removeListener, emit, status, reconnect, isOpen }, children: children }));
238
225
  };
239
226
  export default SocketProvider;
@@ -1,15 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import api from '@cccsaurora/howler-ui/api';
3
3
  import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
4
- import { createContext, useCallback, useEffect, useRef, useState } from 'react';
4
+ import { createContext, useCallback, useState } from 'react';
5
5
  export const UserListContext = createContext(null);
6
6
  const UserListProvider = ({ children }) => {
7
7
  const { dispatchApi } = useMyApi();
8
8
  const [users, setUsers] = useState({});
9
- const usersRef = useRef(users);
10
- usersRef.current = users;
11
- const pendingIds = useRef(new Set());
12
- const debounceTimer = useRef(null);
13
9
  const searchUsers = useCallback(async (query) => {
14
10
  const newUsers = (await dispatchApi(api.search.user.post({ query, rows: 1000 }), {
15
11
  throwError: false,
@@ -21,30 +17,14 @@ const UserListProvider = ({ children }) => {
21
17
  ...newUsers
22
18
  }));
23
19
  }, [dispatchApi]);
24
- const fetchUsers = useCallback((ids) => {
25
- const nextIds = new Set(ids);
26
- nextIds.delete('Unknown');
27
- nextIds.forEach(id => pendingIds.current.add(id));
28
- if (debounceTimer.current) {
29
- clearTimeout(debounceTimer.current);
20
+ const fetchUsers = useCallback(async (ids) => {
21
+ ids.delete('Unknown');
22
+ const idsToGet = Array.from(ids.values()).filter(id => !Object.keys(users).includes(id));
23
+ if (idsToGet.length <= 0) {
24
+ return;
30
25
  }
31
- debounceTimer.current = setTimeout(async () => {
32
- const idsToGet = Array.from(pendingIds.current).filter(id => !Object.keys(usersRef.current).includes(id));
33
- pendingIds.current = new Set();
34
- debounceTimer.current = null;
35
- if (idsToGet.length <= 0) {
36
- return;
37
- }
38
- await searchUsers(`id:${idsToGet.join(' OR ')}`);
39
- }, 200);
40
- }, [searchUsers]);
41
- useEffect(() => {
42
- return () => {
43
- if (debounceTimer.current) {
44
- clearTimeout(debounceTimer.current);
45
- }
46
- };
47
- }, []);
26
+ await searchUsers(`id:${[...idsToGet].join(' OR ')}`);
27
+ }, [searchUsers, users]);
48
28
  return _jsx(UserListContext.Provider, { value: { users, fetchUsers, searchUsers }, children: children });
49
29
  };
50
30
  export default UserListProvider;
@@ -1,11 +1,10 @@
1
1
  import { type TypographyProps } from '@mui/material';
2
2
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
3
- import type { Observable } from '@cccsaurora/howler-ui/models/entities/generated/Observable';
4
3
  export type PluginTypographyProps = TypographyProps & {
5
4
  value: string;
6
5
  context: string;
7
6
  field?: string;
8
- obj?: Hit | Observable;
7
+ hit?: Hit;
9
8
  };
10
9
  declare const _default: import("react").NamedExoticComponent<PluginTypographyProps>;
11
10
  export default _default;
@@ -3,7 +3,7 @@ import { Typography } from '@mui/material';
3
3
  import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
4
4
  import { memo } from 'react';
5
5
  import { usePluginStore } from 'react-pluggable';
6
- const PluginTypography = ({ children, value, context, field, obj, ...props }) => {
6
+ const PluginTypography = ({ children, value, context, field, hit, ...props }) => {
7
7
  const pluginStore = usePluginStore();
8
8
  for (const plugin of howlerPluginStore.plugins) {
9
9
  const component = pluginStore.executeFunction(`${plugin}.typography`, {
@@ -11,8 +11,7 @@ const PluginTypography = ({ children, value, context, field, obj, ...props }) =>
11
11
  value,
12
12
  context,
13
13
  field,
14
- hit: obj,
15
- obj,
14
+ hit,
16
15
  ...props
17
16
  });
18
17
  if (component) {
@@ -2,11 +2,8 @@ import type { SxProps, Theme } from '@mui/material';
2
2
  import type { FC } from 'react';
3
3
  declare const UserList: FC<{
4
4
  buttonSx?: SxProps<Theme>;
5
- userIds: string[];
6
- onChange: (userIds: string[]) => void;
5
+ userId: string;
6
+ onChange: (userId: string) => void;
7
7
  i18nLabel: string;
8
- avatarHeight?: number;
9
- disabled?: boolean;
10
- multiple?: boolean;
11
8
  }>;
12
9
  export default UserList;
@@ -1,21 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Add } from '@mui/icons-material';
3
- import { Autocomplete, AvatarGroup, Box, IconButton, Popover, Stack, TextField, Typography } from '@mui/material';
2
+ import { Autocomplete, Box, IconButton, Popover, TextField, Typography } from '@mui/material';
4
3
  import { UserListContext } from '@cccsaurora/howler-ui/components/app/providers/UserListProvider';
5
- import { uniq } from 'lodash-es';
6
4
  import { useContext, useEffect, useMemo, useState } from 'react';
7
5
  import { useTranslation } from 'react-i18next';
8
6
  import HowlerAvatar from './display/HowlerAvatar';
9
- const UserList = ({ buttonSx = {}, userIds, onChange, i18nLabel, avatarHeight = 32, multiple = false, disabled = false }) => {
7
+ const UserList = ({ buttonSx = {}, userId, onChange, i18nLabel }) => {
10
8
  const { t } = useTranslation();
11
9
  const [anchorEl, setAnchorEl] = useState(null);
12
- const { users, fetchUsers } = useContext(UserListContext);
13
- const allUserIds = useMemo(() => Object.keys(users), [users]);
10
+ const { users, searchUsers } = useContext(UserListContext);
11
+ const userIds = useMemo(() => Object.keys(users), [users]);
14
12
  useEffect(() => {
15
- fetchUsers(new Set(userIds));
16
- // eslint-disable-next-line react-hooks/exhaustive-deps
17
- }, [userIds]);
18
- return (_jsxs(_Fragment, { children: [multiple ? (_jsxs(Stack, { direction: "row", spacing: 0.25, alignItems: "center", children: [_jsx(AvatarGroup, { children: uniq(userIds ?? [null]).map(userId => (_jsx(HowlerAvatar, { userId: userId, sx: { height: avatarHeight, width: avatarHeight } }, userId))) }), _jsx(IconButton, { size: "small", sx: buttonSx, disabled: disabled, onClick: e => setAnchorEl(e.currentTarget), children: _jsx(Add, {}) })] })) : (_jsx(IconButton, { sx: buttonSx, disabled: disabled, onClick: e => setAnchorEl(e.currentTarget), children: _jsx(HowlerAvatar, { userId: userIds[0], sx: { height: avatarHeight, width: avatarHeight } }) })), _jsx(Popover, { open: !!anchorEl, onClose: () => setAnchorEl(null), anchorEl: anchorEl, anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, children: _jsx(Box, { sx: { p: 2 }, children: _jsx(Autocomplete, { disabled: disabled, multiple: multiple, sx: { minWidth: '300px' }, options: allUserIds, renderInput: params => _jsx(TextField, { ...params, label: t(i18nLabel), size: "small" }), renderOption: (props, _userId) => {
13
+ searchUsers('uname:*');
14
+ }, [searchUsers]);
15
+ return (_jsxs(_Fragment, { children: [_jsx(IconButton, { sx: buttonSx, onClick: e => setAnchorEl(e.currentTarget), children: _jsx(HowlerAvatar, { userId: userId }) }), _jsx(Popover, { open: !!anchorEl, onClose: () => setAnchorEl(null), anchorEl: anchorEl, anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, children: _jsx(Box, { sx: { p: 2 }, children: _jsx(Autocomplete, { sx: { minWidth: '300px' }, options: userIds, renderInput: params => _jsx(TextField, { ...params, label: t(i18nLabel), size: "small" }), renderOption: (props, _userId) => {
19
16
  const user = users[_userId];
20
17
  return (_jsx("li", { ...props, children: _jsxs(Box, { sx: {
21
18
  display: 'grid',
@@ -24,13 +21,6 @@ const UserList = ({ buttonSx = {}, userIds, onChange, i18nLabel, avatarHeight =
24
21
  gridTemplateAreas: `"profile name"\n"profile email"`,
25
22
  columnGap: 1.5
26
23
  }, children: [_jsx(HowlerAvatar, { sx: { gridArea: 'profile', alignSelf: 'center', height: '32px', width: '32px' }, userId: user.username }), _jsx(Typography, { sx: { gridArea: 'name' }, variant: "body1", children: user.name }), _jsx(Typography, { sx: { gridArea: 'email' }, variant: "caption", children: user.email })] }) }));
27
- }, value: userIds, onChange: (__, options) => {
28
- if (multiple) {
29
- onChange(Array.isArray(options) ? options : [options]);
30
- }
31
- else {
32
- onChange([Array.isArray(options) ? (options[0] ?? null) : options]);
33
- }
34
- } }) }) })] }));
24
+ }, value: userId, onChange: (__, option) => onChange(option) }) }) })] }));
35
25
  };
36
26
  export default UserList;
@@ -0,0 +1,106 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import { setupReactRouterMock } from '@cccsaurora/howler-ui/tests/mocks';
5
+ import { vi } from 'vitest';
6
+ setupReactRouterMock();
7
+ import CustomButton from './CustomButton';
8
+ describe('CustomButton', () => {
9
+ afterAll(() => vi.resetModules());
10
+ describe('rendering', () => {
11
+ it('renders a button element', () => {
12
+ render(_jsx(CustomButton, { children: "Click me" }));
13
+ expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
14
+ });
15
+ it('renders with MUI Button classes', () => {
16
+ render(_jsx(CustomButton, { children: "Test" }));
17
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-root');
18
+ });
19
+ it('renders children text', () => {
20
+ render(_jsx(CustomButton, { children: "My Button" }));
21
+ expect(screen.getByText('My Button')).toBeInTheDocument();
22
+ });
23
+ });
24
+ describe('variants', () => {
25
+ it('renders contained variant', () => {
26
+ render(_jsx(CustomButton, { variant: "contained", children: "Contained" }));
27
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-contained');
28
+ });
29
+ it('renders outlined variant', () => {
30
+ render(_jsx(CustomButton, { variant: "outlined", children: "Outlined" }));
31
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-outlined');
32
+ });
33
+ it('renders text variant', () => {
34
+ render(_jsx(CustomButton, { variant: "text", children: "Text" }));
35
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-text');
36
+ });
37
+ });
38
+ describe('MUI color prop', () => {
39
+ it('renders with primary color by default', () => {
40
+ render(_jsx(CustomButton, { children: "Primary" }));
41
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-colorPrimary');
42
+ });
43
+ it('renders with secondary color', () => {
44
+ render(_jsx(CustomButton, { color: "secondary", children: "Secondary" }));
45
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-colorSecondary');
46
+ });
47
+ it('renders with error color', () => {
48
+ render(_jsx(CustomButton, { color: "error", children: "Error" }));
49
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-colorError');
50
+ });
51
+ it('renders with inherit color for custom hex colors', () => {
52
+ render(_jsx(CustomButton, { color: "#ff0000", children: "Custom" }));
53
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-colorInherit');
54
+ });
55
+ });
56
+ describe('progress', () => {
57
+ it('shows a progress indicator when progress is true', () => {
58
+ render(_jsx(CustomButton, { progress: true, children: "Loading" }));
59
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
60
+ });
61
+ it('does not show a progress indicator when progress is false', () => {
62
+ render(_jsx(CustomButton, { progress: false, children: "Not Loading" }));
63
+ expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
64
+ });
65
+ });
66
+ describe('tooltip', () => {
67
+ it('wraps button in a tooltip when tooltip prop is provided', () => {
68
+ render(_jsx(CustomButton, { tooltip: "Help text", children: "Hover me" }));
69
+ // Tooltip wraps in a span
70
+ const button = screen.getByRole('button');
71
+ expect(button.closest('span')).toBeInTheDocument();
72
+ });
73
+ });
74
+ describe('routing', () => {
75
+ it('wraps button in a Link when route prop is provided', () => {
76
+ render(_jsx(CustomButton, { route: "/test-route", children: "Navigate" }));
77
+ const link = screen.getByRole('link');
78
+ expect(link).toHaveAttribute('href', '/test-route');
79
+ });
80
+ it('wraps button in an anchor tag when href prop is provided', () => {
81
+ render(_jsx(CustomButton, { href: "https://example.com", children: "External" }));
82
+ const link = screen.getByRole('link');
83
+ expect(link).toHaveAttribute('href', 'https://example.com');
84
+ });
85
+ it('does not wrap button in link when neither route nor href is provided', () => {
86
+ render(_jsx(CustomButton, { children: "Plain" }));
87
+ expect(screen.queryByRole('link')).not.toBeInTheDocument();
88
+ });
89
+ });
90
+ describe('disabled state', () => {
91
+ it('renders disabled button when disabled prop is true', () => {
92
+ render(_jsx(CustomButton, { disabled: true, children: "Disabled" }));
93
+ expect(screen.getByRole('button')).toBeDisabled();
94
+ });
95
+ });
96
+ describe('sizes', () => {
97
+ it('renders small size', () => {
98
+ render(_jsx(CustomButton, { size: "small", children: "Small" }));
99
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-sizeSmall');
100
+ });
101
+ it('renders large size', () => {
102
+ render(_jsx(CustomButton, { size: "large", children: "Large" }));
103
+ expect(screen.getByRole('button')).toHaveClass('MuiButton-sizeLarge');
104
+ });
105
+ });
106
+ });
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import FlexOne from './FlexOne';
5
+ describe('FlexOne', () => {
6
+ describe('rendering', () => {
7
+ it('renders a div element', () => {
8
+ const { container } = render(_jsx(FlexOne, {}));
9
+ expect(container.querySelector('div')).toBeInTheDocument();
10
+ });
11
+ it('applies flex: 1 style', () => {
12
+ const { container } = render(_jsx(FlexOne, {}));
13
+ expect(container.firstChild).toHaveStyle({ flex: '1' });
14
+ });
15
+ it('renders children inside the div', () => {
16
+ render(_jsx(FlexOne, { children: _jsx("span", { id: "inner", children: "hello" }) }));
17
+ expect(screen.getByTestId('inner')).toBeInTheDocument();
18
+ });
19
+ it('renders without children without error', () => {
20
+ const { container } = render(_jsx(FlexOne, {}));
21
+ expect(container.firstChild).toBeInTheDocument();
22
+ expect(container.firstChild).toBeEmptyDOMElement();
23
+ });
24
+ it('renders multiple children', () => {
25
+ render(_jsxs(FlexOne, { children: [_jsx("span", { id: "a", children: "A" }), _jsx("span", { id: "b", children: "B" })] }));
26
+ expect(screen.getByTestId('a')).toBeInTheDocument();
27
+ expect(screen.getByTestId('b')).toBeInTheDocument();
28
+ });
29
+ });
30
+ });
@@ -30,6 +30,10 @@ const TuiListBaseRoot = styled('div')(({ theme }) => ({
30
30
  display: 'flex',
31
31
  backgroundColor: emphasize(theme.palette.background.default, 0.04)
32
32
  }
33
+ },
34
+ '.elementDisabled': {
35
+ color: theme.palette.text.disabled,
36
+ cursor: 'default'
33
37
  }
34
38
  }));
35
39
  const TuiListBase = ({ keyboard = false, onSelect, children }) => {
@@ -5,11 +5,14 @@ import VSBoxElement from '../layout/vsbox/VSBoxElement';
5
5
  const TuiListElement = ({ position, item, onSelect: onClick, children }) => {
6
6
  const elementEl = useRef();
7
7
  const onItemClick = useCallback(_event => {
8
- if (onClick) {
8
+ if (onClick && !item.disabled) {
9
9
  onClick(item, position);
10
10
  }
11
11
  }, [onClick, item, position]);
12
12
  const classRenderer = useCallback(() => {
13
+ if (item.disabled) {
14
+ return 'elementDisabled';
15
+ }
13
16
  const _classes = ['elementHover'];
14
17
  if (item.cursor) {
15
18
  _classes.push('elementFocus');
@@ -18,7 +21,7 @@ const TuiListElement = ({ position, item, onSelect: onClick, children }) => {
18
21
  _classes.push('elementSelected');
19
22
  }
20
23
  return _classes.join(' ');
21
- }, [item.cursor, item.selected]);
22
- return (_jsx(VSBoxElement, { focus: !!item.cursor, children: _jsx("div", { ref: elementEl, "data-tuilist-index": position, "data-tuilist-id": item.id, "data-tuilist-focus": !!item.cursor, "data-tuilist-selected": !!item.selected, onClick: onItemClick, children: children({ item, position }, classRenderer) }) }));
24
+ }, [item.cursor, item.selected, item.disabled]);
25
+ return (_jsx(VSBoxElement, { focus: !!item.cursor, children: _jsx("div", { ref: elementEl, "data-tuilist-index": position, "data-tuilist-id": item.id, "data-tuilist-focus": !!item.cursor, "data-tuilist-selected": !!item.selected, "aria-disabled": item.disabled, onClick: onItemClick, children: children({ item, position }, classRenderer) }) }));
23
26
  };
24
27
  export default memo(TuiListElement);
@@ -8,6 +8,7 @@ export type TuiListItem<T> = {
8
8
  details?: boolean;
9
9
  cursor?: boolean;
10
10
  selected?: boolean;
11
+ disabled?: boolean;
11
12
  item: T;
12
13
  };
13
14
  export type TuiListItemProps<T> = {
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import userEvent from '@testing-library/user-event';
5
+ import SearchPagination from './SearchPagination';
6
+ describe('SearchPagination', () => {
7
+ const defaultProps = {
8
+ limit: 25,
9
+ offset: 0,
10
+ total: 100,
11
+ onChange: vi.fn()
12
+ };
13
+ beforeEach(() => {
14
+ vi.clearAllMocks();
15
+ });
16
+ describe('rendering', () => {
17
+ it('renders pagination when total exceeds limit', () => {
18
+ render(_jsx(SearchPagination, { ...defaultProps }));
19
+ expect(screen.getByRole('navigation')).toBeInTheDocument();
20
+ });
21
+ it('does not render when total is less than limit', () => {
22
+ const { container } = render(_jsx(SearchPagination, { ...defaultProps, total: 20 }));
23
+ expect(container).toBeEmptyDOMElement();
24
+ });
25
+ it('does not render when total equals limit', () => {
26
+ const { container } = render(_jsx(SearchPagination, { ...defaultProps, total: 25 }));
27
+ expect(container).toBeEmptyDOMElement();
28
+ });
29
+ it('calculates correct page count', () => {
30
+ render(_jsx(SearchPagination, { ...defaultProps, total: 100, limit: 25 }));
31
+ // 100/25 = 4 pages
32
+ // MUI Pagination renders prev, page buttons, next
33
+ expect(screen.getByText('4')).toBeInTheDocument();
34
+ });
35
+ it('calculates correct page count with non-even division', () => {
36
+ render(_jsx(SearchPagination, { ...defaultProps, total: 101, limit: 25 }));
37
+ // ceil(101/25) = 5 pages
38
+ expect(screen.getByText('5')).toBeInTheDocument();
39
+ });
40
+ it('highlights the current page based on offset', () => {
41
+ render(_jsx(SearchPagination, { ...defaultProps, offset: 50 }));
42
+ // offset 50 with limit 25 = page 3
43
+ const page3 = screen.getByText('3');
44
+ expect(page3.closest('button')).toHaveAttribute('aria-current', 'true');
45
+ });
46
+ });
47
+ describe('interaction', () => {
48
+ it('calls onChange with correct offset when clicking page 2', async () => {
49
+ const user = userEvent.setup();
50
+ const onChange = vi.fn();
51
+ render(_jsx(SearchPagination, { ...defaultProps, onChange: onChange }));
52
+ await user.click(screen.getByText('2'));
53
+ expect(onChange).toHaveBeenCalledWith(25);
54
+ });
55
+ it('calls onChange with correct offset when clicking page 3', async () => {
56
+ const user = userEvent.setup();
57
+ const onChange = vi.fn();
58
+ render(_jsx(SearchPagination, { ...defaultProps, onChange: onChange }));
59
+ await user.click(screen.getByText('3'));
60
+ expect(onChange).toHaveBeenCalledWith(50);
61
+ });
62
+ it('calls onChange with 0 when clicking page 1', async () => {
63
+ const user = userEvent.setup();
64
+ const onChange = vi.fn();
65
+ render(_jsx(SearchPagination, { ...defaultProps, offset: 25, onChange: onChange }));
66
+ await user.click(screen.getByText('1'));
67
+ expect(onChange).toHaveBeenCalledWith(0);
68
+ });
69
+ });
70
+ describe('edge cases', () => {
71
+ it('does not render when limit is 0', () => {
72
+ const { container } = render(_jsx(SearchPagination, { ...defaultProps, limit: 0 }));
73
+ expect(container).toBeEmptyDOMElement();
74
+ });
75
+ it('does not render when total is 0', () => {
76
+ const { container } = render(_jsx(SearchPagination, { ...defaultProps, total: 0 }));
77
+ expect(container).toBeEmptyDOMElement();
78
+ });
79
+ });
80
+ });
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /// <reference types="vitest" />
3
+ import { render, screen } from '@testing-library/react';
4
+ import i18n from '@cccsaurora/howler-ui/i18n';
5
+ import { I18nextProvider } from 'react-i18next';
6
+ import SearchTotal from './SearchTotal';
7
+ const Wrapper = ({ children }) => (_jsx(I18nextProvider, { i18n: i18n, children: children }));
8
+ describe('SearchTotal', () => {
9
+ describe('rendering', () => {
10
+ it('renders a Typography element', () => {
11
+ const { container } = render(_jsx(SearchTotal, { total: 10, offset: 0, pageLength: 10 }), { wrapper: Wrapper });
12
+ expect(container.querySelector('.MuiTypography-root')).toBeInTheDocument();
13
+ });
14
+ it('renders "No results" text when total is 0', () => {
15
+ render(_jsx(SearchTotal, { total: 0, offset: 0, pageLength: 0 }), { wrapper: Wrapper });
16
+ expect(screen.getByText('No results')).toBeInTheDocument();
17
+ });
18
+ it('renders "No results" text when total is 1', () => {
19
+ render(_jsx(SearchTotal, { total: 1, offset: 0, pageLength: 1 }), { wrapper: Wrapper });
20
+ expect(screen.getByText('No results')).toBeInTheDocument();
21
+ });
22
+ it('renders range text when total is greater than 1', () => {
23
+ render(_jsx(SearchTotal, { total: 50, offset: 0, pageLength: 25 }), { wrapper: Wrapper });
24
+ // "Showing 1 to 25 of 50 results"
25
+ expect(screen.getByText(/Showing 1 to 25 of 50 results/)).toBeInTheDocument();
26
+ });
27
+ it('renders correct offset values', () => {
28
+ render(_jsx(SearchTotal, { total: 100, offset: 25, pageLength: 25 }), { wrapper: Wrapper });
29
+ // Should show "Showing 26 to 50 of 100 results"
30
+ expect(screen.getByText(/Showing 26 to 50 of 100 results/)).toBeInTheDocument();
31
+ });
32
+ });
33
+ describe('prop passthrough', () => {
34
+ it('passes className to Typography', () => {
35
+ const { container } = render(_jsx(SearchTotal, { total: 10, offset: 0, pageLength: 10, className: "custom" }), {
36
+ wrapper: Wrapper
37
+ });
38
+ expect(container.firstChild).toHaveClass('custom');
39
+ });
40
+ it('passes variant to Typography', () => {
41
+ const { container } = render(_jsx(SearchTotal, { total: 10, offset: 0, pageLength: 10, variant: "caption" }), { wrapper: Wrapper });
42
+ expect(container.firstChild).toHaveClass('MuiTypography-caption');
43
+ });
44
+ });
45
+ });
@@ -80,7 +80,7 @@ const Phrase = ({ value = '', variant = 'outlined', suggestions = [], lexer, sug
80
80
  onSelectCapture: _onSelectCapture,
81
81
  startAdornment: startAdornment && _jsx(InputAdornment, { position: "start", children: startAdornment }),
82
82
  endAdornment: endAdornment && _jsx(InputAdornment, { position: "end", children: endAdornment })
83
- } }), _jsx(Popper, { anchorEl: containerRef.current, style: { width: '100%', zIndex: 100 }, open: optionsOpen && (options.length > 0 || (debug && analysisRef.current?.tokens.length > 0)), disablePortal: true, children: _jsx(Paper, { elevation: 1, sx: { maxHeight: 200, overflow: 'auto', borderTopRightRadius: 0, borderTopLeftRadius: 0 }, children: _jsx(MenuList, { ref: menuRef, onKeyDown: _onMenuKeyDown, sx: {
83
+ } }), _jsx(Popper, { anchorEl: containerRef.current, style: { width: '100%', zIndex: 100 }, open: optionsOpen && (options.length > 0 || (debug && analysisRef.current?.tokens.length > 0)), disablePortal: true, children: _jsx(Paper, { elevation: 2, sx: { maxHeight: 200, overflow: 'auto', borderTopRightRadius: 0, borderTopLeftRadius: 0 }, children: _jsx(MenuList, { ref: menuRef, onKeyDown: _onMenuKeyDown, sx: {
84
84
  '&:focus': {
85
85
  outline: 'none'
86
86
  }
@@ -15,8 +15,8 @@ interface ChipPopperProps {
15
15
  onToggle?: (show: boolean) => void;
16
16
  onDelete?: (event?: any) => void;
17
17
  toggleOnDelete?: boolean;
18
- disablePortal?: boolean;
19
18
  closeOnClick?: boolean;
19
+ disablePortal?: boolean;
20
20
  }
21
21
  declare const _default: import("react").NamedExoticComponent<ChipPopperProps>;
22
22
  export default _default;
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Chip, ClickAwayListener, Collapse, Paper, Popper } from '@mui/material';
3
- import { memo, useState } from 'react';
3
+ import { memo, useRef, useState } from 'react';
4
4
  const ChipPopper = ({ icon, deleteIcon, label, children, minWidth, placement = 'bottom-start', onToggle, onDelete, toggleOnDelete = false, closeOnClick = false, disablePortal = true, slotProps = {} }) => {
5
5
  const [show, setShow] = useState(false);
6
- const [anchorEl, setAnchorEl] = useState(null);
6
+ const anchorEl = useRef(null);
7
7
  const handleToggle = (newShow) => {
8
8
  setShow(newShow);
9
9
  onToggle?.(newShow);
@@ -11,7 +11,7 @@ const ChipPopper = ({ icon, deleteIcon, label, children, minWidth, placement = '
11
11
  return (_jsxs(_Fragment, { children: [_jsx(Chip, { icon: icon, deleteIcon: deleteIcon, label: label, onClick: e => {
12
12
  handleToggle(!show);
13
13
  e.stopPropagation();
14
- }, onDelete: onDelete ?? (toggleOnDelete ? () => handleToggle(!show) : null), ref: setAnchorEl, sx: [
14
+ }, onDelete: onDelete ?? (toggleOnDelete ? () => handleToggle(!show) : null), ref: anchorEl, sx: [
15
15
  theme => ({
16
16
  position: 'relative',
17
17
  zIndex: 1,
@@ -19,8 +19,8 @@ const ChipPopper = ({ icon, deleteIcon, label, children, minWidth, placement = '
19
19
  }),
20
20
  show && { borderBottomLeftRadius: '0', borderBottomRightRadius: '0' },
21
21
  ...(Array.isArray(slotProps.chip?.sx) ? slotProps.chip.sx : [slotProps.chip?.sx])
22
- ], ...(slotProps.chip ?? {}) }), _jsx(Popper, { placement: placement, anchorEl: anchorEl, disablePortal: disablePortal, open: !!anchorEl, sx: {
23
- minWidth: Math.max(typeof minWidth === 'number' ? minWidth : parseInt(minWidth?.replace('px', '')) || 0, anchorEl?.clientWidth || 0),
22
+ ], ...(slotProps.chip ?? {}) }), _jsx(Popper, { placement: placement, anchorEl: anchorEl.current, disablePortal: disablePortal, open: true, sx: {
23
+ minWidth: Math.max(typeof minWidth === 'number' ? minWidth : parseInt(minWidth?.replace('px', '')) || 0, anchorEl.current?.clientWidth || 0),
24
24
  zIndex: 1000
25
25
  }, children: _jsx(Collapse, { in: show, unmountOnExit: true, onClick: () => {
26
26
  if (closeOnClick) {