windmill-components 1.695.1 → 1.699.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 (180) hide show
  1. package/dist/sharedUtils/assets/tokens/colorTokensConfig.d.ts +2 -0
  2. package/dist/sharedUtils/base.d.ts +1 -0
  3. package/dist/sharedUtils/cloud.d.ts +1 -0
  4. package/dist/sharedUtils/common.d.ts +111 -0
  5. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/count.d.ts +5 -0
  6. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/delete.d.ts +5 -0
  7. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/insert.d.ts +5 -0
  8. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/select.d.ts +13 -0
  9. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/update.d.ts +11 -0
  10. package/dist/sharedUtils/components/apps/components/display/dbtable/utils.d.ts +95 -0
  11. package/dist/sharedUtils/components/apps/editor/appPolicy.d.ts +6 -0
  12. package/dist/sharedUtils/components/apps/editor/appUtilsCore.d.ts +7 -0
  13. package/dist/sharedUtils/components/apps/editor/appUtilsS3.d.ts +33 -0
  14. package/dist/sharedUtils/components/apps/editor/commonAppUtils.d.ts +10 -0
  15. package/dist/sharedUtils/components/apps/editor/component/components.d.ts +5371 -0
  16. package/dist/sharedUtils/components/apps/editor/component/default-codes.d.ts +3 -0
  17. package/dist/sharedUtils/components/apps/editor/component/index.d.ts +3 -0
  18. package/dist/sharedUtils/components/apps/editor/component/sets.d.ts +7 -0
  19. package/dist/sharedUtils/components/apps/editor/componentsPanel/componentDefaultProps.d.ts +3 -0
  20. package/dist/sharedUtils/components/apps/gridUtils.d.ts +14 -0
  21. package/dist/sharedUtils/components/apps/inputType.d.ts +178 -0
  22. package/dist/sharedUtils/components/apps/rx.d.ts +29 -0
  23. package/dist/sharedUtils/components/apps/sharedTypes.d.ts +21 -0
  24. package/dist/sharedUtils/components/apps/types.d.ts +274 -0
  25. package/dist/sharedUtils/components/assets/lib.d.ts +25 -0
  26. package/dist/sharedUtils/components/common/alert/model.d.ts +2 -0
  27. package/dist/sharedUtils/components/common/badge/model.d.ts +8 -0
  28. package/dist/sharedUtils/components/common/button/model.d.ts +45 -0
  29. package/dist/sharedUtils/components/common/fileInput/model.d.ts +1 -0
  30. package/dist/sharedUtils/components/common/index.d.ts +24 -0
  31. package/dist/sharedUtils/components/common/skeleton/model.d.ts +21 -0
  32. package/dist/sharedUtils/components/dbTypes.d.ts +14 -0
  33. package/dist/sharedUtils/components/diff_drawer.d.ts +26 -0
  34. package/dist/sharedUtils/components/ducklake.d.ts +1 -0
  35. package/dist/sharedUtils/components/flows/scheduleUtils.d.ts +7 -0
  36. package/dist/sharedUtils/components/icons/index.d.ts +101 -0
  37. package/dist/sharedUtils/components/random_positive_adjetive.d.ts +1 -0
  38. package/dist/sharedUtils/components/raw_apps/rawAppPolicy.d.ts +10 -0
  39. package/dist/sharedUtils/components/raw_apps/utils.d.ts +15 -0
  40. package/dist/sharedUtils/components/triggers/email/utils.d.ts +4 -0
  41. package/dist/sharedUtils/components/triggers/gcp/utils.d.ts +2 -0
  42. package/dist/sharedUtils/components/triggers/http/utils.d.ts +11 -0
  43. package/dist/sharedUtils/components/triggers/kafka/utils.d.ts +2 -0
  44. package/dist/sharedUtils/components/triggers/mqtt/utils.d.ts +2 -0
  45. package/dist/sharedUtils/components/triggers/nats/utils.d.ts +2 -0
  46. package/dist/sharedUtils/components/triggers/postgres/utils.d.ts +8 -0
  47. package/dist/sharedUtils/components/triggers/sqs/utils.d.ts +2 -0
  48. package/dist/sharedUtils/components/triggers/triggers.svelte.d.ts +32 -0
  49. package/dist/sharedUtils/components/triggers/utils.d.ts +80 -0
  50. package/dist/sharedUtils/components/triggers/websocket/utils.d.ts +2 -0
  51. package/dist/sharedUtils/components/triggers.d.ts +20 -0
  52. package/dist/sharedUtils/gen/core/ApiError.d.ts +10 -0
  53. package/dist/sharedUtils/gen/core/ApiRequestOptions.d.ts +13 -0
  54. package/dist/sharedUtils/gen/core/ApiResult.d.ts +7 -0
  55. package/dist/sharedUtils/gen/core/CancelablePromise.d.ts +26 -0
  56. package/dist/sharedUtils/gen/core/OpenAPI.d.ts +27 -0
  57. package/dist/sharedUtils/gen/core/request.d.ts +29 -0
  58. package/dist/sharedUtils/gen/index.d.ts +6 -0
  59. package/dist/sharedUtils/gen/schemas.gen.d.ts +7036 -0
  60. package/dist/sharedUtils/gen/services.gen.d.ts +6047 -0
  61. package/dist/sharedUtils/gen/types.gen.d.ts +21881 -0
  62. package/dist/sharedUtils/history.svelte.d.ts +9 -0
  63. package/dist/sharedUtils/hub.d.ts +49 -0
  64. package/dist/sharedUtils/jsr.json +6 -0
  65. package/dist/sharedUtils/lib.d.ts +5 -0
  66. package/dist/sharedUtils/lib.es.js +1588 -0
  67. package/dist/sharedUtils/package.json +12 -0
  68. package/dist/sharedUtils/schema.d.ts +3 -0
  69. package/dist/sharedUtils/stores.d.ts +97 -0
  70. package/dist/sharedUtils/svelte5Utils.svelte.d.ts +80 -0
  71. package/dist/sharedUtils/toast.d.ts +8 -0
  72. package/dist/sharedUtils/utils.d.ts +265 -0
  73. package/package/components/AppConnectInner.svelte +38 -5
  74. package/package/components/CompareWorkspaces.svelte +142 -486
  75. package/package/components/DisplayResult.svelte +39 -19
  76. package/package/components/Editor.svelte +5 -4
  77. package/package/components/Editor.svelte.d.ts +1 -0
  78. package/package/components/FilterSearchbar.svelte +3 -1
  79. package/package/components/FilterSearchbar.svelte.d.ts +1 -0
  80. package/package/components/FlowStatusViewerInner.svelte +23 -9
  81. package/package/components/ForkWorkspaceBanner.svelte +16 -0
  82. package/package/components/HistoricInputs.svelte +2 -1
  83. package/package/components/InstanceSetting.svelte +47 -5
  84. package/package/components/LogViewer.svelte +101 -71
  85. package/package/components/OnBehalfOfSelector.svelte +10 -7
  86. package/package/components/ParqetCsvTableRenderer.svelte +9 -4
  87. package/package/components/Path.svelte +10 -0
  88. package/package/components/ResourceEditor.svelte +198 -311
  89. package/package/components/ResourceEditor.svelte.d.ts +3 -3
  90. package/package/components/ResourceEditorDrawer.svelte +17 -6
  91. package/package/components/ResourceForm.svelte +235 -0
  92. package/package/components/ResourceForm.svelte.d.ts +25 -0
  93. package/package/components/RunsPage.svelte +1 -0
  94. package/package/components/S3FilePickerInner.svelte +22 -8
  95. package/package/components/ScriptBuilder.svelte +1 -0
  96. package/package/components/ScriptEditor.svelte +44 -7
  97. package/package/components/ScriptEditor.svelte.d.ts +1 -0
  98. package/package/components/ShareModal.svelte.d.ts +1 -1
  99. package/package/components/TaggedTextInput.svelte +4 -1
  100. package/package/components/TaggedTextInput.svelte.d.ts +2 -0
  101. package/package/components/VariableEditor.svelte +177 -199
  102. package/package/components/VariableEditor.svelte.d.ts +1 -2
  103. package/package/components/VariableForm.svelte +133 -0
  104. package/package/components/VariableForm.svelte.d.ts +22 -0
  105. package/package/components/WsSpecificVersions.svelte +39 -0
  106. package/package/components/WsSpecificVersions.svelte.d.ts +9 -0
  107. package/package/components/apps/editor/AppEditorHeaderDeploy.svelte.d.ts +1 -1
  108. package/package/components/common/fileDownload/FileDownload.svelte +16 -6
  109. package/package/components/common/table/AppRow.svelte +2 -1
  110. package/package/components/common/table/AppRow.svelte.d.ts +1 -0
  111. package/package/components/common/table/FlowRow.svelte +2 -1
  112. package/package/components/common/table/FlowRow.svelte.d.ts +1 -0
  113. package/package/components/common/table/RawAppRow.svelte +2 -1
  114. package/package/components/common/table/RawAppRow.svelte.d.ts +1 -0
  115. package/package/components/common/table/Row.svelte +11 -3
  116. package/package/components/common/table/Row.svelte.d.ts +2 -1
  117. package/package/components/common/table/RowIcon.svelte +18 -2
  118. package/package/components/common/table/RowIcon.svelte.d.ts +1 -1
  119. package/package/components/common/table/ScriptRow.svelte +2 -1
  120. package/package/components/common/table/ScriptRow.svelte.d.ts +1 -0
  121. package/package/components/copilot/autocomplete/Autocompletor.d.ts +3 -1
  122. package/package/components/copilot/autocomplete/Autocompletor.js +5 -2
  123. package/package/components/copilot/autocomplete/request.d.ts +1 -0
  124. package/package/components/copilot/autocomplete/request.js +1 -1
  125. package/package/components/copilot/chat/AIChatManager.svelte.js +14 -4
  126. package/package/components/copilot/chat/AiChatLayout.svelte +2 -0
  127. package/package/components/copilot/chat/ContextManager.svelte.d.ts +1 -0
  128. package/package/components/copilot/chat/CreatedResourceActionDrawers.svelte +129 -0
  129. package/package/components/copilot/chat/CreatedResourceActionDrawers.svelte.d.ts +4 -0
  130. package/package/components/copilot/chat/ToolExecutionDisplay.svelte +14 -6
  131. package/package/components/copilot/chat/ToolMessageActions.svelte +73 -0
  132. package/package/components/copilot/chat/ToolMessageActions.svelte.d.ts +7 -0
  133. package/package/components/copilot/chat/createdResourceActions.svelte.d.ts +6 -0
  134. package/package/components/copilot/chat/createdResourceActions.svelte.js +29 -0
  135. package/package/components/copilot/chat/script/core.d.ts +6 -2
  136. package/package/components/copilot/chat/script/core.js +13 -7
  137. package/package/components/copilot/chat/script/wacPrompt.test.d.ts +1 -0
  138. package/package/components/copilot/chat/script/wacPrompt.test.js +25 -0
  139. package/package/components/copilot/chat/shared.d.ts +12 -0
  140. package/package/components/copilot/chat/shared.test.js +23 -2
  141. package/package/components/copilot/chat/workspaceTools.js +34 -4
  142. package/package/components/flows/content/ScriptEditorDrawer.svelte +1 -0
  143. package/package/components/flows/idUtils.js +4 -1
  144. package/package/components/flows/stepsInputArgs.svelte.js +6 -1
  145. package/package/components/graph/wacToFlow.js +1 -1
  146. package/package/components/graph/wacToFlow.test.d.ts +1 -0
  147. package/package/components/graph/wacToFlow.test.js +17 -0
  148. package/package/components/home/Item.svelte +5 -1
  149. package/package/components/home/Item.svelte.d.ts +1 -0
  150. package/package/components/home/ItemsList.svelte +260 -3
  151. package/package/components/instanceSettings/SecretBackendConfig.svelte +492 -98
  152. package/package/components/propertyPicker/ObjectViewer.svelte +10 -4
  153. package/package/components/runs/runsFilter.d.ts +1 -1
  154. package/package/components/runs/useJobsLoader.svelte.d.ts +1 -0
  155. package/package/components/runs/useJobsLoader.svelte.js +8 -12
  156. package/package/components/scriptEditor/LogPanel.svelte +4 -1
  157. package/package/components/scriptEditor/LogPanel.svelte.d.ts +1 -0
  158. package/package/components/settings/WorkspaceOperatorSettings.svelte +1 -1
  159. package/package/components/sidebar/SidebarContent.svelte +40 -2
  160. package/package/components/sidebar/WorkspaceMenu.svelte +19 -5
  161. package/package/externalDomain.d.ts +2 -0
  162. package/package/externalDomain.js +16 -0
  163. package/package/gen/core/OpenAPI.js +1 -1
  164. package/package/gen/schemas.gen.d.ts +33 -4
  165. package/package/gen/schemas.gen.js +33 -4
  166. package/package/gen/services.gen.d.ts +20 -1
  167. package/package/gen/services.gen.js +40 -0
  168. package/package/gen/types.gen.d.ts +70 -3
  169. package/package/hubPaths.json +2 -2
  170. package/package/system_prompts/index.d.ts +1 -1
  171. package/package/system_prompts/index.js +22 -3
  172. package/package/system_prompts/prompts.d.ts +2 -2
  173. package/package/system_prompts/prompts.js +7 -4
  174. package/package/utils/downloadFile.d.ts +11 -0
  175. package/package/utils/downloadFile.js +48 -0
  176. package/package/utils_deployable.d.ts +162 -638
  177. package/package/utils_deployable.js +75 -143
  178. package/package/utils_workspace_deploy.d.ts +10 -4
  179. package/package/utils_workspace_deploy.js +167 -42
  180. package/package.json +7 -3
