@allurereport/web-awesome 3.8.2 → 3.9.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 (206) hide show
  1. package/README.md +112 -0
  2. package/allurerc-dev.mjs +10 -0
  3. package/dist/multi/121.app-d36b0855e3e7a53eeee9.js +1 -0
  4. package/dist/multi/173.app-d36b0855e3e7a53eeee9.js +1 -0
  5. package/dist/multi/174.app-d36b0855e3e7a53eeee9.js +1 -0
  6. package/dist/multi/252.app-d36b0855e3e7a53eeee9.js +1 -0
  7. package/dist/multi/282.app-d36b0855e3e7a53eeee9.js +1 -0
  8. package/dist/multi/29.app-d36b0855e3e7a53eeee9.js +1 -0
  9. package/dist/multi/310.app-d36b0855e3e7a53eeee9.js +1 -0
  10. package/dist/multi/{416.app-f008fb8342025f2b1ace.js → 416.app-d36b0855e3e7a53eeee9.js} +1 -1
  11. package/dist/multi/{507.app-f008fb8342025f2b1ace.js → 507.app-d36b0855e3e7a53eeee9.js} +1 -1
  12. package/dist/multi/527.app-d36b0855e3e7a53eeee9.js +1 -0
  13. package/dist/multi/600.app-d36b0855e3e7a53eeee9.js +1 -0
  14. package/dist/multi/605.app-d36b0855e3e7a53eeee9.js +1 -0
  15. package/dist/multi/638.app-d36b0855e3e7a53eeee9.js +1 -0
  16. package/dist/multi/672.app-d36b0855e3e7a53eeee9.js +1 -0
  17. package/dist/multi/686.app-d36b0855e3e7a53eeee9.js +1 -0
  18. package/dist/multi/725.app-d36b0855e3e7a53eeee9.js +1 -0
  19. package/dist/multi/741.app-d36b0855e3e7a53eeee9.js +1 -0
  20. package/dist/multi/749.app-d36b0855e3e7a53eeee9.js +1 -0
  21. package/dist/multi/755.app-d36b0855e3e7a53eeee9.js +1 -0
  22. package/dist/multi/779.app-d36b0855e3e7a53eeee9.js +1 -0
  23. package/dist/multi/{894.app-f008fb8342025f2b1ace.js → 894.app-d36b0855e3e7a53eeee9.js} +1 -1
  24. package/dist/multi/943.app-d36b0855e3e7a53eeee9.js +1 -0
  25. package/dist/multi/980.app-d36b0855e3e7a53eeee9.js +1 -0
  26. package/dist/multi/app-d36b0855e3e7a53eeee9.js +2 -0
  27. package/dist/multi/manifest.json +26 -23
  28. package/dist/multi/styles-212da6c68fa0beb4c6c5.css +1 -0
  29. package/dist/multi/styles-468416ffee9a9dea6cae.css +58 -0
  30. package/dist/multi/styles-5c882b14b6f3112e40c4.css +1 -0
  31. package/dist/single/app-62171f5f51b5954a787c.js +2 -0
  32. package/dist/single/manifest.json +1 -1
  33. package/package.json +12 -7
  34. package/src/assets/scss/_common.scss +2 -2
  35. package/src/assets/scss/index.scss +8 -6
  36. package/src/components/BaseLayout/index.tsx +14 -2
  37. package/src/components/BaseLayout/styles.scss +5 -5
  38. package/src/components/Categories/CategoryHeaderItem/styles.scss +2 -2
  39. package/src/components/Categories/CategoryTreeItem/styles.scss +2 -2
  40. package/src/components/Categories/GroupTreeItem/styles.scss +4 -5
  41. package/src/components/Categories/HistoryTreeItem/styles.scss +2 -2
  42. package/src/components/Categories/LabelTreeItem/styles.scss +2 -2
  43. package/src/components/Categories/MessageTreeItem/index.tsx +1 -1
  44. package/src/components/Categories/MessageTreeItem/styles.scss +18 -18
  45. package/src/components/Categories/sticky.ts +1 -1
  46. package/src/components/Footer/styles.scss +2 -2
  47. package/src/components/Header/CiInfo/styles.scss +1 -1
  48. package/src/components/Header/styles.scss +2 -2
  49. package/src/components/HotkeysProvider/index.tsx +556 -0
  50. package/src/components/KeyboardShortcuts/index.tsx +73 -0
  51. package/src/components/KeyboardShortcuts/shortcutsConfig.ts +91 -0
  52. package/src/components/KeyboardShortcuts/styles.scss +69 -0
  53. package/src/components/MainReport/index.tsx +89 -72
  54. package/src/components/MainReport/styles.scss +40 -4
  55. package/src/components/Metadata/styles.scss +9 -9
  56. package/src/components/MetadataButton/index.tsx +2 -0
  57. package/src/components/MetadataButton/styles.scss +1 -1
  58. package/src/components/NavTabs/styles.scss +8 -8
  59. package/src/components/ReportBody/index.tsx +11 -2
  60. package/src/components/ReportBody/styles.scss +24 -4
  61. package/src/components/ReportCategories/styles.scss +1 -1
  62. package/src/components/ReportFilters/styles.scss +1 -1
  63. package/src/components/ReportGlobalAttachments/styles.scss +1 -1
  64. package/src/components/ReportGlobalErrors/styles.scss +1 -1
  65. package/src/components/ReportHeader/styles.scss +2 -2
  66. package/src/components/ReportMetadata/index.tsx +9 -11
  67. package/src/components/ReportMetadata/styles.scss +6 -6
  68. package/src/components/ReportQualityGateResults/styles.scss +2 -2
  69. package/src/components/ReportSearch/index.tsx +1 -5
  70. package/src/components/ReportTabs/styles.scss +9 -9
  71. package/src/components/SectionSwitcher/index.tsx +87 -10
  72. package/src/components/SideBySide/index.tsx +20 -2
  73. package/src/components/SideBySide/styles.scss +9 -1
  74. package/src/components/SplitLayout/index.tsx +10 -1
  75. package/src/components/SplitLayout/styles.scss +20 -4
  76. package/src/components/TestResult/TestStepsEmpty/styles.scss +1 -1
  77. package/src/components/TestResult/TrDescription/styles.scss +1 -1
  78. package/src/components/TestResult/TrDropdown/index.tsx +2 -2
  79. package/src/components/TestResult/TrDropdown/styles.scss +1 -1
  80. package/src/components/TestResult/TrEmpty/styles.scss +1 -1
  81. package/src/components/TestResult/TrEnvironmentItem/styles.scss +4 -4
  82. package/src/components/TestResult/TrError/index.tsx +32 -7
  83. package/src/components/TestResult/TrError/styles.scss +23 -23
  84. package/src/components/TestResult/TrHeader/styles.scss +2 -2
  85. package/src/components/TestResult/TrHistory/styles.scss +6 -6
  86. package/src/components/TestResult/TrInfo/styles.scss +8 -8
  87. package/src/components/TestResult/TrLinks/index.tsx +2 -2
  88. package/src/components/TestResult/TrLinks/styles.scss +2 -2
  89. package/src/components/TestResult/TrMetadata/index.tsx +1 -1
  90. package/src/components/TestResult/TrMetadata/styles.scss +1 -1
  91. package/src/components/TestResult/TrNavigation/index.tsx +1 -1
  92. package/src/components/TestResult/TrNavigation/styles.scss +2 -2
  93. package/src/components/TestResult/TrOverview.tsx +2 -0
  94. package/src/components/TestResult/TrParameters/index.tsx +1 -1
  95. package/src/components/TestResult/TrParameters/styles.scss +1 -1
  96. package/src/components/TestResult/TrPrevStatuses/styles.scss +8 -8
  97. package/src/components/TestResult/TrPwTraces/styles.scss +1 -1
  98. package/src/components/TestResult/TrRetriesView/styles.scss +3 -3
  99. package/src/components/TestResult/TrSetup/index.tsx +9 -3
  100. package/src/components/TestResult/TrSeverity/styles.scss +7 -7
  101. package/src/components/TestResult/TrStatus/styles.scss +2 -35
  102. package/src/components/TestResult/TrSteps/TrAttachment.tsx +79 -43
  103. package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +44 -17
  104. package/src/components/TestResult/TrSteps/TrErrorStep.tsx +3 -0
  105. package/src/components/TestResult/TrSteps/TrStep.tsx +9 -4
  106. package/src/components/TestResult/TrSteps/TrStepHeader.tsx +8 -5
  107. package/src/components/TestResult/TrSteps/index.tsx +7 -4
  108. package/src/components/TestResult/TrSteps/stepTreeExpansion.ts +27 -9
  109. package/src/components/TestResult/TrSteps/styles.scss +80 -20
  110. package/src/components/TestResult/TrTeardown/index.tsx +9 -3
  111. package/src/components/TestResult/bodyItems.ts +1 -1
  112. package/src/components/TestResult/index.tsx +8 -2
  113. package/src/components/TestResult/styles.scss +10 -1
  114. package/src/components/TestResult/trOverviewFocus.scss +4 -0
  115. package/src/components/Timeline/styles.scss +6 -6
  116. package/src/components/Tree/index.tsx +54 -5
  117. package/src/components/Tree/styles.scss +55 -35
  118. package/src/hooks/useTestResultOverviewFocusScroll.ts +23 -0
  119. package/src/index.html +30 -33
  120. package/src/index.tsx +12 -6
  121. package/src/locales/ar.json +61 -1
  122. package/src/locales/az.json +61 -1
  123. package/src/locales/de.json +61 -1
  124. package/src/locales/en.json +61 -1
  125. package/src/locales/es.json +61 -1
  126. package/src/locales/fr.json +61 -1
  127. package/src/locales/he.json +61 -1
  128. package/src/locales/hy.json +61 -1
  129. package/src/locales/it.json +61 -1
  130. package/src/locales/ja.json +61 -1
  131. package/src/locales/ka.json +61 -1
  132. package/src/locales/kr.json +61 -1
  133. package/src/locales/nl.json +61 -1
  134. package/src/locales/pl.json +61 -1
  135. package/src/locales/pt.json +61 -1
  136. package/src/locales/ru.json +61 -1
  137. package/src/locales/sv.json +61 -1
  138. package/src/locales/tr.json +61 -1
  139. package/src/locales/uk.json +61 -1
  140. package/src/locales/zh-TW.json +61 -1
  141. package/src/locales/zh.json +61 -1
  142. package/src/stores/keyboard.ts +371 -0
  143. package/src/stores/keyboardActions.ts +769 -0
  144. package/src/stores/locale.ts +1 -0
  145. package/src/stores/reportEnvSections.ts +6 -0
  146. package/src/stores/reportRootTabs.ts +95 -0
  147. package/src/stores/search.ts +147 -0
  148. package/src/stores/testResultOverviewNav.ts +119 -0
  149. package/src/stores/testResultTabs.ts +62 -0
  150. package/src/stores/timeline.ts +1 -1
  151. package/src/stores/tree.ts +42 -4
  152. package/src/stores/treeFilters/store.ts +3 -36
  153. package/src/styles/_pane-active.scss +8 -0
  154. package/src/styles.scss +1 -1
  155. package/src/utils/flattenTestResultOverview.ts +182 -0
  156. package/src/utils/trOverviewFocus.ts +18 -0
  157. package/test/components/EnvironmentPicker.test.tsx +21 -3
  158. package/test/components/Header/CiInfo.test.tsx +8 -0
  159. package/test/components/Header.test.tsx +8 -0
  160. package/test/components/ReportGlobals.test.tsx +9 -1
  161. package/test/components/TestResult/PwTraceButton.test.tsx +8 -0
  162. package/test/components/TestResult/TrErrorStep.test.tsx +8 -0
  163. package/test/components/TestResult/TrOverview.test.tsx +30 -10
  164. package/test/components/TestResult/TrSteps.test.tsx +73 -0
  165. package/test/components/TestResult/bodyItems.test.ts +9 -1
  166. package/test/components/TestResult/openPwTraceInNewTab.test.ts +8 -0
  167. package/test/components/TestResult/stepTreeExpansion.test.ts +10 -2
  168. package/test/components/Timeline.test.tsx +15 -7
  169. package/test/stores/keyboard/keyboardActions.test.ts +615 -0
  170. package/test/stores/search.test.ts +143 -0
  171. package/test/stores/treeFilters/actions.test.ts +8 -0
  172. package/test/utils/flattenTestResultOverview.test.ts +57 -0
  173. package/test/utils/ownerAddress.test.ts +9 -1
  174. package/test/utils/treeFilters.test.ts +9 -1
  175. package/types.d.ts +17 -0
  176. package/webpack.config.js +3 -0
  177. package/CONTRIBUTING.md +0 -34
  178. package/dist/multi/173.app-f008fb8342025f2b1ace.js +0 -1
  179. package/dist/multi/174.app-f008fb8342025f2b1ace.js +0 -1
  180. package/dist/multi/252.app-f008fb8342025f2b1ace.js +0 -1
  181. package/dist/multi/282.app-f008fb8342025f2b1ace.js +0 -1
  182. package/dist/multi/29.app-f008fb8342025f2b1ace.js +0 -1
  183. package/dist/multi/310.app-f008fb8342025f2b1ace.js +0 -1
  184. package/dist/multi/527.app-f008fb8342025f2b1ace.js +0 -1
  185. package/dist/multi/600.app-f008fb8342025f2b1ace.js +0 -1
  186. package/dist/multi/605.app-f008fb8342025f2b1ace.js +0 -1
  187. package/dist/multi/638.app-f008fb8342025f2b1ace.js +0 -1
  188. package/dist/multi/672.app-f008fb8342025f2b1ace.js +0 -1
  189. package/dist/multi/686.app-f008fb8342025f2b1ace.js +0 -1
  190. package/dist/multi/725.app-f008fb8342025f2b1ace.js +0 -1
  191. package/dist/multi/741.app-f008fb8342025f2b1ace.js +0 -1
  192. package/dist/multi/749.app-f008fb8342025f2b1ace.js +0 -1
  193. package/dist/multi/755.app-f008fb8342025f2b1ace.js +0 -1
  194. package/dist/multi/943.app-f008fb8342025f2b1ace.js +0 -1
  195. package/dist/multi/980.app-f008fb8342025f2b1ace.js +0 -1
  196. package/dist/multi/app-f008fb8342025f2b1ace.js +0 -2
  197. package/dist/multi/styles-9f7a23a0c8b79fa76981.css +0 -58
  198. package/dist/single/app-07332238da9897064301.js +0 -2
  199. package/src/assets/scss/day.scss +0 -53
  200. package/src/assets/scss/fonts.scss +0 -3
  201. package/src/assets/scss/night.scss +0 -63
  202. package/src/assets/scss/palette.scss +0 -393
  203. package/src/assets/scss/theme.scss +0 -330
  204. package/src/assets/scss/vars.scss +0 -11
  205. /package/dist/multi/{app-f008fb8342025f2b1ace.js.LICENSE.txt → app-d36b0855e3e7a53eeee9.js.LICENSE.txt} +0 -0
  206. /package/dist/single/{app-07332238da9897064301.js.LICENSE.txt → app-62171f5f51b5954a787c.js.LICENSE.txt} +0 -0
