@svadmin/ui 0.72.0 → 0.74.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 (276) hide show
  1. package/README.md +62 -22
  2. package/THIRD_PARTY_NOTICES.md +52 -0
  3. package/dist/app.css +8488 -6297
  4. package/dist/app.theme.css +8514 -6374
  5. package/dist/class-properties.generated.d.ts +1 -0
  6. package/dist/class-properties.generated.js +2 -0
  7. package/dist/classnames.d.ts +8 -0
  8. package/dist/classnames.js +26 -0
  9. package/dist/component-registry.d.ts +14977 -0
  10. package/dist/component-registry.js +216 -0
  11. package/dist/components/AboutSettings.svelte +7 -1
  12. package/dist/components/AboutSettings.svelte.d.ts +4 -1
  13. package/dist/components/ActivityFeed.svelte +9 -3
  14. package/dist/components/ActivityFeed.svelte.d.ts +3 -0
  15. package/dist/components/AdminApp.svelte +19 -10
  16. package/dist/components/AdminApp.svelte.d.ts +6 -0
  17. package/dist/components/ApiSettings.svelte +41 -5
  18. package/dist/components/ApprovalCenter.svelte +283 -0
  19. package/dist/components/ApprovalCenter.svelte.d.ts +10 -0
  20. package/dist/components/AuditLogViewer.svelte +3 -1
  21. package/dist/components/AutoForm.svelte +53 -9
  22. package/dist/components/AutoForm.svelte.d.ts +3 -0
  23. package/dist/components/AutoTable.svelte +846 -43
  24. package/dist/components/AutoTable.svelte.d.ts +22 -1
  25. package/dist/components/BoundRecordDetailDrawer.svelte +17 -2
  26. package/dist/components/BoundRecordDetailDrawer.svelte.d.ts +4 -0
  27. package/dist/components/Breadcrumbs.svelte +11 -1
  28. package/dist/components/CancelTaskButton.svelte +12 -42
  29. package/dist/components/ColorPicker.svelte +73 -0
  30. package/dist/components/ColorPicker.svelte.d.ts +15 -0
  31. package/dist/components/ComboboxField.svelte +143 -34
  32. package/dist/components/ComboboxField.svelte.d.ts +4 -2
  33. package/dist/components/CreatePage.svelte +4 -0
  34. package/dist/components/CreatePage.svelte.d.ts +2 -0
  35. package/dist/components/DashboardView.svelte +99 -0
  36. package/dist/components/DashboardView.svelte.d.ts +14 -0
  37. package/dist/components/DatePicker.svelte +10 -0
  38. package/dist/components/DatePicker.svelte.d.ts +6 -0
  39. package/dist/components/DateRangeInput.svelte +155 -0
  40. package/dist/components/DateRangeInput.svelte.d.ts +35 -0
  41. package/dist/components/DateRangePicker.svelte +10 -0
  42. package/dist/components/DateRangePicker.svelte.d.ts +6 -0
  43. package/dist/components/DateTimeInput.svelte +134 -0
  44. package/dist/components/DateTimeInput.svelte.d.ts +27 -0
  45. package/dist/components/DateTimePicker.svelte +10 -0
  46. package/dist/components/DateTimePicker.svelte.d.ts +6 -0
  47. package/dist/components/DevTools.svelte +36 -28
  48. package/dist/components/DevframePanel.svelte +123 -0
  49. package/dist/components/DevframePanel.svelte.d.ts +3 -0
  50. package/dist/components/EditPage.svelte +4 -0
  51. package/dist/components/EditPage.svelte.d.ts +2 -0
  52. package/dist/components/ErrorSummary.svelte +52 -0
  53. package/dist/components/ErrorSummary.svelte.d.ts +14 -0
  54. package/dist/components/FieldRenderer.svelte +172 -99
  55. package/dist/components/FileUpload.svelte +412 -0
  56. package/dist/components/FileUpload.svelte.d.ts +43 -0
  57. package/dist/components/FilterBuilder.svelte +244 -265
  58. package/dist/components/FilterBuilder.svelte.d.ts +3 -0
  59. package/dist/components/FilterCollectionInput.svelte +80 -0
  60. package/dist/components/FilterCollectionInput.svelte.d.ts +10 -0
  61. package/dist/components/GanttChart.svelte +66 -14
  62. package/dist/components/GanttChart.svelte.d.ts +6 -0
  63. package/dist/components/Header.svelte +18 -2
  64. package/dist/components/ImportWizard.svelte +509 -100
  65. package/dist/components/ImportWizard.svelte.d.ts +11 -0
  66. package/dist/components/JsonSchemaForm.svelte +322 -98
  67. package/dist/components/JsonSchemaForm.svelte.d.ts +18 -1
  68. package/dist/components/KanbanBoard.svelte +195 -40
  69. package/dist/components/KanbanBoard.svelte.d.ts +9 -2
  70. package/dist/components/Layout.svelte +4 -3
  71. package/dist/components/LazyAutoForm.svelte +28 -0
  72. package/dist/components/LazyAutoForm.svelte.d.ts +8 -0
  73. package/dist/components/LazyAutoTable.svelte +28 -0
  74. package/dist/components/LazyAutoTable.svelte.d.ts +8 -0
  75. package/dist/components/LazySettingsPage.svelte +28 -0
  76. package/dist/components/LazySettingsPage.svelte.d.ts +8 -0
  77. package/dist/components/LazyShowPage.svelte +28 -0
  78. package/dist/components/LazyShowPage.svelte.d.ts +8 -0
  79. package/dist/components/LazyTaskQueueDrawer.svelte.d.ts +1 -1
  80. package/dist/components/ListPage.svelte +9 -1
  81. package/dist/components/ListPage.svelte.d.ts +5 -0
  82. package/dist/components/LoginPage.svelte +2 -2
  83. package/dist/components/MoneyInput.svelte +25 -0
  84. package/dist/components/MoneyInput.svelte.d.ts +20 -0
  85. package/dist/components/MultiTabKeepAlive.svelte +11 -6
  86. package/dist/components/NotificationsSettings.svelte +69 -2
  87. package/dist/components/NotificationsSettings.svelte.d.ts +25 -1
  88. package/dist/components/NumberInput.svelte +25 -0
  89. package/dist/components/NumberInput.svelte.d.ts +19 -0
  90. package/dist/components/NumericInput.svelte +110 -0
  91. package/dist/components/NumericInput.svelte.d.ts +23 -0
  92. package/dist/components/PercentInput.svelte +25 -0
  93. package/dist/components/PercentInput.svelte.d.ts +20 -0
  94. package/dist/components/PermissionMatrix.svelte +20 -1
  95. package/dist/components/PivotExportButton.svelte +157 -0
  96. package/dist/components/PivotExportButton.svelte.d.ts +16 -0
  97. package/dist/components/PivotTable.svelte +229 -74
  98. package/dist/components/PivotTable.svelte.d.ts +19 -2
  99. package/dist/components/QuickEditDrawer.svelte +4 -1
  100. package/dist/components/QuickEditDrawer.svelte.d.ts +2 -0
  101. package/dist/components/RadioGroup.svelte +121 -0
  102. package/dist/components/RadioGroup.svelte.d.ts +43 -0
  103. package/dist/components/RangeSlider.svelte +127 -0
  104. package/dist/components/RangeSlider.svelte.d.ts +22 -0
  105. package/dist/components/Rate.svelte +121 -0
  106. package/dist/components/Rate.svelte.d.ts +16 -0
  107. package/dist/components/RecordDetailDrawer.svelte +6 -2
  108. package/dist/components/RecordDetailDrawer.svelte.d.ts +4 -0
  109. package/dist/components/RelationPicker.svelte +341 -0
  110. package/dist/components/RelationPicker.svelte.d.ts +26 -0
  111. package/dist/components/ResourceOperationsPage.svelte +25 -19
  112. package/dist/components/ResourceOperationsPage.svelte.d.ts +5 -1
  113. package/dist/components/RetryTaskButton.svelte +12 -42
  114. package/dist/components/SecuritySettings.svelte +29 -5
  115. package/dist/components/SegmentedControl.svelte +145 -0
  116. package/dist/components/SegmentedControl.svelte.d.ts +38 -0
  117. package/dist/components/SettingsPage.svelte +3 -1
  118. package/dist/components/SettingsPage.svelte.d.ts +1 -0
  119. package/dist/components/ShowInferencer.svelte +4 -2
  120. package/dist/components/ShowInferencer.svelte.d.ts +2 -0
  121. package/dist/components/ShowPage.svelte +25 -6
  122. package/dist/components/ShowPage.svelte.d.ts +5 -0
  123. package/dist/components/Sidebar.svelte +5 -5
  124. package/dist/components/Slider.svelte +100 -0
  125. package/dist/components/Slider.svelte.d.ts +19 -0
  126. package/dist/components/SpreadsheetView.svelte +1037 -124
  127. package/dist/components/SpreadsheetView.svelte.d.ts +19 -0
  128. package/dist/components/StepsForm.svelte +5 -5
  129. package/dist/components/SvarAutoTable.svelte +39 -0
  130. package/dist/components/SvarAutoTable.svelte.d.ts +13 -0
  131. package/dist/components/SvarDataGrid.svelte +362 -0
  132. package/dist/components/SvarDataGrid.svelte.d.ts +57 -0
  133. package/dist/components/SvarGridCell.svelte +10 -0
  134. package/dist/components/SvarGridCell.svelte.d.ts +7 -0
  135. package/dist/components/SvarResourceRead.svelte +50 -0
  136. package/dist/components/SvarResourceRead.svelte.d.ts +23 -0
  137. package/dist/components/SvarResourceTable.svelte +63 -0
  138. package/dist/components/SvarResourceTable.svelte.d.ts +42 -0
  139. package/dist/components/SvarResourceTableView.svelte +364 -0
  140. package/dist/components/SvarResourceTableView.svelte.d.ts +4 -0
  141. package/dist/components/TagsInput.svelte +178 -0
  142. package/dist/components/TagsInput.svelte.d.ts +17 -0
  143. package/dist/components/TaskQueueDrawer.svelte +72 -16
  144. package/dist/components/TimePicker.svelte +10 -0
  145. package/dist/components/TimePicker.svelte.d.ts +6 -0
  146. package/dist/components/TreeSelect.svelte +440 -46
  147. package/dist/components/TreeSelect.svelte.d.ts +6 -1
  148. package/dist/components/TreeTable.svelte +484 -82
  149. package/dist/components/TreeTable.svelte.d.ts +24 -1
  150. package/dist/components/TwoFactorAuthPage.svelte +85 -48
  151. package/dist/components/TwoFactorAuthPage.svelte.d.ts +12 -1
  152. package/dist/components/VirtualTable.svelte +116 -20
  153. package/dist/components/VirtualTable.svelte.d.ts +5 -0
  154. package/dist/components/account/CompanyProfilePage.svelte +74 -38
  155. package/dist/components/account/GetStartedPage.svelte +2 -1
  156. package/dist/components/account/ImportMembersPage.svelte +22 -167
  157. package/dist/components/account/ImportMembersPage.svelte.d.ts +4 -1
  158. package/dist/components/account/MemberDirectory.svelte +156 -0
  159. package/dist/components/account/MemberDirectory.svelte.d.ts +19 -0
  160. package/dist/components/account/MembersStarterPage.svelte +9 -55
  161. package/dist/components/account/MembersStarterPage.svelte.d.ts +5 -1
  162. package/dist/components/account/SecurityLogPage.svelte +4 -1
  163. package/dist/components/account/SettingsPlainPage.svelte +7 -38
  164. package/dist/components/account/SettingsPlainPage.svelte.d.ts +4 -1
  165. package/dist/components/account/SettingsSidebarPage.svelte +7 -20
  166. package/dist/components/account/TeamMembersPage.svelte +4 -20
  167. package/dist/components/account/TeamMembersPage.svelte.d.ts +5 -1
  168. package/dist/components/account/UserProfilePage.svelte +3 -25
  169. package/dist/components/account/UserProfilePage.svelte.d.ts +17 -2
  170. package/dist/components/auto-table-grid.d.ts +26 -0
  171. package/dist/components/auto-table-grid.js +1 -0
  172. package/dist/components/buttons/ExportButton.svelte +56 -12
  173. package/dist/components/buttons/ExportButton.svelte.d.ts +11 -0
  174. package/dist/components/content/ContentPageHeader.svelte +12 -9
  175. package/dist/components/content/ContentPageShell.svelte +6 -9
  176. package/dist/components/content/FileBrowser.svelte +35 -0
  177. package/dist/components/content/FileBrowser.svelte.d.ts +14 -0
  178. package/dist/components/content/MetricBlock.svelte +10 -13
  179. package/dist/components/content/NetworkTable.svelte +3 -3
  180. package/dist/components/content/NetworkTable.svelte.d.ts +1 -0
  181. package/dist/components/content/PageToolbar.svelte +6 -10
  182. package/dist/components/content/ReferenceNotice.svelte +5 -0
  183. package/dist/components/content/ReferenceNotice.svelte.d.ts +18 -0
  184. package/dist/components/content/SectionHeader.svelte +8 -13
  185. package/dist/components/content/SettingsFieldRow.svelte +9 -23
  186. package/dist/components/content/SettingsGroup.svelte +11 -27
  187. package/dist/components/content/StatusBadge.svelte +3 -8
  188. package/dist/components/content/WorkspaceLayout.svelte +8 -12
  189. package/dist/components/enterprise/filter-tree.d.ts +48 -0
  190. package/dist/components/enterprise/filter-tree.js +224 -0
  191. package/dist/components/enterprise/json-schema-form.d.ts +39 -0
  192. package/dist/components/enterprise/json-schema-form.js +195 -0
  193. package/dist/components/enterprise/recursive-schema-form.d.ts +30 -0
  194. package/dist/components/enterprise/recursive-schema-form.js +196 -0
  195. package/dist/components/enterprise/spreadsheet-formula.d.ts +12 -0
  196. package/dist/components/enterprise/spreadsheet-formula.js +245 -0
  197. package/dist/components/export-reference.d.ts +2 -0
  198. package/dist/components/export-reference.js +9 -0
  199. package/dist/components/fieldComponentMap.js +2 -0
  200. package/dist/components/fields/DateField.svelte +12 -12
  201. package/dist/components/fields/date-display.d.ts +6 -0
  202. package/dist/components/fields/date-display.js +24 -0
  203. package/dist/components/fields/date-field-value.d.ts +2 -0
  204. package/dist/components/fields/date-field-value.js +13 -0
  205. package/dist/components/json-schema-form-state.d.ts +37 -0
  206. package/dist/components/json-schema-form-state.js +168 -0
  207. package/dist/components/network/TeamCrewTablePage.svelte +6 -1
  208. package/dist/components/network/UserCardsNFTPage.svelte +2 -0
  209. package/dist/components/profile/PublicProfilePage.svelte +2 -0
  210. package/dist/components/record-detail.svelte.d.ts +3 -0
  211. package/dist/components/record-detail.svelte.js +10 -4
  212. package/dist/components/saved-list-views.d.ts +74 -1
  213. package/dist/components/saved-list-views.js +191 -3
  214. package/dist/components/svar-grid-cells.d.ts +14 -0
  215. package/dist/components/svar-grid-cells.js +2 -0
  216. package/dist/components/svar-grid-contract.d.ts +80 -0
  217. package/dist/components/svar-grid-contract.js +159 -0
  218. package/dist/components/svar-grid-interactions.d.ts +54 -0
  219. package/dist/components/svar-grid-interactions.js +174 -0
  220. package/dist/components/svar-grid-loading.d.ts +40 -0
  221. package/dist/components/svar-grid-loading.js +180 -0
  222. package/dist/components/svar-grid-operations.d.ts +37 -0
  223. package/dist/components/svar-grid-operations.js +186 -0
  224. package/dist/components/svar-grid-panes.d.ts +34 -0
  225. package/dist/components/svar-grid-panes.js +66 -0
  226. package/dist/components/svar-grid-resource-loading.d.ts +18 -0
  227. package/dist/components/svar-grid-resource-loading.js +68 -0
  228. package/dist/components/svar-grid-resource-session.svelte.d.ts +29 -0
  229. package/dist/components/svar-grid-resource-session.svelte.js +61 -0
  230. package/dist/components/table-contract.d.ts +12 -1
  231. package/dist/components/task-action.svelte.d.ts +13 -0
  232. package/dist/components/task-action.svelte.js +73 -0
  233. package/dist/components/ui/DesignSystemShowcase.svelte +164 -0
  234. package/dist/components/ui/DesignSystemShowcase.svelte.d.ts +3 -0
  235. package/dist/components/ui/badge/badge-variants.d.ts +3 -2
  236. package/dist/components/ui/badge/badge-variants.js +2 -1
  237. package/dist/components/ui/badge/badge.svelte +3 -0
  238. package/dist/components/ui/badge/badge.svelte.d.ts +1 -0
  239. package/dist/components/ui/button/button-variants.d.ts +5 -4
  240. package/dist/components/ui/button/button-variants.js +7 -2
  241. package/dist/components/ui/checkbox/checkbox.svelte +5 -1
  242. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +5 -1
  243. package/dist/components/ui/input/input.svelte +8 -6
  244. package/dist/components/ui/input/input.svelte.d.ts +4 -1
  245. package/dist/components/ui/select/select.svelte +4 -1
  246. package/dist/components/ui/select/select.svelte.d.ts +2 -1
  247. package/dist/components/ui/textarea/textarea.svelte +2 -1
  248. package/dist/components.css +3110 -0
  249. package/dist/date-input-policy.d.ts +4 -0
  250. package/dist/date-input-policy.js +35 -0
  251. package/dist/design-contract.d.ts +13 -0
  252. package/dist/design-contract.js +11 -0
  253. package/dist/design-system-components.d.ts +100 -0
  254. package/dist/design-system-components.js +101 -0
  255. package/dist/design-system.d.ts +15 -0
  256. package/dist/design-system.js +7 -0
  257. package/dist/devtools-bridge.d.ts +80 -0
  258. package/dist/devtools-bridge.js +92 -0
  259. package/dist/index.d.ts +50 -1
  260. package/dist/index.js +32 -2
  261. package/dist/page-chrome.css +12 -49
  262. package/dist/recipes.d.ts +960 -0
  263. package/dist/recipes.js +264 -0
  264. package/dist/rendering/index.d.ts +87 -0
  265. package/dist/rendering/index.js +117 -0
  266. package/dist/styles/aliases.css +49 -0
  267. package/dist/styles/compatibility.epilogue.css +384 -0
  268. package/dist/styles/compatibility.prelude.css +5513 -0
  269. package/dist/styles/conditional-states.css +28 -0
  270. package/dist/styles/conditional-utilities.css +22 -0
  271. package/dist/tree-table-model.d.ts +24 -0
  272. package/dist/tree-table-model.js +111 -0
  273. package/dist/utils.d.ts +1 -1
  274. package/dist/utils.js +1 -1
  275. package/package.json +40 -10
  276. package/styles-compatibility.json +12 -0