@@ -20,7 +20,7 @@ import DrawerContent from '../common/drawer/DrawerContent.svelte';
20
20
  import Item from './Item.svelte';
21
21
  import TreeViewRoot from './TreeViewRoot.svelte';
22
22
  import Popover from '../meltComponents/Popover.svelte';
23
- import { getContext, untrack } from 'svelte';
23
+ import { getContext, tick, untrack } from 'svelte';
24
24
  import { triggerableByAI } from '../../actions/triggerableByAI.svelte';
25
25
  import TextInput from '../text_input/TextInput.svelte';
26
26
  let { filter = $bindable(''), subtab = $bindable('script'), showEditButtons = true } = $props();
@@ -215,9 +215,261 @@ let preFilteredItems = $derived(ownerFilter != undefined
215
215
  filterItemsPathsBaseOnUserFilters(x, filterUserFolders, filterUserFoldersType) &&
216
216
  (labelFilter == undefined || ('labels' in x && x.labels?.includes(labelFilter)))));
217
217
  let items = $derived(filter !== '' ? filteredItems : preFilteredItems);
218
+ let displayedItems = $derived((items ?? []).slice(0, nbDisplayed));
218
219
  $effect(() => {
219
220
  items && resetScroll();
220
221
  });
222
+ let selectedIndex = $state(-1);
223
+ let hasMore = $derived(items != undefined && items.length > nbDisplayed);
224
+ let loadMoreIndex = $derived(displayedItems.length);
225
+ let loadMoreEl = $state();
226
+ let pendingAutoSelect = $state(true);
227
+ let firstWorkspaceRun = true;
228
+ $effect(() => {
229
+ $workspaceStore;
230
+ pendingAutoSelect = true;
231
+ if (firstWorkspaceRun) {
232
+ firstWorkspaceRun = false;
233
+ return;
234
+ }
235
+ // On workspace switch, melt-ui restores focus to the workspace-picker trigger
236
+ // button asynchronously after the menu closes. Without overriding it, pressing
237
+ // an arrow key would re-open / re-highlight the workspace picker instead of
238
+ // moving the items-list selection. Run several times to win the focus race.
239
+ const focusSearch = () => {
240
+ const el = document.getElementById('home-search-input');
241
+ el?.focus();
242
+ };
243
+ focusSearch();
244
+ const raf1 = requestAnimationFrame(() => {
245
+ focusSearch();
246
+ requestAnimationFrame(focusSearch);
247
+ });
248
+ const timeoutId = setTimeout(focusSearch, 100);
249
+ return () => {
250
+ cancelAnimationFrame(raf1);
251
+ clearTimeout(timeoutId);
252
+ };
253
+ });
254
+ $effect(() => {
255
+ filter;
256
+ itemKind;
257
+ ownerFilter;
258
+ labelFilter;
259
+ // Skip while pendingAutoSelect is true (initial load / workspace switch);
260
+ // the auto-select effect below will set the index once items appear.
261
+ if (!pendingAutoSelect) {
262
+ selectedIndex = -1;
263
+ }
264
+ });
265
+ $effect(() => {
266
+ if (pendingAutoSelect && displayedItems.length > 0) {
267
+ selectedIndex = 0;
268
+ pendingAutoSelect = false;
269
+ }
270
+ });
271
+ $effect(() => {
272
+ const max = hasMore ? displayedItems.length : displayedItems.length - 1;
273
+ if (selectedIndex > max) {
274
+ selectedIndex = max;
275
+ }
276
+ });
277
+ $effect(() => {
278
+ if (hasMore && selectedIndex === loadMoreIndex) {
279
+ loadMoreEl?.scrollIntoView({ block: 'nearest' });
280
+ }
281
+ });
282
+ // Capture-phase listener so we run before melt-ui's button keydown handlers
283
+ // (e.g. ArrowDown on the dropdown trigger would otherwise open the menu).
284
+ $effect(() => {
285
+ window.addEventListener('keydown', handleGlobalKeydown, true);
286
+ return () => window.removeEventListener('keydown', handleGlobalKeydown, true);
287
+ });
288
+ function loadMoreAndPreselectFirstNew() {
289
+ const previousNbDisplayed = nbDisplayed;
290
+ nbDisplayed += 30;
291
+ selectedIndex = previousNbDisplayed;
292
+ }
293
+ function getSelectedRowActionButtons() {
294
+ const anchor = document.querySelector('a[data-row-keyboard-selected="true"]');
295
+ const actions = anchor?.parentElement?.querySelector('[data-row-actions]');
296
+ return actions ? Array.from(actions.querySelectorAll('button, a[href]')) : [];
297
+ }
298
+ function handleGlobalKeydown(e) {
299
+ if (treeView)
300
+ return;
301
+ const target = e.target;
302
+ // When focus is inside a row's action buttons, handle arrow keys ourselves:
303
+ // - Left/Right cycle between buttons (Left from the first returns to search).
304
+ // - Up/Down move to the same-position button on the previous/next row.
305
+ // All other keys pass through so Enter/Space activate the focused button normally.
306
+ // This must run BEFORE the skipSelector check, since the dropdown ellipsis
307
+ // trigger carries [data-menu] (which would otherwise filter the event out).
308
+ // Up/Down also need stopImmediatePropagation so melt-ui's dropdown trigger
309
+ // doesn't open the menu (its default ArrowDown behavior).
310
+ const actionsContainer = target?.closest('[data-row-actions]');
311
+ if (actionsContainer) {
312
+ if (e.key !== 'ArrowRight' &&
313
+ e.key !== 'ArrowLeft' &&
314
+ e.key !== 'ArrowUp' &&
315
+ e.key !== 'ArrowDown')
316
+ return;
317
+ const buttons = Array.from(actionsContainer.querySelectorAll('button, a[href]'));
318
+ const currentIdx = buttons.indexOf(target);
319
+ if (currentIdx < 0)
320
+ return;
321
+ if (e.key === 'ArrowRight') {
322
+ if (currentIdx < buttons.length - 1) {
323
+ e.preventDefault();
324
+ buttons[currentIdx + 1].focus();
325
+ }
326
+ }
327
+ else if (e.key === 'ArrowLeft') {
328
+ e.preventDefault();
329
+ if (currentIdx > 0) {
330
+ buttons[currentIdx - 1].focus();
331
+ }
332
+ else {
333
+ ;
334
+ document.getElementById('home-search-input')?.focus();
335
+ }
336
+ }
337
+ else {
338
+ // ArrowUp / ArrowDown: move to same-position button on prev/next row.
339
+ e.preventDefault();
340
+ e.stopImmediatePropagation();
341
+ if (selectedIndex < 0 || selectedIndex >= displayedItems.length)
342
+ return;
343
+ const newIndex = e.key === 'ArrowDown'
344
+ ? Math.min(selectedIndex + 1, displayedItems.length - 1)
345
+ : Math.max(selectedIndex - 1, 0);
346
+ if (newIndex === selectedIndex)
347
+ return;
348
+ selectedIndex = newIndex;
349
+ tick().then(() => {
350
+ const newButtons = getSelectedRowActionButtons();
351
+ if (newButtons.length === 0)
352
+ return;
353
+ const targetIdx = Math.min(currentIdx, newButtons.length - 1);
354
+ newButtons[targetIdx]?.focus();
355
+ });
356
+ }
357
+ return;
358
+ }
359
+ // Inside an open dropdown menu: ArrowUp on first item / ArrowDown on last item
360
+ // closes the menu (so users can leave with arrows instead of needing Escape).
361
+ // Other arrow keys fall through to melt-ui's default cycle.
362
+ const menuItem = target?.closest('[role="menuitem"]');
363
+ if (menuItem) {
364
+ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
365
+ const menu = menuItem.closest('[role="menu"]');
366
+ if (menu) {
367
+ const items = Array.from(menu.querySelectorAll('[role="menuitem"]'));
368
+ const idx = items.indexOf(menuItem);
369
+ const isFirst = idx === 0;
370
+ const isLast = idx === items.length - 1;
371
+ if ((e.key === 'ArrowUp' && isFirst) || (e.key === 'ArrowDown' && isLast)) {
372
+ e.preventDefault();
373
+ e.stopImmediatePropagation();
374
+ menuItem.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }));
375
+ }
376
+ }
377
+ }
378
+ return;
379
+ }
380
+ const skipSelector = '[role="menu"], [role="menuitem"], [role="dialog"], [role="listbox"], [role="combobox"], [aria-expanded="true"], [data-menu]';
381
+ if (target) {
382
+ const tag = target.tagName;
383
+ const isEditable = tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target.isContentEditable;
384
+ const isOurSearch = target.id === 'home-search-input';
385
+ if (isEditable && !isOurSearch)
386
+ return;
387
+ if (target.closest(skipSelector))
388
+ return;
389
+ }
390
+ const active = document.activeElement;
391
+ if (active?.closest(skipSelector))
392
+ return;
393
+ // ArrowRight from search input / body → focus first action button of selected row.
394
+ // Guard: if cursor is in the middle of typed search text, let the cursor move.
395
+ if (e.key === 'ArrowRight') {
396
+ if (target?.id === 'home-search-input') {
397
+ const inp = target;
398
+ if (inp.value.length > 0 && inp.selectionEnd !== inp.value.length)
399
+ return;
400
+ }
401
+ if (selectedIndex < 0 || selectedIndex >= displayedItems.length)
402
+ return;
403
+ const buttons = getSelectedRowActionButtons();
404
+ if (buttons.length > 0) {
405
+ e.preventDefault();
406
+ buttons[0].focus();
407
+ }
408
+ return;
409
+ }
410
+ // ArrowLeft from search input with cursor at start: no-op (let default handle).
411
+ if (e.key === 'ArrowLeft') {
412
+ if (target?.id === 'home-search-input') {
413
+ const inp = target;
414
+ if (inp.value.length > 0 && inp.selectionStart !== 0)
415
+ return;
416
+ }
417
+ return;
418
+ }
419
+ if (e.key === 'ArrowDown') {
420
+ if (displayedItems.length === 0)
421
+ return;
422
+ e.preventDefault();
423
+ if (selectedIndex === -1) {
424
+ selectedIndex = 0;
425
+ }
426
+ else if (selectedIndex === loadMoreIndex && hasMore) {
427
+ selectedIndex = 0;
428
+ }
429
+ else if (selectedIndex === displayedItems.length - 1) {
430
+ selectedIndex = hasMore ? loadMoreIndex : 0;
431
+ }
432
+ else {
433
+ selectedIndex = selectedIndex + 1;
434
+ }
435
+ }
436
+ else if (e.key === 'ArrowUp') {
437
+ if (displayedItems.length === 0)
438
+ return;
439
+ e.preventDefault();
440
+ if (selectedIndex === -1) {
441
+ selectedIndex = displayedItems.length - 1;
442
+ }
443
+ else if (selectedIndex === loadMoreIndex && hasMore) {
444
+ selectedIndex = displayedItems.length - 1;
445
+ }
446
+ else if (selectedIndex === 0) {
447
+ selectedIndex = hasMore ? loadMoreIndex : displayedItems.length - 1;
448
+ }
449
+ else {
450
+ selectedIndex = selectedIndex - 1;
451
+ }
452
+ }
453
+ else if (e.key === 'Enter') {
454
+ if (selectedIndex === loadMoreIndex && hasMore) {
455
+ e.preventDefault();
456
+ loadMoreAndPreselectFirstNew();
457
+ }
458
+ else if (selectedIndex >= 0 && selectedIndex < displayedItems.length) {
459
+ const anchor = document.querySelector('a[data-row-keyboard-selected="true"]');
460
+ if (anchor) {
461
+ e.preventDefault();
462
+ anchor.click();
463
+ }
464
+ }
465
+ }
466
+ else if (e.key === 'Escape') {
467
+ if (selectedIndex !== -1) {
468
+ e.preventDefault();
469
+ selectedIndex = -1;
470
+ }
471
+ }
472
+ }
221
473
  $effect(() => {
222
474
  storeLocalSetting(TREE_VIEW_SETTING_NAME, treeView ? 'true' : undefined);
223
475
  });