@@ -0,0 +1,556 @@
1
+ import { createHotkeyController, type HotkeyBinding, type HotkeyScope } from "@allurereport/web-commons";
2
+ import { useEffect } from "preact/hooks";
3
+
4
+ import {
5
+ focusTreePane,
6
+ hotkeysHelpOpen,
7
+ isHotkeyScopeActive,
8
+ isSearchInput,
9
+ toggleHotkeysHelp,
10
+ } from "@/stores/keyboard";
11
+ import {
12
+ applyTreeNavigation,
13
+ collapseAllChildrenFromFocus,
14
+ collapseFocusedSubtree,
15
+ cycleFocusedSubtreeToggle,
16
+ expandAllChildrenFromFocus,
17
+ expandFocusedSubtree,
18
+ expandFocusedSubtreeFirstLevel,
19
+ blurSearch,
20
+ focusSearch,
21
+ focusTestResultPaneIfOpen,
22
+ getHotkeyScope,
23
+ cycleReportRootTabHotkey,
24
+ cycleTestResultTabHotkey,
25
+ goToNextTestResult,
26
+ goToPrevTestResult,
27
+ goToReportRootTab,
28
+ goToTestResultTab,
29
+ handleTestResultEscape,
30
+ isHotkeysEnabled,
31
+ navigateDownInTestResultPane,
32
+ navigateUpInTestResultPane,
33
+ openTestResultFromTree,
34
+ openTreeNodeFromFocus,
35
+ toggleMetadataSection,
36
+ toggleReportEnvSection,
37
+ toggleTreeNodeFromFocus,
38
+ } from "@/stores/keyboardActions";
39
+ import { toggleLayout } from "@/stores/layout";
40
+ import { REPORT_ROOT_TAB } from "@/stores/reportRootTabs";
41
+ import { TEST_RESULT_TAB } from "@/stores/testResultTabs";
42
+
43
+ const TREE_NAVIGATION_KEYS = new Set([
44
+ "ArrowUp",
45
+ "ArrowDown",
46
+ "ArrowLeft",
47
+ "ArrowRight",
48
+ "Home",
49
+ "End",
50
+ " ",
51
+ "-",
52
+ "=",
53
+ "+",
54
+ ]);
55
+
56
+ const TREE_NAV_CODES = new Set([
57
+ "KeyJ",
58
+ "KeyK",
59
+ "KeyH",
60
+ "KeyL",
61
+ "KeyP",
62
+ "KeyU",
63
+ "KeyO",
64
+ "KeyA",
65
+ "KeyC",
66
+ "KeyF",
67
+ "KeyZ",
68
+ "KeyT",
69
+ "Minus",
70
+ "Equal",
71
+ ]);
72
+
73
+ const TEST_RESULT_OVERVIEW_NAV_KEYS = new Set(["ArrowUp", "ArrowDown"]);
74
+
75
+ const TEST_RESULT_OVERVIEW_NAV_CODES = new Set(["KeyJ", "KeyK"]);
76
+
77
+ const shouldSuppressHotkeyScroll = (event: KeyboardEvent, activeScope: HotkeyScope): boolean => {
78
+ if (
79
+ activeScope === "tree" &&
80
+ isHotkeyScopeActive("tree") &&
81
+ (TREE_NAVIGATION_KEYS.has(event.key) || TREE_NAV_CODES.has(event.code))
82
+ ) {
83
+ return true;
84
+ }
85
+
86
+ return (
87
+ activeScope === "testResult" &&
88
+ isHotkeyScopeActive("testResult") &&
89
+ (TEST_RESULT_OVERVIEW_NAV_KEYS.has(event.key) || TEST_RESULT_OVERVIEW_NAV_CODES.has(event.code))
90
+ );
91
+ };
92
+
93
+ const createBindings = (): HotkeyBinding[] => [
94
+ {
95
+ id: "toggle-help",
96
+ scope: "global",
97
+ key: "?",
98
+ code: "Slash",
99
+ modifiers: { shift: true },
100
+ handler: () => toggleHotkeysHelp(),
101
+ },
102
+ {
103
+ id: "blur-search",
104
+ scope: "global",
105
+ key: "Escape",
106
+ allowInEditable: true,
107
+ handler: () => {
108
+ if (!isSearchInput(document.activeElement)) {
109
+ return;
110
+ }
111
+
112
+ if (hotkeysHelpOpen.value) {
113
+ hotkeysHelpOpen.value = false;
114
+ return;
115
+ }
116
+
117
+ blurSearch();
118
+ },
119
+ },
120
+ {
121
+ id: "escape",
122
+ scope: ["global", "tree", "testResult"],
123
+ key: "Escape",
124
+ handler: () => {
125
+ if (hotkeysHelpOpen.value) {
126
+ hotkeysHelpOpen.value = false;
127
+ return;
128
+ }
129
+
130
+ if (getHotkeyScope() === "testResult") {
131
+ handleTestResultEscape();
132
+ }
133
+ },
134
+ preventDefault: false,
135
+ },
136
+ {
137
+ id: "focus-search",
138
+ scope: "global",
139
+ key: "s",
140
+ code: "KeyS",
141
+ handler: () => focusSearch(),
142
+ },
143
+ {
144
+ id: "toggle-layout",
145
+ scope: "global",
146
+ key: "l",
147
+ code: "KeyL",
148
+ modifiers: { shift: true },
149
+ handler: () => toggleLayout(),
150
+ },
151
+ {
152
+ id: "toggle-layout-ctrl",
153
+ scope: "global",
154
+ key: "\\",
155
+ code: "Backslash",
156
+ modifiers: { ctrlOrMeta: true },
157
+ handler: () => toggleLayout(),
158
+ },
159
+ {
160
+ id: "focus-tree-pane",
161
+ scope: "global",
162
+ key: "[",
163
+ code: "BracketLeft",
164
+ handler: () => focusTreePane(),
165
+ },
166
+ {
167
+ id: "report-tab-results",
168
+ scope: "global",
169
+ key: "1",
170
+ handler: () => goToReportRootTab(REPORT_ROOT_TAB.Results),
171
+ },
172
+ {
173
+ id: "report-tab-categories",
174
+ scope: "global",
175
+ key: "2",
176
+ handler: () => goToReportRootTab(REPORT_ROOT_TAB.Categories),
177
+ },
178
+ {
179
+ id: "report-tab-quality-gate",
180
+ scope: "global",
181
+ key: "3",
182
+ handler: () => goToReportRootTab(REPORT_ROOT_TAB.QualityGate),
183
+ },
184
+ {
185
+ id: "report-tab-global-attachments",
186
+ scope: "global",
187
+ key: "4",
188
+ handler: () => goToReportRootTab(REPORT_ROOT_TAB.GlobalAttachments),
189
+ },
190
+ {
191
+ id: "report-tab-global-errors",
192
+ scope: "global",
193
+ key: "5",
194
+ handler: () => goToReportRootTab(REPORT_ROOT_TAB.GlobalErrors),
195
+ },
196
+ {
197
+ id: "report-tab-next",
198
+ scope: "global",
199
+ key: "Tab",
200
+ handler: () => cycleReportRootTabHotkey("next"),
201
+ },
202
+ {
203
+ id: "report-tab-prev",
204
+ scope: "global",
205
+ key: "Tab",
206
+ modifiers: { shift: true },
207
+ handler: () => cycleReportRootTabHotkey("prev"),
208
+ },
209
+ {
210
+ id: "focus-tree-pane-fallback",
211
+ scope: "global",
212
+ key: "[",
213
+ handler: () => focusTreePane(),
214
+ },
215
+ {
216
+ id: "focus-test-result-pane",
217
+ scope: "global",
218
+ key: "]",
219
+ code: "BracketRight",
220
+ handler: () => focusTestResultPaneIfOpen(),
221
+ },
222
+ {
223
+ id: "focus-test-result-pane-fallback",
224
+ scope: "global",
225
+ key: "]",
226
+ handler: () => focusTestResultPaneIfOpen(),
227
+ },
228
+ {
229
+ id: "tree-up",
230
+ scope: "tree",
231
+ key: "ArrowUp",
232
+ handler: () => applyTreeNavigation("up"),
233
+ },
234
+ {
235
+ id: "tree-down",
236
+ scope: "tree",
237
+ key: "ArrowDown",
238
+ handler: () => applyTreeNavigation("down"),
239
+ },
240
+ {
241
+ id: "tree-left",
242
+ scope: "tree",
243
+ key: "ArrowLeft",
244
+ handler: () => applyTreeNavigation("left"),
245
+ },
246
+ {
247
+ id: "tree-right",
248
+ scope: "tree",
249
+ key: "ArrowRight",
250
+ handler: () => applyTreeNavigation("right"),
251
+ },
252
+ {
253
+ id: "tree-up-vim",
254
+ scope: "tree",
255
+ key: "k",
256
+ code: "KeyK",
257
+ handler: () => applyTreeNavigation("up"),
258
+ },
259
+ {
260
+ id: "tree-down-vim",
261
+ scope: "tree",
262
+ key: "j",
263
+ code: "KeyJ",
264
+ handler: () => applyTreeNavigation("down"),
265
+ },
266
+ {
267
+ id: "tree-left-vim",
268
+ scope: "tree",
269
+ key: "h",
270
+ code: "KeyH",
271
+ handler: () => applyTreeNavigation("left"),
272
+ },
273
+ {
274
+ id: "tree-right-vim",
275
+ scope: "tree",
276
+ key: "l",
277
+ code: "KeyL",
278
+ handler: () => applyTreeNavigation("right"),
279
+ },
280
+ {
281
+ id: "tree-parent",
282
+ scope: "tree",
283
+ key: "p",
284
+ code: "KeyP",
285
+ handler: () => applyTreeNavigation("parent"),
286
+ },
287
+ {
288
+ id: "tree-parent-alt",
289
+ scope: "tree",
290
+ key: "u",
291
+ code: "KeyU",
292
+ handler: () => applyTreeNavigation("parent"),
293
+ },
294
+ {
295
+ id: "tree-open",
296
+ scope: "tree",
297
+ key: "o",
298
+ code: "KeyO",
299
+ handler: () => openTreeNodeFromFocus(),
300
+ },
301
+ {
302
+ id: "tree-collapse",
303
+ scope: "tree",
304
+ key: "-",
305
+ code: "Minus",
306
+ handler: () => applyTreeNavigation("left"),
307
+ },
308
+ {
309
+ id: "tree-expand",
310
+ scope: "tree",
311
+ key: "+",
312
+ code: "Equal",
313
+ modifiers: { shift: true },
314
+ handler: () => applyTreeNavigation("firstChild"),
315
+ },
316
+ {
317
+ id: "tree-expand-equal",
318
+ scope: "tree",
319
+ key: "=",
320
+ code: "Equal",
321
+ handler: () => applyTreeNavigation("firstChild"),
322
+ },
323
+ {
324
+ id: "toggle-report-variables",
325
+ scope: "tree",
326
+ key: "V",
327
+ code: "KeyV",
328
+ handler: () => toggleReportEnvSection("variables"),
329
+ },
330
+ {
331
+ id: "toggle-report-metadata",
332
+ scope: "tree",
333
+ key: "M",
334
+ code: "KeyM",
335
+ handler: () => toggleReportEnvSection("metadata"),
336
+ },
337
+ {
338
+ id: "tree-collapse-all",
339
+ scope: "tree",
340
+ key: "C",
341
+ code: "KeyC",
342
+ handler: () => collapseAllChildrenFromFocus(),
343
+ },
344
+ {
345
+ id: "tree-expand-all",
346
+ scope: "tree",
347
+ key: "A",
348
+ code: "KeyA",
349
+ handler: () => expandAllChildrenFromFocus(),
350
+ },
351
+ {
352
+ id: "tree-subtree-collapse",
353
+ scope: "tree",
354
+ key: "C",
355
+ code: "KeyC",
356
+ modifiers: { shift: true },
357
+ handler: () => collapseFocusedSubtree(),
358
+ },
359
+ {
360
+ id: "tree-subtree-expand",
361
+ scope: "tree",
362
+ key: "A",
363
+ code: "KeyA",
364
+ modifiers: { shift: true },
365
+ handler: () => expandFocusedSubtree(),
366
+ },
367
+ {
368
+ id: "tree-subtree-first-level",
369
+ scope: "tree",
370
+ key: "f",
371
+ code: "KeyF",
372
+ handler: () => expandFocusedSubtreeFirstLevel(),
373
+ },
374
+ {
375
+ id: "tree-subtree-cycle",
376
+ scope: "tree",
377
+ key: ">",
378
+ code: "Period",
379
+ modifiers: { shift: true },
380
+ handler: () => cycleFocusedSubtreeToggle(),
381
+ },
382
+ {
383
+ id: "tree-home",
384
+ scope: "tree",
385
+ key: "Home",
386
+ handler: () => applyTreeNavigation("home"),
387
+ },
388
+ {
389
+ id: "tree-scroll-top-z",
390
+ scope: "tree",
391
+ key: "z",
392
+ code: "KeyZ",
393
+ handler: () => applyTreeNavigation("z"),
394
+ },
395
+ {
396
+ id: "tree-scroll-top-t",
397
+ scope: "tree",
398
+ key: "t",
399
+ code: "KeyT",
400
+ handler: () => applyTreeNavigation("t"),
401
+ },
402
+ {
403
+ id: "tree-end",
404
+ scope: "tree",
405
+ key: "End",
406
+ handler: () => applyTreeNavigation("end"),
407
+ },
408
+ {
409
+ id: "tree-go-first",
410
+ scope: "tree",
411
+ key: "g",
412
+ handler: () => applyTreeNavigation("g"),
413
+ },
414
+ {
415
+ id: "tree-last-leaf",
416
+ scope: "tree",
417
+ key: "G",
418
+ modifiers: { shift: true },
419
+ handler: () => applyTreeNavigation("lastLeaf"),
420
+ },
421
+ {
422
+ id: "tree-toggle",
423
+ scope: "tree",
424
+ key: " ",
425
+ handler: () => toggleTreeNodeFromFocus(),
426
+ },
427
+ {
428
+ id: "tree-open-enter",
429
+ scope: "tree",
430
+ key: "Enter",
431
+ handler: () => openTestResultFromTree(),
432
+ },
433
+ {
434
+ id: "test-result-prev",
435
+ scope: "testResult",
436
+ key: "N",
437
+ code: "KeyN",
438
+ modifiers: { shift: true },
439
+ handler: () => goToPrevTestResult(),
440
+ },
441
+ {
442
+ id: "test-result-next",
443
+ scope: "testResult",
444
+ key: "n",
445
+ code: "KeyN",
446
+ handler: () => goToNextTestResult(),
447
+ },
448
+ {
449
+ id: "test-result-tab-overview",
450
+ scope: "testResult",
451
+ key: "1",
452
+ handler: () => goToTestResultTab(TEST_RESULT_TAB.Overview),
453
+ },
454
+ {
455
+ id: "test-result-tab-history",
456
+ scope: "testResult",
457
+ key: "2",
458
+ handler: () => goToTestResultTab(TEST_RESULT_TAB.History),
459
+ },
460
+ {
461
+ id: "test-result-tab-retries",
462
+ scope: "testResult",
463
+ key: "3",
464
+ handler: () => goToTestResultTab(TEST_RESULT_TAB.Retries),
465
+ },
466
+ {
467
+ id: "test-result-tab-attachments",
468
+ scope: "testResult",
469
+ key: "4",
470
+ handler: () => goToTestResultTab(TEST_RESULT_TAB.Attachments),
471
+ },
472
+ {
473
+ id: "test-result-tab-environments",
474
+ scope: "testResult",
475
+ key: "5",
476
+ handler: () => goToTestResultTab(TEST_RESULT_TAB.Environments),
477
+ },
478
+ {
479
+ id: "test-result-tab-next",
480
+ scope: "testResult",
481
+ key: "Tab",
482
+ handler: () => cycleTestResultTabHotkey("next"),
483
+ },
484
+ {
485
+ id: "test-result-tab-prev",
486
+ scope: "testResult",
487
+ key: "Tab",
488
+ modifiers: { shift: true },
489
+ handler: () => cycleTestResultTabHotkey("prev"),
490
+ },
491
+ {
492
+ id: "test-result-overview-down",
493
+ scope: "testResult",
494
+ key: "ArrowDown",
495
+ handler: () => navigateDownInTestResultPane(),
496
+ },
497
+ {
498
+ id: "test-result-overview-down-vim",
499
+ scope: "testResult",
500
+ key: "j",
501
+ code: "KeyJ",
502
+ handler: () => navigateDownInTestResultPane(),
503
+ },
504
+ {
505
+ id: "test-result-overview-up",
506
+ scope: "testResult",
507
+ key: "ArrowUp",
508
+ handler: () => navigateUpInTestResultPane(),
509
+ },
510
+ {
511
+ id: "test-result-overview-up-vim",
512
+ scope: "testResult",
513
+ key: "k",
514
+ code: "KeyK",
515
+ handler: () => navigateUpInTestResultPane(),
516
+ },
517
+ {
518
+ id: "toggle-labels",
519
+ scope: "testResult",
520
+ key: "l",
521
+ code: "KeyL",
522
+ handler: () => toggleMetadataSection("labels"),
523
+ },
524
+ {
525
+ id: "toggle-parameters",
526
+ scope: "testResult",
527
+ key: "p",
528
+ code: "KeyP",
529
+ handler: () => toggleMetadataSection("parameters"),
530
+ },
531
+ {
532
+ id: "toggle-links",
533
+ scope: "testResult",
534
+ key: "i",
535
+ code: "KeyI",
536
+ handler: () => toggleMetadataSection("links"),
537
+ },
538
+ ];
539
+
540
+ export const HotkeysProvider = () => {
541
+ useEffect(() => {
542
+ const controller = createHotkeyController({
543
+ getActiveScope: getHotkeyScope,
544
+ getEnabled: isHotkeysEnabled,
545
+ isScopeActive: isHotkeyScopeActive,
546
+ bindings: createBindings(),
547
+ shouldSuppressDefault: shouldSuppressHotkeyScroll,
548
+ });
549
+
550
+ controller.attach();
551
+
552
+ return () => controller.detach();
553
+ }, []);
554
+
555
+ return null;
556
+ };
@@ -0,0 +1,73 @@
1
+ import { Button, Code, Text, allureIcons } from "@allurereport/web-components";
2
+ import clsx from "clsx";
3
+
4
+ import { useI18n } from "@/stores";
5
+ import { activePane, hotkeysHelpOpen, toggleHotkeysHelp } from "@/stores/keyboard";
6
+ import { isSplitMode } from "@/stores/layout";
7
+
8
+ import { formatShortcut, shortcutGroups, type ShortcutGroupId } from "./shortcutsConfig";
9
+
10
+ import * as styles from "./styles.scss";
11
+
12
+ const visibleGroups = (pane: "tree" | "testResult", split: boolean): ShortcutGroupId[] => {
13
+ const groups: ShortcutGroupId[] = ["global", "tree"];
14
+
15
+ if (split || pane === "testResult") {
16
+ groups.push("testResult");
17
+ }
18
+
19
+ return groups;
20
+ };
21
+
22
+ export const KeyboardShortcuts = () => {
23
+ const { t } = useI18n("shortcuts");
24
+ const pane = activePane.value;
25
+ const split = isSplitMode.value;
26
+ const groups = shortcutGroups.filter((group) => visibleGroups(pane, split).includes(group.id));
27
+
28
+ return (
29
+ <div className={styles.shortcuts} data-testid="keyboard-shortcuts">
30
+ {hotkeysHelpOpen.value && (
31
+ <div className={styles.panel} data-testid="keyboard-shortcuts-panel">
32
+ <div className={styles.header}>
33
+ <Text size="m" bold>
34
+ {t("title")}
35
+ </Text>
36
+ <Button
37
+ style="ghost"
38
+ size="xs"
39
+ icon={allureIcons.lineGeneralXClose}
40
+ onClick={() => toggleHotkeysHelp()}
41
+ data-testid="keyboard-shortcuts-close"
42
+ />
43
+ </div>
44
+ {groups.map((group) => (
45
+ <div key={group.id} className={styles.group}>
46
+ <Code size="s" className={styles.groupTitle}>
47
+ {t(group.titleKey)}
48
+ </Code>
49
+ {group.items.map((item) => (
50
+ <div key={`${group.id}-${item.labelKey}`} className={styles.item}>
51
+ <Code size="s" className={clsx(styles.keys, "hotkey")}>
52
+ {formatShortcut(item.binding)}
53
+ </Code>
54
+ <Text size="s" className={styles.label}>
55
+ {t(item.labelKey)}
56
+ </Text>
57
+ </div>
58
+ ))}
59
+ </div>
60
+ ))}
61
+ </div>
62
+ )}
63
+ <Button
64
+ className={styles.trigger}
65
+ style="outline"
66
+ size="s"
67
+ text="?"
68
+ onClick={() => toggleHotkeysHelp()}
69
+ data-testid="keyboard-shortcuts-trigger"
70
+ />
71
+ </div>
72
+ );
73
+ };