@@ -0,0 +1,123 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { connectPanelChannel, type PanelChannel } from 'devframe/in-page-channel';
4
+ import {
5
+ SVADMIN_DEVFRAME_CHANNEL,
6
+ type DevtoolsQuerySelector,
7
+ type SvadminDevframeProtocol,
8
+ type SvadminDevtoolsSnapshot,
9
+ } from '../devtools-bridge.js';
10
+
11
+ let channel = $state<PanelChannel<SvadminDevframeProtocol> | null>(null);
12
+ let snapshot = $state<SvadminDevtoolsSnapshot | null>(null);
13
+ let status = $state('connecting');
14
+ let busy = $state(false);
15
+ let selectedProvider = $state('');
16
+ let selectedResource = $state('');
17
+ let selectedOperation = $state('');
18
+
19
+ const selector = $derived<DevtoolsQuerySelector>({
20
+ ...(selectedProvider ? { provider: selectedProvider } : {}),
21
+ ...(selectedResource ? { resource: selectedResource } : {}),
22
+ ...(selectedOperation ? { operation: selectedOperation } : {}),
23
+ });
24
+
25
+ async function run(action: (selector?: DevtoolsQuerySelector) => Promise<void> | void): Promise<void> {
26
+ if (!channel || !snapshot) return;
27
+ busy = true;
28
+ try {
29
+ await action(Object.keys(selector).length > 0 ? selector : undefined);
30
+ snapshot = await channel.call('getSnapshot');
31
+ } finally {
32
+ busy = false;
33
+ }
34
+ }
35
+
36
+ onMount(() => {
37
+ const nextChannel = connectPanelChannel<SvadminDevframeProtocol>({
38
+ name: SVADMIN_DEVFRAME_CHANNEL,
39
+ functions: {},
40
+ });
41
+ channel = nextChannel;
42
+ status = nextChannel.status;
43
+ const onStatus = () => {
44
+ status = nextChannel.status;
45
+ if (nextChannel.status === 'connected') {
46
+ void nextChannel.call('getSnapshot').then((next) => { snapshot = next; });
47
+ }
48
+ };
49
+ nextChannel.events.on('status:updated', onStatus);
50
+ onStatus();
51
+ return () => nextChannel.close();
52
+ });
53
+
54
+ function unique(values: string[]): string[] {
55
+ return [...new Set(values)].sort();
56
+ }
57
+ </script>
58
+
59
+ <section aria-label="svadmin Devframe panel">
60
+ <header>
61
+ <strong>svadmin DevTools</strong>
62
+ <span>{status}</span>
63
+ </header>
64
+
65
+ {#if snapshot}
66
+ <dl>
67
+ <div><dt>Route</dt><dd>{snapshot.route}</dd></div>
68
+ <div><dt>Resources</dt><dd>{snapshot.resourceCount}</dd></div>
69
+ <div><dt>Queries</dt><dd>{snapshot.cache.queries.total}</dd></div>
70
+ <div><dt>Mutations</dt><dd>{snapshot.cache.mutations.total}</dd></div>
71
+ </dl>
72
+ <div>
73
+ <label>
74
+ Provider
75
+ <select bind:value={selectedProvider}>
76
+ <option value="">All</option>
77
+ {#each unique(snapshot.queries.map((query) => query.provider)) as provider (provider)}
78
+ <option value={provider}>{provider}</option>
79
+ {/each}
80
+ </select>
81
+ </label>
82
+ <label>
83
+ Resource
84
+ <select bind:value={selectedResource}>
85
+ <option value="">All</option>
86
+ {#each unique(snapshot.queries.map((query) => query.resource)) as resource (resource)}
87
+ <option value={resource}>{resource}</option>
88
+ {/each}
89
+ </select>
90
+ </label>
91
+ <label>
92
+ Operation
93
+ <select bind:value={selectedOperation}>
94
+ <option value="">All</option>
95
+ {#each unique(snapshot.queries.map((query) => query.operation)) as operation (operation)}
96
+ <option value={operation}>{operation}</option>
97
+ {/each}
98
+ </select>
99
+ </label>
100
+ </div>
101
+ {#if snapshot.queries.length > 0}
102
+ <ul>
103
+ {#each snapshot.queries as query (`${query.provider}:${query.resource}:${query.operation}`)}
104
+ <li>
105
+ <strong>{query.provider} / {query.resource}</strong>
106
+ <span>{query.operation} · {query.status} · {query.duration}</span>
107
+ </li>
108
+ {/each}
109
+ </ul>
110
+ {/if}
111
+ <div>
112
+ <button type="button" disabled={busy} onclick={() => run((selector) => channel?.call('cacheInvalidate', selector))}>Invalidate</button>
113
+ <button type="button" disabled={busy} onclick={() => run((selector) => channel?.call('cacheRefetch', selector))}>Refetch</button>
114
+ <button type="button" disabled={busy} onclick={() => run((selector) => channel?.call('cacheCancel', selector))}>Cancel</button>
115
+ <button type="button" disabled={busy} onclick={() => run((selector) => channel?.call('cacheReset', selector))}>Reset</button>
116
+ <button type="button" disabled={busy} onclick={() => run((selector) => channel?.call('cacheRemove', selector))}>Remove</button>
117
+ <button type="button" disabled={busy} onclick={() => run(() => channel?.call('cacheClear'))}>Clear cache</button>
118
+ <button type="button" disabled={busy} onclick={() => run(() => channel?.call('clearMutations'))}>Clear mutations</button>
119
+ </div>
120
+ {:else}
121
+ <p>Waiting for an svadmin page.</p>
122
+ {/if}
123
+ </section>
@@ -0,0 +1,3 @@
1
+ declare const DevframePanel: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type DevframePanel = ReturnType<typeof DevframePanel>;
3
+ export default DevframePanel;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { ResourceRendering } from '../rendering/index.js';
2
3
  import { definedOptions } from '@svadmin/core/options';
3
4
 
4
5
  import { getResource, useNavigation } from '@svadmin/core';
@@ -16,6 +17,7 @@
16
17
 
17
18
  interface Props {
18
19
  resourceName: string;
20
+ rendering?: ResourceRendering | undefined;
19
21
  id: string | number;
20
22
  title?: string;
21
23
  density?: 'compact' | 'comfortable';
@@ -28,6 +30,7 @@
28
30
 
29
31
  let {
30
32
  resourceName,
33
+ rendering,
31
34
  id,
32
35
  title,
33
36
  density = 'comfortable',
@@ -65,6 +68,7 @@
65
68
  </PageHeader>
66
69
 
67
70
  <AutoForm
71
+ {rendering}
68
72
  {resourceName}
69
73
  mode="edit"
70
74
  {id}
@@ -1,6 +1,8 @@
1
+ import type { ResourceRendering } from '../rendering/index.js';
1
2
  import type { Snippet } from 'svelte';
2
3
  interface Props {
3
4
  resourceName: string;
5
+ rendering?: ResourceRendering | undefined;
4
6
  id: string | number;
5
7
  title?: string;
6
8
  density?: 'compact' | 'comfortable';
@@ -0,0 +1,52 @@
1
+ <script lang="ts">
2
+ import { useTranslation } from '@svadmin/core/i18n';
3
+
4
+ const i18n = useTranslation();
5
+
6
+ export interface FormErrorEntry {
7
+ fieldKey: string;
8
+ label: string;
9
+ message: string;
10
+ }
11
+
12
+ let {
13
+ errors = [],
14
+ title = i18n.t('common.formErrors'),
15
+ id,
16
+ onfocusfield,
17
+ } = $props<{
18
+ errors?: FormErrorEntry[];
19
+ title?: string;
20
+ id?: string;
21
+ onfocusfield?: (fieldKey: string) => void;
22
+ }>();
23
+
24
+ const headingId = $derived(id ? `${id}-title` : undefined);
25
+ </script>
26
+
27
+ {#if errors.length > 0}
28
+ <div
29
+ class="svadmin-u-ee1a5af3aa10"
30
+ role="region"
31
+ aria-labelledby={headingId}
32
+ >
33
+ <h2 id={headingId} class="svadmin-u-2689f3958069">{title}</h2>
34
+ <ul>
35
+ {#each errors as error (error.fieldKey)}
36
+ <li>
37
+ {#if onfocusfield}
38
+ <button
39
+ type="button"
40
+ class="svadmin-u-d4108abe6359"
41
+ onclick={() => onfocusfield?.(error.fieldKey)}
42
+ >
43
+ {error.label}: {error.message}
44
+ </button>
45
+ {:else}
46
+ <span>{error.label}: {error.message}</span>
47
+ {/if}
48
+ </li>
49
+ {/each}
50
+ </ul>
51
+ </div>
52
+ {/if}
@@ -0,0 +1,14 @@
1
+ export interface FormErrorEntry {
2
+ fieldKey: string;
3
+ label: string;
4
+ message: string;
5
+ }
6
+ type $$ComponentProps = {
7
+ errors?: FormErrorEntry[];
8
+ title?: string;
9
+ id?: string;
10
+ onfocusfield?: (fieldKey: string) => void;
11
+ };
12
+ declare const ErrorSummary: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type ErrorSummary = ReturnType<typeof ErrorSummary>;
14
+ export default ErrorSummary;
@@ -18,6 +18,15 @@
18
18
  import { Button } from './ui/button/index.js';
19
19
  import TooltipButton from './TooltipButton.svelte';
20
20
  import ComboboxField from './ComboboxField.svelte';
21
+ import NumberInput from './NumberInput.svelte';
22
+ import MoneyInput from './MoneyInput.svelte';
23
+ import PercentInput from './PercentInput.svelte';
24
+ import DateTimeInput from './DateTimeInput.svelte';
25
+ import DateRangeInput, { type DateRangeInputValue } from './DateRangeInput.svelte';
26
+ import FileUpload from './FileUpload.svelte';
27
+ import ColorPicker from './ColorPicker.svelte';
28
+ import Rate from './Rate.svelte';
29
+ import TagsInput from './TagsInput.svelte';
21
30
  import TreeSelect, { type TreeSelectOption } from './TreeSelect.svelte';
22
31
  import Cascader, { type CascaderOption } from './Cascader.svelte';
23
32
  import Transfer, { type TransferItem } from './Transfer.svelte';
@@ -50,6 +59,11 @@
50
59
  const boolVal = $derived((value as boolean) ?? false);
51
60
  const tagsVal = $derived((value as string[]) ?? []);
52
61
  const multiVal = $derived((value as (string | number)[]) ?? []);
62
+ type FieldOption = NonNullable<FieldDefinition['options']>[number];
63
+ const selectToken = $derived.by(() => {
64
+ const index = field.options?.findIndex((option: FieldOption) => option.value === value) ?? -1;
65
+ return index < 0 ? '' : `option:${index}`;
66
+ });
53
67
  const imagesVal = $derived((value as string[]) ?? []);
54
68
  let jsonEditText = $state('');
55
69
  let jsonEditing = false;
@@ -59,24 +73,20 @@
59
73
  jsonEditText = typeof value === 'string' ? String(value) : JSON.stringify(value, null, 2);
60
74
  });
61
75
 
62
- function handleTagKeydown(e: KeyboardEvent) {
63
- if (e.key === 'Enter') {
64
- e.preventDefault();
65
- const input = e.target as HTMLInputElement;
66
- const tag = input.value.trim();
67
- if (tag) {
68
- onchange([...tagsVal, tag]);
69
- input.value = '';
70
- }
76
+ function changeSelect(event: Event) {
77
+ if (disabled || !(event.currentTarget instanceof HTMLSelectElement)) return;
78
+ const token = event.currentTarget.value;
79
+ if (token === '') {
80
+ onchange(null);
81
+ return;
71
82
  }
83
+ const option = field.options?.find((_option: FieldOption, index: number) => token === `option:${index}`);
84
+ if (option && !option.disabled) onchange(option.value);
72
85
  }
73
86
 
74
- function removeTag(index: number) {
75
- onchange(tagsVal.filter((_: string, i: number) => i !== index));
76
- }
77
-
78
- // Multiselect toggle
87
+ // 禁用值保留回显,但不能从复选框或标签删除入口修改。
79
88
  function toggleMulti(optValue: string | number) {
89
+ if (disabled || field.options?.find((option: FieldOption) => option.value === optValue)?.disabled) return;
80
90
  if (multiVal.includes(optValue)) {
81
91
  onchange(multiVal.filter((v: string | number) => v !== optValue));
82
92
  } else {
@@ -180,48 +190,65 @@
180
190
  />
181
191
 
182
192
  {:else if field.type === 'color'}
183
- <div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-1004c0c3954c">
184
- <input
185
- id={field.key}
186
- name={field.key}
187
- type="color"
188
- value={strVal || '#000000'}
189
- oninput={(e) => onchange((e.target as HTMLInputElement).value)}
190
- class="svadmin-u-426b8b75185b svadmin-u-7e74e5fe798a svadmin-u-34516836730d svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-eb6a3cef9686"
191
- disabled={disabled}
192
- aria-invalid={invalid || undefined}
193
- aria-describedby={errorId}
194
- />
195
- <Input
196
- type="text"
197
- value={strVal}
198
- oninput={(e) => onchange((e.target as HTMLInputElement).value)}
199
- placeholder="#000000"
200
- class="svadmin-u-1d274d2422d8 svadmin-u-0e65706bcccd svadmin-u-fc7473ca09eb"
201
- {disabled}
202
- />
203
- {#if strVal}
204
- <span
205
- class="svadmin-u-ed8a5df7b2fb svadmin-u-2bbcfc3b5179 svadmin-u-ac204c108886 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-438b2237b8d6"
206
- style="background-color: {strVal}"
207
- ></span>
208
- {/if}
209
- </div>
193
+ <ColorPicker
194
+ id={field.key}
195
+ name={field.key}
196
+ value={strVal}
197
+ onchange={onchange}
198
+ required={field.required}
199
+ invalid={invalid}
200
+ describedby={errorId}
201
+ ariaLabel={field.label}
202
+ {disabled}
203
+ />
210
204
 
211
205
  {:else if field.type === 'number'}
212
- <Input
206
+ <NumberInput
213
207
  id={field.key}
214
208
  name={field.key}
215
- type="number"
216
209
  value={numVal}
217
- oninput={(e) => {
218
- const input = e.currentTarget;
219
- if (!(input instanceof HTMLInputElement)) return;
220
- onchange(input.value === '' ? null : numericInputValue(input.valueAsNumber));
221
- }}
210
+ min={field.min}
211
+ max={field.max}
212
+ step={field.step}
213
+ precision={field.precision}
214
+ onchange={onchange}
222
215
  required={field.required}
223
- aria-invalid={invalid || undefined}
224
- aria-describedby={errorId}
216
+ invalid={invalid}
217
+ describedby={errorId}
218
+ {disabled}
219
+ />
220
+
221
+ {:else if field.type === 'currency'}
222
+ <MoneyInput
223
+ id={field.key}
224
+ name={field.key}
225
+ value={numVal}
226
+ currency={field.currency ?? 'USD'}
227
+ min={field.min}
228
+ max={field.max}
229
+ step={field.step}
230
+ precision={field.precision ?? 2}
231
+ onchange={onchange}
232
+ required={field.required}
233
+ invalid={invalid}
234
+ describedby={errorId}
235
+ {disabled}
236
+ />
237
+
238
+ {:else if field.type === 'percent'}
239
+ <PercentInput
240
+ id={field.key}
241
+ name={field.key}
242
+ value={numVal}
243
+ scale={field.scale ?? '100'}
244
+ min={field.min}
245
+ max={field.max}
246
+ step={field.step}
247
+ precision={field.precision ?? 1}
248
+ onchange={onchange}
249
+ required={field.required}
250
+ invalid={invalid}
251
+ describedby={errorId}
225
252
  {disabled}
226
253
  />
227
254
 
@@ -300,14 +327,21 @@
300
327
  />
301
328
 
302
329
  {:else if field.type === 'relation' && field.resource}
303
- <input type="hidden" name={field.key} value={value == null ? '' : String(value)} />
330
+ {#if field.multiple}
331
+ {#each multiVal as selectedValue, _i (selectedValue)}
332
+ <input type="hidden" name={field.key} value={String(selectedValue)} />
333
+ {/each}
334
+ {:else}
335
+ <input type="hidden" name={field.key} value={value == null ? '' : String(value)} />
336
+ {/if}
304
337
  <ComboboxField
305
338
  id={field.key}
306
339
  resource={field.resource}
307
- value={value as string | number | null}
340
+ value={field.multiple ? multiVal : value as string | number | null}
308
341
  onchange={(v) => onchange(v)}
309
342
  optionLabel={field.optionLabel ?? 'title'}
310
343
  optionValue={field.optionValue ?? 'id'}
344
+ multiple={field.multiple}
311
345
  placeholder={i18n.t('field.selectPlaceholder')}
312
346
  aria-invalid={invalid || undefined}
313
347
  aria-describedby={errorId}
@@ -315,14 +349,14 @@
315
349
  />
316
350
 
317
351
  {:else if field.type === 'select'}
352
+ <input type="hidden" name={field.key} value={value == null ? '' : String(value)} {disabled} />
318
353
  {#if (field.options?.length ?? 0) > 8}
319
354
  <select
320
355
  id={field.key}
321
- name={field.key}
322
356
  data-slot="select"
323
357
  class="svadmin-u-60fbb7713999 svadmin-u-426b8b75185b svadmin-u-6da6a3c3f741 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-0e17f2bd9074 svadmin-u-03b4dd7f172b svadmin-u-fc7473ca09eb svadmin-u-582e6ef4b245 svadmin-u-9c24ab70af61 svadmin-u-55d048ebfb1c svadmin-u-608dd26cd5ba svadmin-u-80b9d0ae125f svadmin-u-6b22a22a9752 svadmin-u-5f533b3a7de7 svadmin-u-b29d8adbad2e"
324
- value={strVal}
325
- onchange={(e) => onchange((e.target as HTMLSelectElement).value)}
358
+ value={selectToken}
359
+ onchange={changeSelect}
326
360
  required={field.required}
327
361
  aria-invalid={invalid || undefined}
328
362
  aria-describedby={errorId}
@@ -330,30 +364,29 @@
330
364
  >
331
365
  <option value="">{i18n.t('field.selectPlaceholder')}</option>
332
366
  {#each field.options ?? [] as opt, _i (_i)}
333
- <option value={opt.value}>{opt.label}</option>
367
+ <option value={`option:${_i}`} disabled={opt.disabled}>{opt.label}</option>
334
368
  {/each}
335
369
  </select>
336
370
  {:else}
337
371
  <Select
338
372
  id={field.key}
339
- name={field.key}
340
- value={strVal}
341
- onchange={(e) => onchange((e.target as HTMLSelectElement).value)}
373
+ value={selectToken}
374
+ onchange={changeSelect}
342
375
  required={field.required}
343
376
  aria-invalid={invalid || undefined}
344
377
  aria-describedby={errorId}
345
378
  {disabled}
346
- placeholder={i18n.t('field.selectPlaceholder')}
347
379
  >
380
+ <option value="">{i18n.t('field.selectPlaceholder')}</option>
348
381
  {#each field.options ?? [] as opt, _i (_i)}
349
- <option value={opt.value}>{opt.label}</option>
382
+ <option value={`option:${_i}`} disabled={opt.disabled}>{opt.label}</option>
350
383
  {/each}
351
384
  </Select>
352
385
  {/if}
353
386
 
354
387
  {:else if field.type === 'multiselect'}
355
388
  {#each multiVal as selectedValue, selectedIndex (`${selectedValue}-${selectedIndex}`)}
356
- <input type="hidden" name={`${field.key}[]`} value={String(selectedValue)} />
389
+ <input type="hidden" name={`${field.key}[]`} value={String(selectedValue)} {disabled} />
357
390
  {/each}
358
391
  <div
359
392
  class="svadmin-u-6f7e013d6499 svadmin-u-5f22e64f2282 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-eb6e8b881acd svadmin-u-558f64349245 svadmin-u-92bf82f493b1"
@@ -365,12 +398,12 @@
365
398
  {#each field.options ?? [] as opt, _i (_i)}
366
399
  <label class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4 svadmin-u-fc7473ca09eb svadmin-u-34516836730d svadmin-u-39f703dbe296 svadmin-u-07389a777c1f svadmin-u-d8e0e382c67b svadmin-u-465609a240a8 svadmin-u-ceb69a6b0e5f">
367
400
  <Checkbox
368
- id={`${field.key}-${opt.value}`}
401
+ id={`${field.key}-option-${_i}`}
369
402
  checked={multiVal.includes(opt.value)}
370
403
  onCheckedChange={() => toggleMulti(opt.value)}
371
404
  aria-invalid={invalid || undefined}
372
405
  aria-describedby={errorId}
373
- disabled={disabled}
406
+ disabled={disabled || opt.disabled}
374
407
  />
375
408
  {opt.label}
376
409
  </label>
@@ -385,7 +418,7 @@
385
418
  {@const label = field.options?.find((o: { label: string; value: string | number }) => o.value === v)?.label ?? String(v)}
386
419
  <Badge variant="secondary" class="svadmin-u-44ee8ba0a421">
387
420
  {label}
388
- <button type="button" onclick={() => toggleMulti(v)} class="svadmin-u-b45ce4b65d53 svadmin-u-36d4469299aa svadmin-u-51e95020d6f2 svadmin-u-8db899b4e072 svadmin-u-ceb69a6b0e5f" aria-label={i18n.t('common.clear')}>×</button>
421
+ <button type="button" disabled={disabled || field.options?.find((option: FieldOption) => option.value === v)?.disabled} onclick={() => toggleMulti(v)} class="svadmin-u-b45ce4b65d53 svadmin-u-36d4469299aa svadmin-u-51e95020d6f2 svadmin-u-8db899b4e072 svadmin-u-ceb69a6b0e5f" aria-label={i18n.t('common.clear')}>×</button>
389
422
  </Badge>
390
423
  {/each}
391
424
  </div>
@@ -406,47 +439,87 @@
406
439
  </div>
407
440
 
408
441
  {:else if field.type === 'tags'}
409
- {#each tagsVal as tag, tagIndex (`${tag}-${tagIndex}`)}
410
- <input type="hidden" name={`${field.key}[]`} value={tag} />
411
- {/each}
412
- <div class="svadmin-u-6f7e013d6499">
413
- <div class="svadmin-u-60fbb7713999 svadmin-u-1eb5c6df38c1 svadmin-u-58284b4ea568">
414
- {#each tagsVal as tag, i (i)}
415
- <Badge variant="secondary" class="svadmin-u-44ee8ba0a421">
416
- {tag}
417
- <button
418
- type="button"
419
- onclick={() => removeTag(i)}
420
- class="svadmin-u-b45ce4b65d53 svadmin-u-36d4469299aa svadmin-u-51e95020d6f2 svadmin-u-8db899b4e072 svadmin-u-ceb69a6b0e5f"
421
- aria-label={i18n.t('common.clear')}
422
- >×</button>
423
- </Badge>
424
- {/each}
425
- </div>
426
- <Input
427
- id={field.key}
428
- type="text"
429
- placeholder={i18n.t('field.tagsPlaceholder')}
430
- onkeydown={handleTagKeydown}
431
- aria-invalid={invalid || undefined}
432
- aria-describedby={errorId}
433
- {disabled}
434
- />
435
- </div>
442
+ <TagsInput
443
+ name={`${field.key}[]`}
444
+ value={tagsVal}
445
+ onchange={onchange}
446
+ placeholder={i18n.t('field.tagsPlaceholder')}
447
+ required={field.required}
448
+ invalid={invalid}
449
+ describedby={errorId}
450
+ ariaLabel={field.label}
451
+ {disabled}
452
+ />
436
453
 
437
- {:else if field.type === 'date'}
438
- <Input
454
+ {:else if field.type === 'date' || field.type === 'time' || field.type === 'datetime'}
455
+ <DateTimeInput
439
456
  id={field.key}
440
457
  name={field.key}
441
- type="date"
442
- value={strVal}
443
- oninput={(e) => onchange((e.target as HTMLInputElement).value)}
458
+ mode={field.type}
459
+ min={field.dateInput?.min}
460
+ max={field.dateInput?.max}
461
+ step={field.dateInput?.step}
462
+ disabledDate={field.dateInput?.disabledDate}
463
+ valueMode={field.dateInput?.valueMode}
464
+ timeZone={field.dateInput?.timeZone}
465
+ disambiguation={field.dateInput?.disambiguation}
466
+ value={strVal || null}
467
+ onchange={(next) => onchange(next)}
444
468
  required={field.required}
445
- aria-invalid={invalid || undefined}
446
- aria-describedby={errorId}
469
+ invalid={invalid}
470
+ describedby={errorId}
447
471
  {disabled}
448
472
  />
449
473
 
474
+ {:else if field.type === 'daterange'}
475
+ <DateRangeInput
476
+ startId={`${field.key}-start`}
477
+ mode={field.dateInput?.rangeMode ?? 'date'}
478
+ valueMode={field.dateInput?.valueMode}
479
+ timeZone={field.dateInput?.timeZone}
480
+ disambiguation={field.dateInput?.disambiguation}
481
+ min={field.dateInput?.min}
482
+ max={field.dateInput?.max}
483
+ step={field.dateInput?.step}
484
+ disabledDate={field.dateInput?.disabledDate}
485
+ presets={field.dateInput?.presets}
486
+ endId={`${field.key}-end`}
487
+ startAriaLabel={`${field.label} ${i18n.t('common.startDate')}`}
488
+ endAriaLabel={`${field.label} ${i18n.t('common.endDate')}`}
489
+ startName={`${field.key}.start`}
490
+ endName={`${field.key}.end`}
491
+ value={value as DateRangeInputValue | null}
492
+ onchange={(next) => onchange(next)}
493
+ required={field.required}
494
+ invalid={invalid}
495
+ describedby={errorId}
496
+ {disabled}
497
+ />
498
+
499
+ {:else if field.type === 'rate' || field.type === 'rating'}
500
+ <Rate
501
+ name={field.key}
502
+ value={numVal ?? 0}
503
+ onchange={onchange}
504
+ required={field.required}
505
+ invalid={invalid}
506
+ describedby={errorId}
507
+ ariaLabel={field.label}
508
+ {disabled}
509
+ />
510
+
511
+ {:else if field.type === 'file'}
512
+ <FileUpload
513
+ id={field.key}
514
+ name={field.key}
515
+ multiple={field.multiple}
516
+ required={field.required && !value}
517
+ disabled={disabled}
518
+ accept={field.accept}
519
+ maxSize={field.maxSize}
520
+ onChange={(items) => onchange(field.multiple ? items.map(item => item.file) : items[0]?.file ?? null)}
521
+ />
522
+
450
523
  {:else if field.type === 'images'}
451
524
  {#each imagesVal as url, imageIndex (imageIndex)}
452
525
  <input type="hidden" name={`${field.key}[]`} value={url} />