@@ -461,7 +713,7 @@ $effect(() => {
461
713
  />
462
714
  {:else}
463
715
  <div class="border rounded-md bg-surface-tertiary">
464
- {#each (items ?? []).slice(0, nbDisplayed) as item (item.type + '/' + item.path + (item.hash ? '/' + item.hash : ''))}
716
+ {#each displayedItems as item, i (item.type + '/' + item.path + (item.hash ? '/' + item.hash : ''))}
465
717
  <Item
466
718
  {item}
467
719
  on:scriptChanged={() => loadScripts(includeWithoutMain)}
@@ -476,6 +728,7 @@ $effect(() => {
476
728
  }}
477
729
  {showCode}
478
730
  showEditButton={showEditButtons}
731
+ keyboardSelected={selectedIndex === i}
479
732
  />
480
733
  {/each}
481
734
  </div>
@@ -483,7 +736,11 @@ $effect(() => {
483
736
  <span class="text-xs font-normal text-secondary"
484
737
  >{nbDisplayed} items out of {items.length}
485
738
  <button
486
- class="ml-4 text-xs font-normal text-primary hover:text-emphasis"
739
+ bind:this={loadMoreEl}
740
+ class="ml-4 text-xs font-normal text-primary hover:text-emphasis rounded px-1 {selectedIndex ===
741
+ loadMoreIndex
742
+ ? 'bg-gray-200 dark:bg-gray-700 underline'
743
+ : ''}"
487
744
  onclick={() => (nbDisplayed += 30)}>load 30 more</button
488
745
  ></span
489
746
  >