@svadmin/ui 0.70.0 → 0.73.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.
- package/README.md +40 -25
- package/THIRD_PARTY_NOTICES.md +52 -0
- package/dist/actions.js +1 -1
- package/dist/app.css +7804 -5188
- package/dist/app.theme.css +7738 -5173
- package/dist/class-properties.generated.d.ts +1 -0
- package/dist/class-properties.generated.js +2 -0
- package/dist/classnames.d.ts +8 -0
- package/dist/classnames.js +26 -0
- package/dist/component-registry.svelte.d.ts +33 -19
- package/dist/component-registry.svelte.js +6 -4
- package/dist/components/AdminApp.svelte +55 -53
- package/dist/components/AdminApp.svelte.d.ts +2 -2
- package/dist/components/ApiSettings.svelte +19 -1
- package/dist/components/AuditLogDrawer.svelte +14 -3
- package/dist/components/AutoForm.svelte +162 -50
- package/dist/components/AutoForm.svelte.d.ts +4 -0
- package/dist/components/AutoTable.svelte +599 -259
- package/dist/components/AutoTable.svelte.d.ts +6 -0
- package/dist/components/BoundRecordDetailDrawer.svelte +172 -0
- package/dist/components/BoundRecordDetailDrawer.svelte.d.ts +11 -0
- package/dist/components/Breadcrumbs.svelte +7 -4
- package/dist/components/CancelTaskButton.svelte +9 -5
- package/dist/components/ColumnHeaderFilter.svelte +4 -3
- package/dist/components/ColumnSettings.svelte +1 -0
- package/dist/components/ComboboxField.svelte +118 -36
- package/dist/components/ComboboxField.svelte.d.ts +5 -4
- package/dist/components/CreatePage.svelte +7 -1
- package/dist/components/CreatePage.svelte.d.ts +2 -0
- package/dist/components/DateRangeInput.svelte +75 -0
- package/dist/components/DateRangeInput.svelte.d.ts +25 -0
- package/dist/components/DateTimeInput.svelte +65 -0
- package/dist/components/DateTimeInput.svelte.d.ts +19 -0
- package/dist/components/DetailDrawer.svelte +4 -0
- package/dist/components/DetailDrawer.svelte.d.ts +1 -0
- package/dist/components/DevTools.svelte +8 -21
- package/dist/components/DraggableGrid.svelte +1 -0
- package/dist/components/DraggableHeader.svelte +5 -9
- package/dist/components/DraggableHeader.svelte.d.ts +43 -18
- package/dist/components/DraggableRowTable.svelte +2 -2
- package/dist/components/DynamicFormList.svelte +17 -17
- package/dist/components/DynamicFormList.svelte.d.ts +2 -1
- package/dist/components/EditPage.svelte +7 -1
- package/dist/components/EditPage.svelte.d.ts +2 -0
- package/dist/components/EditableTable.svelte +4 -0
- package/dist/components/ErrorPage.svelte +3 -1
- package/dist/components/FieldDisplay.svelte +14 -0
- package/dist/components/FieldDisplay.svelte.d.ts +7 -0
- package/dist/components/FieldRenderer.svelte +96 -20
- package/dist/components/FileUpload.svelte +250 -0
- package/dist/components/FileUpload.svelte.d.ts +32 -0
- package/dist/components/FilterBuilder.svelte +236 -268
- package/dist/components/FilterBuilder.svelte.d.ts +3 -0
- package/dist/components/FilterDropdown.svelte.d.ts +1 -1
- package/dist/components/Header.svelte +5 -6
- package/dist/components/ImportWizard.svelte +182 -94
- package/dist/components/InfiniteList.svelte +22 -8
- package/dist/components/InfiniteList.svelte.d.ts +5 -3
- package/dist/components/InlineEdit.svelte +114 -44
- package/dist/components/JsonSchemaForm.svelte +256 -95
- package/dist/components/JsonSchemaForm.svelte.d.ts +12 -1
- package/dist/components/Layout.svelte +20 -17
- package/dist/components/LazyTaskQueueDrawer.svelte +26 -0
- package/dist/components/LazyTaskQueueDrawer.svelte.d.ts +8 -0
- package/dist/components/ListPage.svelte +11 -6
- package/dist/components/ListPage.svelte.d.ts +2 -0
- package/dist/components/LoginPage.svelte +1 -1
- package/dist/components/MasterDetailView.svelte +3 -3
- package/dist/components/MediaLibraryModal.svelte +5 -2
- package/dist/components/MentionsInput.svelte +4 -3
- package/dist/components/MoneyInput.svelte +25 -0
- package/dist/components/MoneyInput.svelte.d.ts +20 -0
- package/dist/components/NavigateToResource.svelte +3 -2
- package/dist/components/NumberInput.svelte +25 -0
- package/dist/components/NumberInput.svelte.d.ts +19 -0
- package/dist/components/NumericInput.svelte +110 -0
- package/dist/components/NumericInput.svelte.d.ts +23 -0
- package/dist/components/PercentInput.svelte +25 -0
- package/dist/components/PercentInput.svelte.d.ts +20 -0
- package/dist/components/PermissionMatrix.svelte +4 -3
- package/dist/components/ProfilePage.svelte +2 -2
- package/dist/components/QuickEditDrawer.svelte +42 -0
- package/dist/components/QuickEditDrawer.svelte.d.ts +10 -0
- package/dist/components/RecordDetailDrawer.svelte +16 -108
- package/dist/components/RecordDetailDrawer.svelte.d.ts +2 -0
- package/dist/components/RecordRowActions.svelte +41 -0
- package/dist/components/RecordRowActions.svelte.d.ts +14 -0
- package/dist/components/ResourceAccessGuard.svelte +7 -5
- package/dist/components/ResourceOperationsPage.svelte +25 -19
- package/dist/components/ResourceOperationsPage.svelte.d.ts +5 -1
- package/dist/components/RetryTaskButton.svelte +9 -5
- package/dist/components/RowActions.svelte +5 -3
- package/dist/components/SensitiveDataMask.svelte +3 -3
- package/dist/components/SettingsPage.svelte +1 -1
- package/dist/components/ShowInferencer.svelte +4 -2
- package/dist/components/ShowInferencer.svelte.d.ts +2 -0
- package/dist/components/ShowPage.svelte +49 -39
- package/dist/components/ShowPage.svelte.d.ts +2 -0
- package/dist/components/Sidebar.svelte +15 -13
- package/dist/components/SplitPaneLayout.svelte +4 -2
- package/dist/components/SpreadsheetView.svelte +81 -286
- package/dist/components/StepsForm.svelte +166 -49
- package/dist/components/StepsForm.svelte.d.ts +1 -0
- package/dist/components/SvarAutoTable.svelte +39 -0
- package/dist/components/SvarAutoTable.svelte.d.ts +13 -0
- package/dist/components/SvarDataGrid.svelte +362 -0
- package/dist/components/SvarDataGrid.svelte.d.ts +57 -0
- package/dist/components/SvarGridCell.svelte +10 -0
- package/dist/components/SvarGridCell.svelte.d.ts +7 -0
- package/dist/components/SvarResourceRead.svelte +50 -0
- package/dist/components/SvarResourceRead.svelte.d.ts +23 -0
- package/dist/components/SvarResourceTable.svelte +63 -0
- package/dist/components/SvarResourceTable.svelte.d.ts +42 -0
- package/dist/components/SvarResourceTableView.svelte +364 -0
- package/dist/components/SvarResourceTableView.svelte.d.ts +4 -0
- package/dist/components/TaskDetails.svelte +20 -7
- package/dist/components/TaskList.svelte +19 -7
- package/dist/components/TaskQueueDrawer.svelte +92 -37
- package/dist/components/Toast.svelte +4 -2
- package/dist/components/TooltipButton.svelte +1 -1
- package/dist/components/TreeSelect.svelte +212 -30
- package/dist/components/TreeSelect.svelte.d.ts +3 -1
- package/dist/components/ValidatedField.svelte +27 -0
- package/dist/components/ValidatedField.svelte.d.ts +35 -0
- package/dist/components/account/ImportMembersPage.svelte +2 -2
- package/dist/components/account/SecurityLogPage.svelte +3 -1
- package/dist/components/account/SettingsEnterprisePage.svelte +7 -5
- package/dist/components/account/TeamMembersPage.svelte +1 -1
- package/dist/components/auto-table-grid.d.ts +26 -0
- package/dist/components/auto-table-grid.js +1 -0
- package/dist/components/buttons/CloneButton.svelte +6 -4
- package/dist/components/buttons/DeleteButton.svelte +95 -29
- package/dist/components/buttons/DeleteButton.svelte.d.ts +2 -0
- package/dist/components/buttons/EditButton.svelte +6 -4
- package/dist/components/buttons/ExportButton.svelte +22 -4
- package/dist/components/buttons/ImportButton.svelte +83 -38
- package/dist/components/buttons/ImportButton.svelte.d.ts +6 -10
- package/dist/components/buttons/RefreshButton.svelte +48 -8
- package/dist/components/buttons/ShowButton.svelte +6 -4
- package/dist/components/content/ApiKeyList.svelte +3 -1
- package/dist/components/content/ContentPageHeader.svelte +12 -9
- package/dist/components/content/ContentPageShell.svelte +8 -9
- package/dist/components/content/FileBrowser.svelte +35 -0
- package/dist/components/content/FileBrowser.svelte.d.ts +14 -0
- package/dist/components/content/FileList.svelte +3 -1
- package/dist/components/content/MemberList.svelte +3 -1
- package/dist/components/content/MetricBlock.svelte +10 -13
- package/dist/components/content/NetworkTable.svelte +6 -4
- package/dist/components/content/NetworkTable.svelte.d.ts +1 -0
- package/dist/components/content/PageToolbar.svelte +6 -10
- package/dist/components/content/SectionHeader.svelte +8 -13
- package/dist/components/content/SecurityEventTable.svelte +3 -1
- package/dist/components/content/SettingsFieldRow.svelte +9 -23
- package/dist/components/content/SettingsGroup.svelte +11 -27
- package/dist/components/content/StatusBadge.svelte +3 -8
- package/dist/components/content/StatusTabs.svelte +2 -2
- package/dist/components/content/WorkspaceLayout.svelte +8 -12
- package/dist/components/enterprise/filter-tree.d.ts +48 -0
- package/dist/components/enterprise/filter-tree.js +224 -0
- package/dist/components/enterprise/json-schema-form.d.ts +39 -0
- package/dist/components/enterprise/json-schema-form.js +195 -0
- package/dist/components/enterprise/recursive-schema-form.d.ts +30 -0
- package/dist/components/enterprise/recursive-schema-form.js +196 -0
- package/dist/components/enterprise/spreadsheet-formula.d.ts +12 -0
- package/dist/components/enterprise/spreadsheet-formula.js +245 -0
- package/dist/components/fieldComponentMap.d.ts +18 -13
- package/dist/components/fieldComponentMap.js +100 -47
- package/dist/components/fields/AvatarField.svelte +1 -1
- package/dist/components/fields/ChoiceField.svelte +16 -0
- package/dist/components/fields/ChoiceField.svelte.d.ts +10 -0
- package/dist/components/fields/CodeField.svelte +11 -12
- package/dist/components/fields/CodeField.svelte.d.ts +1 -1
- package/dist/components/fields/DateField.svelte +4 -3
- package/dist/components/fields/DateRangeField.svelte +2 -4
- package/dist/components/fields/ImageField.svelte +3 -1
- package/dist/components/fields/ImagesField.svelte +23 -0
- package/dist/components/fields/ImagesField.svelte.d.ts +6 -0
- package/dist/components/fields/JsonField.svelte +19 -13
- package/dist/components/fields/PasswordField.svelte +5 -0
- package/dist/components/fields/PasswordField.svelte.d.ts +6 -0
- package/dist/components/fields/date-field-value.d.ts +2 -0
- package/dist/components/fields/date-field-value.js +13 -0
- package/dist/components/fields/json-value.d.ts +11 -0
- package/dist/components/fields/json-value.js +28 -0
- package/dist/components/json-schema-form-state.d.ts +37 -0
- package/dist/components/json-schema-form-state.js +168 -0
- package/dist/components/profile/ActivityTimeline.svelte +2 -2
- package/dist/components/record-detail.svelte.d.ts +19 -0
- package/dist/components/record-detail.svelte.js +34 -0
- package/dist/components/saved-list-views.js +29 -29
- package/dist/components/svar-grid-cells.d.ts +14 -0
- package/dist/components/svar-grid-cells.js +2 -0
- package/dist/components/svar-grid-contract.d.ts +80 -0
- package/dist/components/svar-grid-contract.js +159 -0
- package/dist/components/svar-grid-interactions.d.ts +54 -0
- package/dist/components/svar-grid-interactions.js +174 -0
- package/dist/components/svar-grid-loading.d.ts +40 -0
- package/dist/components/svar-grid-loading.js +180 -0
- package/dist/components/svar-grid-operations.d.ts +37 -0
- package/dist/components/svar-grid-operations.js +186 -0
- package/dist/components/svar-grid-panes.d.ts +34 -0
- package/dist/components/svar-grid-panes.js +66 -0
- package/dist/components/svar-grid-resource-loading.d.ts +18 -0
- package/dist/components/svar-grid-resource-loading.js +68 -0
- package/dist/components/svar-grid-resource-session.svelte.d.ts +29 -0
- package/dist/components/svar-grid-resource-session.svelte.js +61 -0
- package/dist/components/table-contract.d.ts +13 -0
- package/dist/components/table-contract.js +42 -0
- package/dist/components/task-utils.js +4 -2
- package/dist/components/ui/alert/alert-variants.d.ts +2 -3
- package/dist/components/ui/alert/alert-variants.js +1 -2
- package/dist/components/ui/alert/alert.svelte +4 -5
- package/dist/components/ui/alert/alert.svelte.d.ts +3 -8
- package/dist/components/ui/alert/index.js +0 -2
- package/dist/components/ui/avatar/avatar-variants.d.ts +2 -3
- package/dist/components/ui/avatar/avatar-variants.js +1 -2
- package/dist/components/ui/avatar/avatar.svelte +5 -6
- package/dist/components/ui/avatar/avatar.svelte.d.ts +3 -8
- package/dist/components/ui/badge/badge-variants.d.ts +2 -3
- package/dist/components/ui/badge/badge-variants.js +3 -2
- package/dist/components/ui/badge/badge.svelte +4 -5
- package/dist/components/ui/badge/badge.svelte.d.ts +3 -8
- package/dist/components/ui/badge/index.js +0 -2
- package/dist/components/ui/button/button-variants.d.ts +2 -3
- package/dist/components/ui/button/button-variants.js +5 -3
- package/dist/components/ui/button/button.svelte +100 -44
- package/dist/components/ui/button/button.svelte.d.ts +8 -12
- package/dist/components/ui/button/index.js +0 -2
- package/dist/components/ui/command/command-dialog.svelte +3 -1
- package/dist/components/ui/command/command-dialog.svelte.d.ts +1 -1
- package/dist/components/ui/command/command-group.svelte +4 -2
- package/dist/components/ui/command/command-item.svelte +4 -2
- package/dist/components/ui/command/command-separator.svelte +3 -1
- package/dist/components/ui/command/index.d.ts +5 -5
- package/dist/components/ui/input/input.svelte +41 -24
- package/dist/components/ui/input/input.svelte.d.ts +5 -4
- package/dist/components/ui/sheet/sheet.svelte +9 -3
- package/dist/components/ui/sheet/sheet.svelte.d.ts +1 -0
- package/dist/components/ui/textarea/textarea.svelte +2 -1
- package/dist/components/ui/tooltip/tooltip.svelte +4 -2
- package/dist/components.css +3079 -0
- package/dist/design-contract.d.ts +13 -0
- package/dist/design-contract.js +11 -0
- package/dist/design-system.d.ts +15 -0
- package/dist/design-system.js +7 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.js +9 -0
- package/dist/inline-value.d.ts +5 -0
- package/dist/inline-value.js +24 -0
- package/dist/numeric-input.d.ts +2 -0
- package/dist/numeric-input.js +9 -0
- package/dist/page-chrome.css +12 -49
- package/dist/recipes.d.ts +4 -0
- package/dist/recipes.js +4 -0
- package/dist/rendering/index.d.ts +87 -0
- package/dist/rendering/index.js +117 -0
- package/dist/styled-system/css/conditions.js +36 -0
- package/dist/styled-system/css/css.d.ts +22 -0
- package/dist/styled-system/css/css.js +45 -0
- package/dist/styled-system/css/cva.d.ts +6 -0
- package/dist/styled-system/css/cva.js +87 -0
- package/dist/styled-system/css/cx.d.ts +5 -0
- package/dist/styled-system/css/cx.js +15 -0
- package/dist/styled-system/css/index.d.ts +5 -0
- package/dist/styled-system/css/index.js +4 -0
- package/dist/styled-system/css/sva.d.ts +4 -0
- package/dist/styled-system/css/sva.js +46 -0
- package/dist/styled-system/helpers.js +316 -0
- package/dist/styled-system/patterns/aspect-ratio.d.ts +20 -0
- package/dist/styled-system/patterns/aspect-ratio.js +38 -0
- package/dist/styled-system/patterns/bleed.d.ts +21 -0
- package/dist/styled-system/patterns/bleed.js +24 -0
- package/dist/styled-system/patterns/box.d.ts +20 -0
- package/dist/styled-system/patterns/box.js +15 -0
- package/dist/styled-system/patterns/center.d.ts +20 -0
- package/dist/styled-system/patterns/center.js +21 -0
- package/dist/styled-system/patterns/circle.d.ts +20 -0
- package/dist/styled-system/patterns/circle.js +25 -0
- package/dist/styled-system/patterns/container.d.ts +20 -0
- package/dist/styled-system/patterns/container.js +21 -0
- package/dist/styled-system/patterns/cq.d.ts +21 -0
- package/dist/styled-system/patterns/cq.js +21 -0
- package/dist/styled-system/patterns/divider.d.ts +22 -0
- package/dist/styled-system/patterns/divider.js +25 -0
- package/dist/styled-system/patterns/flex.d.ts +26 -0
- package/dist/styled-system/patterns/flex.js +26 -0
- package/dist/styled-system/patterns/float.d.ts +23 -0
- package/dist/styled-system/patterns/float.js +52 -0
- package/dist/styled-system/patterns/grid-item.d.ts +25 -0
- package/dist/styled-system/patterns/grid-item.js +25 -0
- package/dist/styled-system/patterns/grid.d.ts +24 -0
- package/dist/styled-system/patterns/grid.js +27 -0
- package/dist/styled-system/patterns/hstack.d.ts +21 -0
- package/dist/styled-system/patterns/hstack.js +24 -0
- package/dist/styled-system/patterns/index.d.ts +21 -0
- package/dist/styled-system/patterns/index.js +20 -0
- package/dist/styled-system/patterns/link-overlay.d.ts +20 -0
- package/dist/styled-system/patterns/link-overlay.js +24 -0
- package/dist/styled-system/patterns/spacer.d.ts +20 -0
- package/dist/styled-system/patterns/spacer.js +25 -0
- package/dist/styled-system/patterns/square.d.ts +20 -0
- package/dist/styled-system/patterns/square.js +24 -0
- package/dist/styled-system/patterns/stack.d.ts +23 -0
- package/dist/styled-system/patterns/stack.js +24 -0
- package/dist/styled-system/patterns/visually-hidden.d.ts +20 -0
- package/dist/styled-system/patterns/visually-hidden.js +18 -0
- package/dist/styled-system/patterns/vstack.d.ts +21 -0
- package/dist/styled-system/patterns/vstack.js +24 -0
- package/dist/styled-system/patterns/wrap.d.ts +24 -0
- package/dist/styled-system/patterns/wrap.js +25 -0
- package/dist/styled-system/recipes/content-header.d.ts +31 -0
- package/dist/styled-system/recipes/content-header.js +65 -0
- package/dist/styled-system/recipes/content-page.d.ts +34 -0
- package/dist/styled-system/recipes/content-page.js +43 -0
- package/dist/styled-system/recipes/create-recipe.js +82 -0
- package/dist/styled-system/recipes/index.d.ts +17 -0
- package/dist/styled-system/recipes/index.js +16 -0
- package/dist/styled-system/recipes/metric-block.d.ts +34 -0
- package/dist/styled-system/recipes/metric-block.js +76 -0
- package/dist/styled-system/recipes/product-list.d.ts +31 -0
- package/dist/styled-system/recipes/product-list.js +73 -0
- package/dist/styled-system/recipes/product-section.d.ts +31 -0
- package/dist/styled-system/recipes/product-section.js +49 -0
- package/dist/styled-system/recipes/product-settings-row.d.ts +34 -0
- package/dist/styled-system/recipes/product-settings-row.js +58 -0
- package/dist/styled-system/recipes/product-settings.d.ts +31 -0
- package/dist/styled-system/recipes/product-settings.js +57 -0
- package/dist/styled-system/recipes/product-status.d.ts +34 -0
- package/dist/styled-system/recipes/product-status.js +45 -0
- package/dist/styled-system/recipes/product-toolbar.d.ts +31 -0
- package/dist/styled-system/recipes/product-toolbar.js +41 -0
- package/dist/styled-system/recipes/product-workspace.d.ts +34 -0
- package/dist/styled-system/recipes/product-workspace.js +58 -0
- package/dist/styled-system/recipes/surface-metric.d.ts +38 -0
- package/dist/styled-system/recipes/surface-metric.js +63 -0
- package/dist/styled-system/recipes/surface-table.d.ts +34 -0
- package/dist/styled-system/recipes/surface-table.js +62 -0
- package/dist/styled-system/recipes/ui-badge.d.ts +31 -0
- package/dist/styled-system/recipes/ui-badge.js +38 -0
- package/dist/styled-system/recipes/ui-button.d.ts +32 -0
- package/dist/styled-system/recipes/ui-button.js +43 -0
- package/dist/styled-system/recipes/ui-input.d.ts +31 -0
- package/dist/styled-system/recipes/ui-input.js +49 -0
- package/dist/styled-system/recipes/ui-textarea.d.ts +31 -0
- package/dist/styled-system/recipes/ui-textarea.js +24 -0
- package/dist/styled-system/styles.css +1257 -0
- package/dist/styled-system/tokens/index.d.ts +9 -0
- package/dist/styled-system/tokens/index.js +268 -0
- package/dist/styled-system/tokens/tokens.d.ts +36 -0
- package/dist/styled-system/types/composition.d.ts +227 -0
- package/dist/styled-system/types/conditions.d.ts +236 -0
- package/dist/styled-system/types/csstype.d.ts +22570 -0
- package/dist/styled-system/types/index.d.ts +6 -0
- package/dist/styled-system/types/parts.d.ts +8 -0
- package/dist/styled-system/types/pattern.d.ts +78 -0
- package/dist/styled-system/types/prop-type.d.ts +223 -0
- package/dist/styled-system/types/recipe.d.ts +181 -0
- package/dist/styled-system/types/selectors.d.ts +59 -0
- package/dist/styled-system/types/static-css.d.ts +56 -0
- package/dist/styled-system/types/style-props.d.ts +8088 -0
- package/dist/styled-system/types/system-types.d.ts +151 -0
- package/dist/styles/aliases.css +49 -0
- package/dist/styles/compatibility.epilogue.css +384 -0
- package/dist/styles/compatibility.prelude.css +5513 -0
- package/dist/styles/conditional-states.css +28 -0
- package/dist/styles/conditional-utilities.css +22 -0
- package/dist/styles/recipes.css +1262 -0
- package/dist/types.d.ts +3 -3
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +1 -1
- package/package.json +38 -14
- package/styles-compatibility.json +12 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { onDestroy } from 'svelte';
|
|
3
|
+
import { definedReactiveOptions, definedOptions } from '@svadmin/core/options';
|
|
4
|
+
|
|
2
5
|
import { ListTodo, Loader2, Plus, Search, RefreshCw } from '@lucide/svelte';
|
|
3
|
-
import {
|
|
6
|
+
import { captureAdminContext, captureAuthSession, useSubmitTask, useTaskList } from '@svadmin/core';
|
|
7
|
+
import { decodeTaskSubmitOptions } from '@svadmin/core/schema';
|
|
4
8
|
import { useTranslation } from '@svadmin/core/i18n';
|
|
5
9
|
import type { TaskProvider, TaskRecord } from '@svadmin/core';
|
|
6
10
|
import { Button } from './ui/button/index.js';
|
|
@@ -22,13 +26,14 @@
|
|
|
22
26
|
} from './task-utils.js';
|
|
23
27
|
|
|
24
28
|
const i18n = useTranslation();
|
|
29
|
+
const context = captureAdminContext();
|
|
25
30
|
|
|
26
31
|
type AutoRefreshValue = '0' | '5000' | '15000' | '30000';
|
|
27
32
|
type TaskTab = 'tasks' | 'dlq';
|
|
28
33
|
|
|
29
34
|
let {
|
|
30
35
|
open = $bindable(false),
|
|
31
|
-
taskProvider
|
|
36
|
+
taskProvider,
|
|
32
37
|
title,
|
|
33
38
|
initialTab = 'tasks',
|
|
34
39
|
}: {
|
|
@@ -38,8 +43,7 @@
|
|
|
38
43
|
initialTab?: TaskTab;
|
|
39
44
|
} = $props();
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
let activeTab = $state<TaskTab>('tasks');
|
|
46
|
+
let activeTab = $derived(initialTab);
|
|
43
47
|
let selectedTaskId = $state<string | null>(null);
|
|
44
48
|
let searchQuery = $state('');
|
|
45
49
|
let statusFilter = $state('all');
|
|
@@ -49,40 +53,79 @@
|
|
|
49
53
|
let submitBodyText = $state(i18n.t('task.bodyPlaceholder'));
|
|
50
54
|
let submitError = $state<string | null>(null);
|
|
51
55
|
let submitOpen = $state(false);
|
|
56
|
+
let submitAttempt = $state.raw<object | null>(null);
|
|
57
|
+
let mounted = true;
|
|
58
|
+
onDestroy(() => { mounted = false; submitAttempt = null; });
|
|
59
|
+
const activeTaskProvider = $derived(taskProvider ?? context.taskProvider);
|
|
60
|
+
const taskScope = $derived({
|
|
61
|
+
provider: activeTaskProvider,
|
|
62
|
+
tenant: context.tenantCacheKey?.__svadminTenant,
|
|
63
|
+
auth: context.authProvider,
|
|
64
|
+
router: context.routerProvider,
|
|
65
|
+
session: captureAuthSession(context.authProvider),
|
|
66
|
+
});
|
|
67
|
+
let previousTaskScope: typeof taskScope | undefined;
|
|
68
|
+
function taskScopesEqual(left: typeof taskScope, right: typeof taskScope): boolean {
|
|
69
|
+
return left.provider === right.provider
|
|
70
|
+
&& left.tenant === right.tenant
|
|
71
|
+
&& left.auth === right.auth
|
|
72
|
+
&& left.router === right.router
|
|
73
|
+
&& left.session.cacheKey === right.session.cacheKey
|
|
74
|
+
&& left.session.available === right.session.available;
|
|
75
|
+
}
|
|
76
|
+
function taskScopeIsCurrent(origin: typeof taskScope): boolean {
|
|
77
|
+
return mounted && taskScopesEqual(origin, taskScope) && origin.session.isCurrent();
|
|
78
|
+
}
|
|
79
|
+
$effect.pre(() => {
|
|
80
|
+
const scope = taskScope;
|
|
81
|
+
if (previousTaskScope && !taskScopesEqual(previousTaskScope, scope)) {
|
|
82
|
+
selectedTaskId = null;
|
|
83
|
+
submitAttempt = null;
|
|
84
|
+
submitOpen = false;
|
|
85
|
+
resetSubmitForm();
|
|
86
|
+
}
|
|
87
|
+
previousTaskScope = scope;
|
|
88
|
+
});
|
|
89
|
+
$effect.pre(() => {
|
|
90
|
+
if (!open) {
|
|
91
|
+
submitAttempt = null;
|
|
92
|
+
submitOpen = false;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
52
95
|
|
|
53
96
|
const refreshInterval = $derived.by<number | false>(() =>
|
|
54
97
|
autoRefresh === '0' ? false : Number(autoRefresh),
|
|
55
98
|
);
|
|
56
99
|
const resolvedTitle = $derived(title ?? i18n.t('task.drawerTitle'));
|
|
57
100
|
|
|
58
|
-
const taskQuery = useTaskList({
|
|
101
|
+
const taskQuery = useTaskList(definedReactiveOptions({
|
|
59
102
|
get taskProvider() {
|
|
60
|
-
return
|
|
103
|
+
return activeTaskProvider;
|
|
61
104
|
},
|
|
62
105
|
get queryOptions() {
|
|
63
106
|
return {
|
|
64
|
-
enabled: !!
|
|
107
|
+
enabled: !!activeTaskProvider,
|
|
65
108
|
refetchInterval: refreshInterval,
|
|
66
109
|
refetchIntervalInBackground: true,
|
|
67
110
|
};
|
|
68
111
|
},
|
|
69
|
-
});
|
|
112
|
+
}));
|
|
70
113
|
|
|
71
|
-
const dlqQuery = useTaskList({
|
|
114
|
+
const dlqQuery = useTaskList(definedReactiveOptions({
|
|
72
115
|
get dlq() {
|
|
73
116
|
return true;
|
|
74
117
|
},
|
|
75
118
|
get taskProvider() {
|
|
76
|
-
return
|
|
119
|
+
return activeTaskProvider;
|
|
77
120
|
},
|
|
78
121
|
get queryOptions() {
|
|
79
122
|
return {
|
|
80
|
-
enabled: !!
|
|
123
|
+
enabled: !!activeTaskProvider && !!activeTaskProvider?.listDlq,
|
|
81
124
|
refetchInterval: refreshInterval,
|
|
82
125
|
refetchIntervalInBackground: true,
|
|
83
126
|
};
|
|
84
127
|
},
|
|
85
|
-
});
|
|
128
|
+
}));
|
|
86
129
|
|
|
87
130
|
const submitTask = useSubmitTask();
|
|
88
131
|
|
|
@@ -123,10 +166,6 @@
|
|
|
123
166
|
allTasks.filter(isTaskActive).length,
|
|
124
167
|
);
|
|
125
168
|
|
|
126
|
-
$effect(() => {
|
|
127
|
-
activeTab = initialTab;
|
|
128
|
-
});
|
|
129
|
-
|
|
130
169
|
$effect(() => {
|
|
131
170
|
if (statusFilter !== 'all' && !availableStatuses.includes(statusFilter)) {
|
|
132
171
|
statusFilter = 'all';
|
|
@@ -141,19 +180,19 @@
|
|
|
141
180
|
}
|
|
142
181
|
|
|
143
182
|
if (!selectedTaskId) {
|
|
144
|
-
selectedTaskId = current[0]
|
|
183
|
+
selectedTaskId = current[0]?.id ?? null;
|
|
145
184
|
return;
|
|
146
185
|
}
|
|
147
186
|
|
|
148
187
|
if (!current.some((task) => task.id === selectedTaskId)) {
|
|
149
|
-
selectedTaskId = current[0]
|
|
188
|
+
selectedTaskId = current[0]?.id ?? null;
|
|
150
189
|
}
|
|
151
190
|
});
|
|
152
191
|
|
|
153
192
|
function formatTime(value: unknown) {
|
|
154
|
-
if (!value) return '—';
|
|
155
|
-
const date = new Date(value
|
|
156
|
-
if (Number.isNaN(date.getTime())) return
|
|
193
|
+
if (typeof value !== 'string' || !value) return '—';
|
|
194
|
+
const date = new Date(value);
|
|
195
|
+
if (Number.isNaN(date.getTime())) return '—';
|
|
157
196
|
return date.toLocaleString();
|
|
158
197
|
}
|
|
159
198
|
|
|
@@ -164,7 +203,14 @@
|
|
|
164
203
|
submitError = null;
|
|
165
204
|
}
|
|
166
205
|
|
|
206
|
+
function toggleSubmitForm(): void {
|
|
207
|
+
submitAttempt = null;
|
|
208
|
+
submitError = null;
|
|
209
|
+
submitOpen = !submitOpen;
|
|
210
|
+
}
|
|
211
|
+
|
|
167
212
|
async function handleSubmitTask() {
|
|
213
|
+
if (!open || !submitOpen || submitAttempt || !activeTaskProvider || !taskScope.session.available) return;
|
|
168
214
|
submitError = null;
|
|
169
215
|
if (!submitTaskName.trim()) {
|
|
170
216
|
submitError = i18n.t('validation.required');
|
|
@@ -174,32 +220,41 @@
|
|
|
174
220
|
let body: Record<string, unknown> | undefined;
|
|
175
221
|
if (submitBodyText.trim()) {
|
|
176
222
|
try {
|
|
177
|
-
|
|
223
|
+
const parsed: unknown = JSON.parse(submitBodyText);
|
|
224
|
+
body = decodeTaskSubmitOptions({ body: parsed }).body;
|
|
178
225
|
} catch {
|
|
179
226
|
submitError = i18n.t('task.invalidJson');
|
|
180
227
|
return;
|
|
181
228
|
}
|
|
182
229
|
}
|
|
183
230
|
|
|
231
|
+
const origin = taskScope;
|
|
232
|
+
const attempt = {};
|
|
233
|
+
submitAttempt = attempt;
|
|
234
|
+
const current = () => submitAttempt === attempt && taskScopeIsCurrent(origin);
|
|
184
235
|
try {
|
|
185
|
-
const handle = await submitTask.mutation.mutateAsync({
|
|
236
|
+
const handle = await submitTask.mutation.mutateAsync(definedOptions({
|
|
186
237
|
taskName: submitTaskName.trim(),
|
|
187
|
-
taskProvider,
|
|
188
|
-
options: {
|
|
238
|
+
taskProvider: activeTaskProvider,
|
|
239
|
+
options: definedOptions({
|
|
189
240
|
body,
|
|
190
241
|
idempotencyKey: submitIdempotencyKey.trim() || undefined,
|
|
191
|
-
},
|
|
192
|
-
});
|
|
242
|
+
}),
|
|
243
|
+
}));
|
|
244
|
+
if (!current()) return;
|
|
193
245
|
activeTab = 'tasks';
|
|
194
|
-
selectedTaskId = handle.id
|
|
246
|
+
selectedTaskId = handle.id;
|
|
195
247
|
submitOpen = false;
|
|
196
248
|
resetSubmitForm();
|
|
197
|
-
await Promise.
|
|
249
|
+
await Promise.allSettled([
|
|
198
250
|
taskQuery.refetch?.(),
|
|
199
251
|
dlqQuery.refetch?.(),
|
|
200
252
|
]);
|
|
201
253
|
} catch (error) {
|
|
254
|
+
if (!current()) return;
|
|
202
255
|
submitError = error instanceof Error ? error.message : i18n.t('task.submitFailed');
|
|
256
|
+
} finally {
|
|
257
|
+
if (submitAttempt === attempt) submitAttempt = null;
|
|
203
258
|
}
|
|
204
259
|
}
|
|
205
260
|
|
|
@@ -250,7 +305,7 @@
|
|
|
250
305
|
</div>
|
|
251
306
|
</div>
|
|
252
307
|
|
|
253
|
-
{#if !
|
|
308
|
+
{#if !activeTaskProvider}
|
|
254
309
|
<div class="svadmin-u-60fbb7713999 svadmin-u-36e579c0b41c svadmin-u-3960ffc248d9 svadmin-u-86843cf1e227 svadmin-u-0478c89a150f svadmin-u-fc7473ca09eb svadmin-u-bfa603190748">
|
|
255
310
|
{i18n.t('common.configRequired')}
|
|
256
311
|
</div>
|
|
@@ -277,7 +332,7 @@
|
|
|
277
332
|
<RefreshCw class="svadmin-u-82cc6c6581cd svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
278
333
|
{i18n.t('common.refresh')}
|
|
279
334
|
</Button>
|
|
280
|
-
<Button size="sm"
|
|
335
|
+
<Button size="sm" disabled={!taskScope.session.available} onclick={toggleSubmitForm}>
|
|
281
336
|
<Plus class="svadmin-u-82cc6c6581cd svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
282
337
|
{i18n.t('task.submitAction')}
|
|
283
338
|
</Button>
|
|
@@ -328,14 +383,14 @@
|
|
|
328
383
|
<Textarea id="task-body" bind:value={submitBodyText} class="svadmin-u-ee15a477cd9c svadmin-u-0e65706bcccd svadmin-u-359090c2d529" />
|
|
329
384
|
</div>
|
|
330
385
|
{#if submitError}
|
|
331
|
-
<p class="svadmin-u-fc7473ca09eb svadmin-u-811148b13d1e">{submitError}</p>
|
|
386
|
+
<p role="alert" class="svadmin-u-fc7473ca09eb svadmin-u-811148b13d1e">{submitError}</p>
|
|
332
387
|
{/if}
|
|
333
388
|
<div class="svadmin-u-60fbb7713999 svadmin-u-1eb5c6df38c1 svadmin-u-77c08e015d14 svadmin-u-77a2a20e90d4">
|
|
334
|
-
<Button variant="ghost" onclick={
|
|
389
|
+
<Button variant="ghost" onclick={toggleSubmitForm}>
|
|
335
390
|
{i18n.t('common.cancel')}
|
|
336
391
|
</Button>
|
|
337
|
-
<Button onclick={() => void handleSubmitTask()} disabled={
|
|
338
|
-
{#if
|
|
392
|
+
<Button onclick={() => void handleSubmitTask()} disabled={submitAttempt !== null || !taskScope.session.available}>
|
|
393
|
+
{#if submitAttempt !== null}
|
|
339
394
|
<Loader2 class="svadmin-u-82cc6c6581cd svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-afbdd13a380e" />
|
|
340
395
|
{/if}
|
|
341
396
|
{i18n.t('task.submitAction')}
|
|
@@ -347,7 +402,7 @@
|
|
|
347
402
|
|
|
348
403
|
<TaskList
|
|
349
404
|
tasks={filteredTasks}
|
|
350
|
-
{
|
|
405
|
+
taskProvider={activeTaskProvider}
|
|
351
406
|
dlq={activeTab === 'dlq'}
|
|
352
407
|
title={activeTab === 'dlq' ? i18n.t('task.dlqTitle') : i18n.t('task.listTitle')}
|
|
353
408
|
emptyText={activeTab === 'dlq' ? i18n.t('task.noDlq') : i18n.t('task.noTasks')}
|
|
@@ -363,7 +418,7 @@
|
|
|
363
418
|
{#if selectedTaskId}
|
|
364
419
|
<TaskDetails
|
|
365
420
|
taskId={selectedTaskId}
|
|
366
|
-
{
|
|
421
|
+
taskProvider={activeTaskProvider}
|
|
367
422
|
useProviderData
|
|
368
423
|
queryOptions={{
|
|
369
424
|
refetchInterval: refreshInterval,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { definedOptions } from '@svadmin/core/options';
|
|
3
|
+
|
|
2
4
|
import { onMount } from 'svelte';
|
|
3
5
|
import { Toaster, toast as sonner, type ToasterProps } from 'svelte-sonner';
|
|
4
6
|
import {
|
|
@@ -29,7 +31,7 @@
|
|
|
29
31
|
const queue = getToastQueue();
|
|
30
32
|
if (queue.length > 0) {
|
|
31
33
|
for (const t of queue) {
|
|
32
|
-
const options = { duration: t.duration, id: t.key ?? t.id };
|
|
34
|
+
const options = definedOptions({ duration: t.duration, id: t.key ?? t.id });
|
|
33
35
|
switch (t.type) {
|
|
34
36
|
case 'success': sonner.success(t.message, options); break;
|
|
35
37
|
case 'error': sonner.error(t.message, options); break;
|
|
@@ -86,7 +88,7 @@
|
|
|
86
88
|
{#each getToasts().slice(-3) as item (item.id)}
|
|
87
89
|
<UndoableNotification
|
|
88
90
|
message={item.message}
|
|
89
|
-
duration
|
|
91
|
+
{...definedOptions({ "duration": item.duration })}
|
|
90
92
|
embedded
|
|
91
93
|
managedExternally
|
|
92
94
|
onUndo={() => undo(item.id, item.onUndo)}
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
<Tooltip.Root bind:open>
|
|
61
61
|
<Tooltip.Trigger aria-describedby={restProps['aria-describedby']}>
|
|
62
62
|
{#snippet child({ props })}
|
|
63
|
-
{@const primitiveOnclick = props
|
|
63
|
+
{@const primitiveOnclick = props['onclick'] as ((event: MouseEvent) => void) | undefined}
|
|
64
64
|
{@const buttonProps = { ...mergeButtonProps(props), href, target, rel, variant, size, type, class: className, 'aria-label': restProps['aria-label'] ?? tooltip, 'aria-describedby': props['aria-describedby'], onclick: (event: MouseEvent) => handleClick(event, primitiveOnclick), disabled, tabindex } as any}
|
|
65
65
|
<Button {...buttonProps}>
|
|
66
66
|
{@render children()}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { definedOptions } from '@svadmin/core/options';
|
|
3
|
+
|
|
2
4
|
import { SvelteSet } from 'svelte/reactivity';
|
|
3
|
-
import {
|
|
5
|
+
import { onDestroy } from 'svelte';
|
|
6
|
+
import { ChevronRight, ChevronDown, Check, X, Search, ChevronsUpDown, Loader2, Minus, RotateCw } from '@lucide/svelte';
|
|
4
7
|
import { cn } from '../utils.js';
|
|
5
8
|
import * as Popover from './ui/popover/index.js';
|
|
6
9
|
import { Input } from './ui/input/index.js';
|
|
@@ -11,6 +14,7 @@
|
|
|
11
14
|
value: string | number;
|
|
12
15
|
label: string;
|
|
13
16
|
children?: TreeSelectOption[];
|
|
17
|
+
hasChildren?: boolean;
|
|
14
18
|
disabled?: boolean;
|
|
15
19
|
expanded?: boolean;
|
|
16
20
|
}
|
|
@@ -26,12 +30,13 @@
|
|
|
26
30
|
onlyLeafSelectable?: boolean;
|
|
27
31
|
disabled?: boolean;
|
|
28
32
|
allowClear?: boolean;
|
|
33
|
+
loadChildren?: (node: TreeSelectOption) => Promise<TreeSelectOption[]>;
|
|
29
34
|
class?: string;
|
|
30
35
|
onchange?: (value: string | number | (string | number)[] | undefined) => void;
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
let {
|
|
34
|
-
options = [],
|
|
39
|
+
options = $bindable([]),
|
|
35
40
|
value = $bindable(undefined),
|
|
36
41
|
multiple = false,
|
|
37
42
|
placeholder,
|
|
@@ -39,13 +44,22 @@
|
|
|
39
44
|
onlyLeafSelectable = false,
|
|
40
45
|
disabled = false,
|
|
41
46
|
allowClear = true,
|
|
47
|
+
loadChildren,
|
|
42
48
|
class: className,
|
|
43
49
|
onchange,
|
|
44
50
|
}: Props = $props();
|
|
45
51
|
|
|
46
52
|
let open = $state(false);
|
|
47
53
|
let searchQuery = $state('');
|
|
54
|
+
let loadingValues = new SvelteSet<string | number>();
|
|
55
|
+
let loadErrors = new SvelteSet<string | number>();
|
|
48
56
|
let expandedNodes = new SvelteSet<string | number>();
|
|
57
|
+
let mounted = true;
|
|
58
|
+
const loads = new Map<string | number, {
|
|
59
|
+
node: TreeSelectOption;
|
|
60
|
+
loader: NonNullable<Props['loadChildren']>;
|
|
61
|
+
}>();
|
|
62
|
+
onDestroy(() => { mounted = false; loads.clear(); });
|
|
49
63
|
|
|
50
64
|
// Map to quickly look up option info by value
|
|
51
65
|
const optionMap = $derived.by(() => {
|
|
@@ -70,6 +84,19 @@
|
|
|
70
84
|
return selectedValues.map((v) => optionMap.get(v)?.label ?? String(v));
|
|
71
85
|
});
|
|
72
86
|
|
|
87
|
+
$effect.pre(() => {
|
|
88
|
+
const nodes = optionMap;
|
|
89
|
+
const loader = loadChildren;
|
|
90
|
+
const unavailable = disabled;
|
|
91
|
+
for (const [key, request] of loads) {
|
|
92
|
+
if (unavailable || nodes.get(key) !== request.node || loader !== request.loader) {
|
|
93
|
+
loads.delete(key);
|
|
94
|
+
loadingValues.delete(key);
|
|
95
|
+
loadErrors.delete(key);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
73
100
|
function toggleExpand(nodeValue: string | number, event?: MouseEvent) {
|
|
74
101
|
event?.stopPropagation();
|
|
75
102
|
if (expandedNodes.has(nodeValue)) {
|
|
@@ -79,32 +106,121 @@
|
|
|
79
106
|
}
|
|
80
107
|
}
|
|
81
108
|
|
|
109
|
+
function hasChildren(node: TreeSelectOption): boolean {
|
|
110
|
+
return Boolean(node.hasChildren ?? (node.children && node.children.length > 0));
|
|
111
|
+
}
|
|
112
|
+
|
|
82
113
|
function isNodeExpanded(node: TreeSelectOption): boolean {
|
|
83
114
|
if (searchQuery.trim()) return true; // Auto expand all on search
|
|
84
115
|
return expandedNodes.has(node.value) || !!node.expanded;
|
|
85
116
|
}
|
|
86
117
|
|
|
118
|
+
function selectableLeaves(node: TreeSelectOption): TreeSelectOption[] {
|
|
119
|
+
if (!hasChildren(node)) return node.disabled ? [] : [node];
|
|
120
|
+
if (!node.children) return [];
|
|
121
|
+
return (node.children ?? []).flatMap(selectableLeaves);
|
|
122
|
+
}
|
|
123
|
+
|
|
87
124
|
function isSelected(val: string | number): boolean {
|
|
88
125
|
return selectedValues.includes(val);
|
|
89
126
|
}
|
|
90
127
|
|
|
91
|
-
function
|
|
128
|
+
function isNodeSelected(node: TreeSelectOption): boolean {
|
|
129
|
+
if (!multiple || !hasChildren(node)) return isSelected(node.value);
|
|
130
|
+
const leaves = selectableLeaves(node);
|
|
131
|
+
return leaves.length > 0 && leaves.every((leaf) => isSelected(leaf.value));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isPartiallySelected(node: TreeSelectOption): boolean {
|
|
135
|
+
if (!multiple || !hasChildren(node)) return false;
|
|
136
|
+
const leaves = selectableLeaves(node);
|
|
137
|
+
const count = leaves.filter((leaf) => isSelected(leaf.value)).length;
|
|
138
|
+
return count > 0 && count < leaves.length;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function updateOptionsChildren(nodes: TreeSelectOption[], target: string | number, children: TreeSelectOption[]): TreeSelectOption[] {
|
|
142
|
+
let changed = false;
|
|
143
|
+
const next = nodes.map((node) => {
|
|
144
|
+
if (node.value === target) {
|
|
145
|
+
changed = true;
|
|
146
|
+
return { ...node, children, hasChildren: children.length > 0 };
|
|
147
|
+
}
|
|
148
|
+
if (!node.children) return node;
|
|
149
|
+
const updated = updateOptionsChildren(node.children, target, children);
|
|
150
|
+
if (updated === node.children) return node;
|
|
151
|
+
changed = true;
|
|
152
|
+
return { ...node, children: updated };
|
|
153
|
+
});
|
|
154
|
+
return changed ? next : nodes;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function ensureChildren(node: TreeSelectOption): Promise<boolean> {
|
|
158
|
+
if (!mounted || disabled || loadingValues.has(node.value)) return false;
|
|
159
|
+
if (!node.hasChildren || node.children) return true;
|
|
160
|
+
const currentNode = optionMap.get(node.value);
|
|
161
|
+
if (!loadChildren || !currentNode) return false;
|
|
162
|
+
const request = { node: currentNode, loader: loadChildren };
|
|
163
|
+
loads.set(node.value, request);
|
|
164
|
+
const current = () => mounted && !disabled && loads.get(node.value) === request
|
|
165
|
+
&& optionMap.get(node.value) === request.node && loadChildren === request.loader;
|
|
166
|
+
loadingValues.add(node.value);
|
|
167
|
+
loadErrors.delete(node.value);
|
|
168
|
+
try {
|
|
169
|
+
const children = await request.loader(request.node);
|
|
170
|
+
if (!current()) return false;
|
|
171
|
+
options = updateOptionsChildren(options, node.value, children);
|
|
172
|
+
return true;
|
|
173
|
+
} catch {
|
|
174
|
+
if (current()) loadErrors.add(node.value);
|
|
175
|
+
return false;
|
|
176
|
+
} finally {
|
|
177
|
+
if (mounted && loads.get(node.value) === request) {
|
|
178
|
+
loads.delete(node.value);
|
|
179
|
+
loadingValues.delete(node.value);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function toggleExpandAsync(node: TreeSelectOption, event?: MouseEvent): Promise<void> {
|
|
185
|
+
event?.stopPropagation();
|
|
186
|
+
if (!await ensureChildren(node)) return;
|
|
187
|
+
if (!mounted || disabled) return;
|
|
188
|
+
toggleExpand(node.value);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function retryChildren(node: TreeSelectOption, event: MouseEvent): void {
|
|
192
|
+
event.stopPropagation();
|
|
193
|
+
void toggleExpandAsync(node);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function setMultipleSelection(node: TreeSelectOption): void {
|
|
197
|
+
const leaves = selectableLeaves(node);
|
|
198
|
+
const leafValues = new Set(leaves.map((leaf) => leaf.value));
|
|
199
|
+
const shouldRemove = leaves.length > 0 && leaves.every((leaf) => isSelected(leaf.value));
|
|
200
|
+
const next = shouldRemove
|
|
201
|
+
? selectedValues.filter((value) => !leafValues.has(value))
|
|
202
|
+
: [...selectedValues, ...leaves.map((leaf) => leaf.value).filter((value) => !isSelected(value))];
|
|
203
|
+
value = next;
|
|
204
|
+
onchange?.(next);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function handleSelect(node: TreeSelectOption): Promise<void> {
|
|
92
208
|
if (node.disabled) return;
|
|
93
|
-
const
|
|
94
|
-
if (onlyLeafSelectable &&
|
|
95
|
-
|
|
209
|
+
const nodeHasChildren = hasChildren(node);
|
|
210
|
+
if (onlyLeafSelectable && nodeHasChildren) {
|
|
211
|
+
await toggleExpandAsync(node);
|
|
96
212
|
return;
|
|
97
213
|
}
|
|
98
214
|
|
|
99
215
|
if (multiple) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
next =
|
|
103
|
-
|
|
104
|
-
|
|
216
|
+
if (nodeHasChildren) setMultipleSelection(node);
|
|
217
|
+
else {
|
|
218
|
+
const next = isSelected(node.value)
|
|
219
|
+
? selectedValues.filter((selected) => selected !== node.value)
|
|
220
|
+
: [...selectedValues, node.value];
|
|
221
|
+
value = next;
|
|
222
|
+
onchange?.(next);
|
|
105
223
|
}
|
|
106
|
-
value = next;
|
|
107
|
-
onchange?.(next);
|
|
108
224
|
} else {
|
|
109
225
|
const next = node.value;
|
|
110
226
|
value = next;
|
|
@@ -113,6 +229,59 @@
|
|
|
113
229
|
}
|
|
114
230
|
}
|
|
115
231
|
|
|
232
|
+
function findParent(nodes: TreeSelectOption[], target: string | number, parent?: TreeSelectOption): TreeSelectOption | undefined {
|
|
233
|
+
for (const node of nodes) {
|
|
234
|
+
if (node.value === target) return parent;
|
|
235
|
+
const match = node.children ? findParent(node.children, target, node) : undefined;
|
|
236
|
+
if (match) return match;
|
|
237
|
+
}
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function focusTreeNode(valueToFocus: string | number): void {
|
|
242
|
+
const element = document.querySelector<HTMLElement>(`[data-tree-value="${CSS.escape(String(valueToFocus))}"]`);
|
|
243
|
+
element?.focus();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function focusSibling(nodeValue: string | number, offset: number): void {
|
|
247
|
+
const nodes = Array.from(document.querySelectorAll<HTMLElement>('[data-tree-value]'));
|
|
248
|
+
const index = nodes.findIndex((node) => node.dataset['treeValue'] === String(nodeValue));
|
|
249
|
+
const target = nodes[index + offset];
|
|
250
|
+
target?.focus();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function handleTreeKeydown(event: KeyboardEvent, node: TreeSelectOption, expanded: boolean): void {
|
|
254
|
+
const nodeHasChildren = hasChildren(node);
|
|
255
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
void handleSelect(node);
|
|
258
|
+
} else if (event.key === 'ArrowDown') {
|
|
259
|
+
event.preventDefault();
|
|
260
|
+
focusSibling(node.value, 1);
|
|
261
|
+
} else if (event.key === 'ArrowUp') {
|
|
262
|
+
event.preventDefault();
|
|
263
|
+
focusSibling(node.value, -1);
|
|
264
|
+
} else if (event.key === 'Home') {
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
document.querySelector<HTMLElement>('[data-tree-value]')?.focus();
|
|
267
|
+
} else if (event.key === 'End') {
|
|
268
|
+
event.preventDefault();
|
|
269
|
+
const nodes = document.querySelectorAll<HTMLElement>('[data-tree-value]');
|
|
270
|
+
nodes[nodes.length - 1]?.focus();
|
|
271
|
+
} else if (event.key === 'ArrowRight' && nodeHasChildren) {
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
if (!expanded) void toggleExpandAsync(node);
|
|
274
|
+
else focusTreeNode(node.children?.[0]?.value ?? node.value);
|
|
275
|
+
} else if (event.key === 'ArrowLeft') {
|
|
276
|
+
event.preventDefault();
|
|
277
|
+
if (nodeHasChildren && expanded) toggleExpand(node.value);
|
|
278
|
+
else {
|
|
279
|
+
const parent = findParent(options, node.value);
|
|
280
|
+
if (parent) focusTreeNode(parent.value);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
116
285
|
function clearAll(event?: MouseEvent) {
|
|
117
286
|
event?.stopPropagation();
|
|
118
287
|
const next = multiple ? [] : undefined;
|
|
@@ -140,10 +309,10 @@
|
|
|
140
309
|
const matchChildren = filteredChildren && filteredChildren.length > 0;
|
|
141
310
|
|
|
142
311
|
if (matchSelf || matchChildren) {
|
|
143
|
-
filtered.push({
|
|
312
|
+
filtered.push(definedOptions({
|
|
144
313
|
...node,
|
|
145
314
|
children: filteredChildren ?? node.children,
|
|
146
|
-
});
|
|
315
|
+
}));
|
|
147
316
|
}
|
|
148
317
|
}
|
|
149
318
|
return filtered;
|
|
@@ -153,17 +322,21 @@
|
|
|
153
322
|
</script>
|
|
154
323
|
|
|
155
324
|
{#snippet treeNode(node: TreeSelectOption, level: number)}
|
|
156
|
-
{@const
|
|
325
|
+
{@const nodeHasChildren = hasChildren(node)}
|
|
157
326
|
{@const expanded = isNodeExpanded(node)}
|
|
158
|
-
{@const selected =
|
|
159
|
-
{@const
|
|
327
|
+
{@const selected = isNodeSelected(node)}
|
|
328
|
+
{@const partial = isPartiallySelected(node)}
|
|
329
|
+
{@const selectable = !node.disabled && (!onlyLeafSelectable || !nodeHasChildren)}
|
|
160
330
|
|
|
161
331
|
<div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed">
|
|
162
332
|
<div
|
|
163
333
|
role="treeitem"
|
|
164
334
|
tabindex="0"
|
|
165
335
|
aria-selected={selected}
|
|
166
|
-
aria-
|
|
336
|
+
aria-checked={multiple ? (partial ? 'mixed' : selected) : undefined}
|
|
337
|
+
aria-level={level + 1}
|
|
338
|
+
aria-expanded={nodeHasChildren ? expanded : undefined}
|
|
339
|
+
data-tree-value={String(node.value)}
|
|
167
340
|
class={cn(
|
|
168
341
|
'group svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-58284b4ea568 svadmin-u-421ac2be5045 svadmin-u-d5eab218aa34 svadmin-u-ec0091ee009b svadmin-u-359090c2d529 svadmin-u-ceb69a6b0e5f svadmin-u-34516836730d svadmin-u-7f6912283f11',
|
|
169
342
|
selected ? 'svadmin-u-375dc44df6e9 svadmin-u-20aaf08a7ed1 svadmin-u-2689f3958069' : 'svadmin-u-68646cdcc246 svadmin-u-d4108abe6359',
|
|
@@ -173,21 +346,20 @@
|
|
|
173
346
|
onclick={() => {
|
|
174
347
|
if (selectable) handleSelect(node);
|
|
175
348
|
}}
|
|
176
|
-
onkeydown={(e) =>
|
|
177
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
178
|
-
e.preventDefault();
|
|
179
|
-
if (selectable) handleSelect(node);
|
|
180
|
-
}
|
|
181
|
-
}}
|
|
349
|
+
onkeydown={(e) => handleTreeKeydown(e, node, expanded)}
|
|
182
350
|
>
|
|
183
351
|
<div class="svadmin-u-60fbb7713999 svadmin-u-7e0b7cdf1a94 svadmin-u-3960ffc248d9 svadmin-u-58284b4ea568">
|
|
184
|
-
{#if
|
|
352
|
+
{#if nodeHasChildren}
|
|
185
353
|
<button
|
|
186
354
|
type="button"
|
|
355
|
+
aria-label={`${node.label}: ${i18n.t('tree.toggleChildren')}`}
|
|
356
|
+
aria-busy={loadingValues.has(node.value)}
|
|
187
357
|
class="svadmin-u-60fbb7713999 svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3 svadmin-u-012fbd121f37 svadmin-u-3960ffc248d9 svadmin-u-86843cf1e227 svadmin-u-07389a777c1f svadmin-u-bfa603190748 svadmin-u-8e551981c8d7"
|
|
188
|
-
onclick={(e) =>
|
|
358
|
+
onclick={(e) => void toggleExpandAsync(node, e)}
|
|
189
359
|
>
|
|
190
|
-
{#if
|
|
360
|
+
{#if loadingValues.has(node.value)}
|
|
361
|
+
<Loader2 class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-afbdd13a380e" />
|
|
362
|
+
{:else if expanded}
|
|
191
363
|
<ChevronDown class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
192
364
|
{:else}
|
|
193
365
|
<ChevronRight class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
@@ -200,12 +372,22 @@
|
|
|
200
372
|
<span class="svadmin-u-f283ea9bea0e">{node.label}</span>
|
|
201
373
|
</div>
|
|
202
374
|
|
|
203
|
-
{#if
|
|
375
|
+
{#if loadErrors.has(node.value)}
|
|
376
|
+
<span role="alert" class="svadmin-u-bfa603190748">{i18n.t('tree.loadFailed')}</span>
|
|
377
|
+
<button type="button" aria-label={`${node.label}: ${i18n.t('common.retry')}`}
|
|
378
|
+
title={i18n.t('common.retry')} onclick={(e) => retryChildren(node, e)}>
|
|
379
|
+
<RotateCw class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
380
|
+
</button>
|
|
381
|
+
{/if}
|
|
382
|
+
|
|
383
|
+
{#if partial}
|
|
384
|
+
<Minus class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-012fbd121f37 svadmin-u-20aaf08a7ed1" />
|
|
385
|
+
{:else if selected}
|
|
204
386
|
<Check class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-012fbd121f37 svadmin-u-20aaf08a7ed1" />
|
|
205
387
|
{/if}
|
|
206
388
|
</div>
|
|
207
389
|
|
|
208
|
-
{#if
|
|
390
|
+
{#if nodeHasChildren && expanded && node.children}
|
|
209
391
|
<div role="group" class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed">
|
|
210
392
|
{#each node.children as child (child.value)}
|
|
211
393
|
{@render treeNode(child, level + 1)}
|