@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,168 @@
1
+ export const SCHEMA_FORM_LIMITS = Object.freeze({ depth: 32, nodes: 10_000, characters: 1_048_576 });
2
+ const unsafe = new Set(['__proto__', 'prototype', 'constructor']);
3
+ const record = (value) => value !== null
4
+ && typeof value === 'object' && !Array.isArray(value)
5
+ && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
6
+ function safeKey(key) {
7
+ if (unsafe.has(key))
8
+ throw new Error('Unsafe form field');
9
+ }
10
+ /** wire 模式仅省略对象的 undefined;数组的空洞/undefined 不能偷偷转成 null。 */
11
+ function copy(value, wire) {
12
+ const active = new Set();
13
+ let nodes = 0, characters = 0;
14
+ function visit(current, depth) {
15
+ if (++nodes > SCHEMA_FORM_LIMITS.nodes || depth > SCHEMA_FORM_LIMITS.depth)
16
+ throw new Error('Form value exceeds limits');
17
+ if (current === undefined && !wire)
18
+ return undefined;
19
+ if (current === null || typeof current === 'boolean')
20
+ return current;
21
+ if (typeof current === 'number' && Number.isFinite(current))
22
+ return current;
23
+ if (typeof current === 'string') {
24
+ characters += current.length;
25
+ if (characters > SCHEMA_FORM_LIMITS.characters)
26
+ throw new Error('Form text exceeds limits');
27
+ return current;
28
+ }
29
+ if ((!record(current) && !Array.isArray(current)) || active.has(current))
30
+ throw new Error('Expected acyclic plain form data');
31
+ active.add(current);
32
+ try {
33
+ if (Reflect.ownKeys(current).some(key => typeof key === 'symbol'))
34
+ throw new Error('Symbol values are not JSON fields');
35
+ if (Array.isArray(current)) {
36
+ if (current.length > SCHEMA_FORM_LIMITS.nodes)
37
+ throw new Error('Form array exceeds limits');
38
+ const result = [];
39
+ for (let index = 0; index < current.length; index++) {
40
+ const descriptor = Object.getOwnPropertyDescriptor(current, String(index));
41
+ if (!descriptor || !('value' in descriptor))
42
+ throw new Error('Sparse arrays and accessors are not form data');
43
+ result.push(visit(descriptor.value, depth + 1));
44
+ }
45
+ if (Object.keys(current).some(key => !/^(0|[1-9][0-9]*)$/u.test(key) || Number(key) >= current.length)) {
46
+ throw new Error('Array properties are not JSON fields');
47
+ }
48
+ return result;
49
+ }
50
+ const result = {};
51
+ for (const key of Object.keys(current)) {
52
+ safeKey(key);
53
+ characters += key.length;
54
+ if (characters > SCHEMA_FORM_LIMITS.characters)
55
+ throw new Error('Form text exceeds limits');
56
+ const descriptor = Object.getOwnPropertyDescriptor(current, key);
57
+ if (!descriptor || !('value' in descriptor))
58
+ throw new Error('Accessors are not form data');
59
+ if (!wire || descriptor.value !== undefined)
60
+ result[key] = visit(descriptor.value, depth + 1);
61
+ }
62
+ return result;
63
+ }
64
+ finally {
65
+ active.delete(current);
66
+ }
67
+ }
68
+ return visit(value, 0);
69
+ }
70
+ /** Svelte 代理也通过普通数据属性读取;回调永远收不到活跃草稿的引用。 */
71
+ export function schemaFormSnapshot(value) {
72
+ if (!record(value))
73
+ throw new Error('Form root must be an object');
74
+ return copy(value, true);
75
+ }
76
+ /** 默认值只填“缺失的键”;显式 undefined/null/false/0/空串都表示调用方的决定。 */
77
+ export function initializeSchemaForm(schema, value) {
78
+ if (!record(value))
79
+ throw new Error('Form root must be an object');
80
+ const active = new Set();
81
+ let nodes = 0;
82
+ function visit(node, current, present, required, depth) {
83
+ if (++nodes > SCHEMA_FORM_LIMITS.nodes || depth > SCHEMA_FORM_LIMITS.depth || !record(node) || active.has(node)) {
84
+ throw new Error('Form schema exceeds supported traversal limits');
85
+ }
86
+ active.add(node);
87
+ try {
88
+ if (!present) {
89
+ if (Object.hasOwn(node, 'default'))
90
+ current = copy(node.default, false);
91
+ else if (node.type === 'object' || node.properties)
92
+ current = {};
93
+ else if (node.type === 'array')
94
+ current = [];
95
+ else if (node.type === 'boolean' && required)
96
+ current = false;
97
+ }
98
+ if (record(current) && (node.type === 'object' || node.properties)) {
99
+ let result = current;
100
+ for (const [key, child] of Object.entries(node.properties ?? {})) {
101
+ safeKey(key);
102
+ const exists = Object.hasOwn(current, key);
103
+ const next = visit(child, exists ? current[key] : undefined, exists, node.required?.includes(key) ?? false, depth + 1);
104
+ if ((!exists && next !== undefined) || (exists && next !== current[key])) {
105
+ if (result === current)
106
+ result = { ...current };
107
+ result[key] = next;
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ if (Array.isArray(current) && node.type === 'array' && node.items) {
113
+ if (current.length > SCHEMA_FORM_LIMITS.nodes)
114
+ throw new Error('Form array exceeds limits');
115
+ const array = current;
116
+ const items = array.map(item => visit(node.items, item, true, true, depth + 1));
117
+ return items.some((item, index) => item !== array[index]) ? items : array;
118
+ }
119
+ return current;
120
+ }
121
+ finally {
122
+ active.delete(node);
123
+ }
124
+ }
125
+ return visit(schema, value, true, true, 0);
126
+ }
127
+ export function schemaFormArrayItem(schema) {
128
+ // 新增对象项也初始化其嵌套默认值及必填 false;数字留空,不猜测为 0。
129
+ const seed = Object.hasOwn(schema, 'default') ? copy(schema.default, false)
130
+ : schema.type === 'object' || schema.properties ? {}
131
+ : schema.type === 'array' ? [] : schema.type === 'boolean' ? false : schema.type === 'number' || schema.type === 'integer' ? undefined : '';
132
+ return initializeSchemaForm({ properties: { item: schema }, required: ['item'] }, { item: seed })['item'];
133
+ }
134
+ export function writeSchemaFormPath(value, path, nextValue) {
135
+ if (!path.length || path.length > SCHEMA_FORM_LIMITS.depth)
136
+ throw new Error('Invalid form path');
137
+ const next = copy(value, false);
138
+ let target = next;
139
+ for (const [index, key] of path.entries()) {
140
+ safeKey(key);
141
+ if (Array.isArray(target) && (!/^(0|[1-9][0-9]*)$/u.test(key) || Number(key) >= target.length))
142
+ throw new Error('Invalid array field');
143
+ if (index === path.length - 1) {
144
+ Reflect.set(target, key, copy(nextValue, false));
145
+ }
146
+ else {
147
+ let child = Object.hasOwn(target, key) ? Reflect.get(target, key) : undefined;
148
+ if (!record(child) && !Array.isArray(child)) {
149
+ child = {};
150
+ Reflect.set(target, key, child);
151
+ }
152
+ target = child;
153
+ }
154
+ }
155
+ return next;
156
+ }
157
+ /** option.value 是索引,不是 String(value):1 与 "1"、null 与 "null" 必须可区分。 */
158
+ export function schemaFormEnumIndex(choices, value) {
159
+ const index = choices.findIndex(choice => choice === value);
160
+ return index === -1 ? '' : String(index);
161
+ }
162
+ export function schemaFormEnumValue(choices, index) {
163
+ if (index === '')
164
+ return undefined;
165
+ if (!/^(0|[1-9][0-9]*)$/u.test(index) || !Object.hasOwn(choices, Number(index)))
166
+ throw new Error('Invalid form choice');
167
+ return choices[Number(index)];
168
+ }
@@ -9,6 +9,10 @@
9
9
  import type { NetworkColumn } from '../content/NetworkTable.types.js';
10
10
  import { Avatar } from '../ui/avatar/index.js';
11
11
  import { Badge } from '../ui/badge/index.js';
12
+ import ReferenceNotice from '../content/ReferenceNotice.svelte';
13
+ import { captureAdminContext } from '@svadmin/core';
14
+ import { downloadRows } from '../export-reference.js';
15
+ const context = captureAdminContext();
12
16
 
13
17
  interface CrewMember { id: string; name: string; email: string; role: string; department: string; status: 'active' | 'away' | 'offline'; projects: number; }
14
18
  const i18n = useTranslation();
@@ -31,7 +35,8 @@
31
35
  {/snippet}
32
36
 
33
37
  <ContentPageShell pageId="network-team-crew" width="wide">
34
- <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-1004c0c3954c svadmin-u-020ba687fa12 svadmin-u-64cac80d2e9a svadmin-u-3b9871a0bf93"><ContentPageHeader title={i18n.t('network.teamCrew')} description={i18n.t('network.teamCrewDescription')} /><div class="svadmin-u-60fbb7713999 svadmin-u-1eb5c6df38c1 svadmin-u-77a2a20e90d4"><Button variant="outline" size="sm"><Download class="svadmin-u-783b0d9d1e2c" />{i18n.t('common.export')}</Button><Button size="sm"><UserPlus class="svadmin-u-783b0d9d1e2c" />{i18n.t('account.inviteMember')}</Button></div></div>
38
+ <ReferenceNotice />
39
+ <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-1004c0c3954c svadmin-u-020ba687fa12 svadmin-u-64cac80d2e9a svadmin-u-3b9871a0bf93"><ContentPageHeader title={i18n.t('network.teamCrew')} description={i18n.t('network.teamCrewDescription')} /><div class="svadmin-u-60fbb7713999 svadmin-u-1eb5c6df38c1 svadmin-u-77a2a20e90d4"><Button variant="outline" size="sm" onclick={() => downloadRows('sample-team.json', filtered)}><Download class="svadmin-u-783b0d9d1e2c" />{i18n.t('common.export')}</Button><Button size="sm" onclick={() => context.navigate('/account/members/team-members')}><UserPlus class="svadmin-u-783b0d9d1e2c" />{i18n.t('account.inviteMember')}</Button></div></div>
35
40
  <FilterToolbar bind:query placeholder={i18n.t('common.search')} />
36
41
  <NetworkTable rows={filtered} {columns} {row} />
37
42
  </ContentPageShell>
@@ -4,6 +4,7 @@
4
4
  import ContentPageHeader from '../content/ContentPageHeader.svelte';
5
5
  import FilterToolbar from '../content/FilterToolbar.svelte';
6
6
  import DataState from '../content/DataState.svelte';
7
+ import ReferenceNotice from '../content/ReferenceNotice.svelte';
7
8
  import NetworkUserCard from '../content/NetworkUserCard.svelte';
8
9
  import type { NetworkUser } from '../content/NetworkUserCard.svelte';
9
10
 
@@ -24,6 +25,7 @@
24
25
  </script>
25
26
 
26
27
  <ContentPageShell pageId="network-user-cards" width="wide">
28
+ <ReferenceNotice />
27
29
  <ContentPageHeader title={i18n.t('network.userCards')} description={i18n.t('network.userCardsDescription')} />
28
30
  <FilterToolbar bind:query placeholder={i18n.t('common.search')} clearLabel={i18n.locale === 'zh-CN' ? '清除搜索' : 'Clear search'} />
29
31
  {#if filtered.length === 0}
@@ -9,6 +9,7 @@
9
9
  import ContentPageShell from '../content/ContentPageShell.svelte';
10
10
  import ContentPageHeader from '../content/ContentPageHeader.svelte';
11
11
  import { referenceDemoData } from '../../reference-data.js';
12
+ import ReferenceNotice from '../content/ReferenceNotice.svelte';
12
13
 
13
14
  type ProfileVariant = 'default' | 'company' | 'gamer';
14
15
  type ProfileTab = 'projects' | 'activity' | 'teams';
@@ -35,6 +36,7 @@
35
36
  </script>
36
37
 
37
38
  <ContentPageShell {pageId} width="wide">
39
+ <ReferenceNotice />
38
40
  <ContentPageHeader title={profileData.name} eyebrow={i18n.t('publicProfile.title')} description={profileData.tagline} />
39
41
  {#if showSections}
40
42
  <div class="svadmin-u-f3c543ad5fe9 svadmin-u-0d304f904cb0 svadmin-u-bf1b5b54929e"><ProfileCard {...profileData} {variant} /><ProfileVariantSections {variant} /></div>
@@ -1,13 +1,16 @@
1
+ import { type ResourceRendering } from '../rendering/index.js';
1
2
  /** Views mount this only when they have an explicit record ID. */
2
3
  export declare function useRecordDetail(options: () => {
3
4
  resourceName: string;
4
5
  id: string | number;
6
+ rendering?: ResourceRendering | undefined;
5
7
  }): {
6
8
  query: import("@tanstack/query-core").QueryObserverResult<import("@svadmin/core").GetOneResult<import("@svadmin/core").BaseRecord & {
7
9
  id: string | number;
8
10
  }>, unknown> & {
9
11
  overtime: import("@svadmin/core").OvertimeResult;
10
12
  };
13
+ readonly rendering: ResourceRendering | undefined;
11
14
  readonly resource: import("@svadmin/core").ResourceDefinition;
12
15
  readonly fields: import("@svadmin/core").FieldDefinition[];
13
16
  readonly canRead: boolean;
@@ -1,20 +1,26 @@
1
+ import { bindResourceRendering } from '../rendering/index.js';
1
2
  import { captureAdminContext, useOne, useCan, useResourceContract } from '@svadmin/core';
2
3
  /** Views mount this only when they have an explicit record ID. */
3
4
  export function useRecordDetail(options) {
4
5
  const context = captureAdminContext();
5
6
  const binding = useResourceContract(() => options().resourceName);
7
+ const rendering = $derived(bindResourceRendering(options().rendering, binding.resource));
6
8
  const resource = $derived(context.getResource(options().resourceName));
7
9
  const permission = useCan(() => ({
8
10
  resource: options().resourceName, action: 'show', id: options().id,
9
11
  queryOptions: { enabled: resource.canShow !== false },
10
12
  }));
11
13
  const canRead = $derived(resource.canShow !== false && permission.allowed === true);
12
- const query = useOne(() => ({
13
- resource: binding.resource, id: options().id, dataProviderName: binding.dataProviderName,
14
- queryOptions: { enabled: canRead },
15
- }));
14
+ const query = useOne(() => {
15
+ void rendering;
16
+ return {
17
+ resource: binding.resource, id: options().id, dataProviderName: binding.dataProviderName,
18
+ queryOptions: { enabled: canRead },
19
+ };
20
+ });
16
21
  return {
17
22
  query,
23
+ get rendering() { return rendering; },
18
24
  get resource() { return resource; },
19
25
  get fields() { return resource.fields.filter(field => field.showInShow !== false); },
20
26
  get canRead() { return canRead; },
@@ -14,13 +14,86 @@ export interface SavedListView {
14
14
  id: string;
15
15
  name: string;
16
16
  state: SavedListViewState;
17
+ version?: number;
18
+ source?: 'local' | 'team' | 'system';
19
+ readOnly?: boolean;
20
+ default?: boolean;
21
+ access?: SavedListViewAccess;
22
+ }
23
+ export type SavedListViewAccessMode = 'team' | 'organization' | 'restricted';
24
+ export interface SavedListViewAccess {
25
+ mode: SavedListViewAccessMode;
26
+ subjectIds: string[];
27
+ }
28
+ export interface SavedListViewSubject {
29
+ id: string;
30
+ label: string;
31
+ description?: string;
32
+ }
33
+ export interface SavedListViewMutation {
34
+ id: string;
35
+ name: string;
36
+ state: SavedListViewState;
37
+ /** null 仅允许创建;更新必须提供读取到的版本。 */
38
+ expectedVersion: number | null;
39
+ source: 'team' | 'system';
40
+ }
41
+ export interface SavedListViewMutationSuccess {
42
+ ok: true;
43
+ view: SavedListView;
44
+ version: number;
45
+ }
46
+ export interface SavedListViewMutationConflict {
47
+ ok: false;
48
+ code: 'VERSION_CONFLICT';
49
+ current: SavedListView;
50
+ version: number;
51
+ }
52
+ export interface SavedListViewRemoveSuccess {
53
+ ok: true;
54
+ id: string;
55
+ version: number;
56
+ }
57
+ export interface SavedListViewProvider {
58
+ list: (scope: ListPreferenceScope) => Promise<unknown>;
59
+ /** 可选的成员目录查询;授权仍由宿主服务端负责。 */
60
+ listAccessSubjects?: (scope: ListPreferenceScope, input: {
61
+ query?: string;
62
+ limit?: number;
63
+ }) => Promise<unknown>;
64
+ save?: (scope: ListPreferenceScope, mutation: SavedListViewMutation) => Promise<unknown>;
65
+ remove?: (scope: ListPreferenceScope, input: {
66
+ id: string;
67
+ expectedVersion: number;
68
+ }) => Promise<unknown>;
69
+ setDefault?: (scope: ListPreferenceScope, input: {
70
+ id: string;
71
+ source: 'team' | 'system';
72
+ expectedVersion: number;
73
+ default: boolean;
74
+ }) => Promise<unknown>;
75
+ updateAccess?: (scope: ListPreferenceScope, input: {
76
+ id: string;
77
+ source: 'team' | 'system';
78
+ expectedVersion: number;
79
+ access: SavedListViewAccess;
80
+ }) => Promise<unknown>;
17
81
  }
18
82
  export interface ListPreferenceScope {
19
83
  resourceName: string;
20
84
  providerName: string;
21
85
  tenantIdentity?: string | number;
86
+ identityKey?: string;
22
87
  }
23
- export declare function readSavedListViews(raw: string | null, allowedColumnIds: Set<string>): SavedListView[];
88
+ export declare function decodeSavedListViewAccess(value: unknown): SavedListViewAccess | undefined;
89
+ export declare function decodeSavedListViewSubjects(value: unknown): SavedListViewSubject[] | undefined;
90
+ export declare function readSavedListViews(raw: string | null, allowedColumnIds: Set<string>, source?: SavedListView['source']): SavedListView[];
91
+ export declare function decodeSavedListViewMutationResult(value: unknown, allowedColumnIds: Set<string>, expected?: Pick<SavedListViewMutation, 'id' | 'source' | 'expectedVersion'>): SavedListViewMutationSuccess | SavedListViewMutationConflict | undefined;
92
+ export declare function decodeSavedListViewRemoveResult(value: unknown, expected: {
93
+ id: string;
94
+ expectedVersion: number;
95
+ }): SavedListViewRemoveSuccess | undefined;
96
+ export declare function decodeRemoteSavedListViews(value: unknown, allowedColumnIds: Set<string>, writable?: boolean): SavedListView[];
24
97
  export declare function serializeSavedListViews(views: SavedListView[]): string;
25
98
  export declare function cloneSavedListViewState(state: SavedListViewState): SavedListViewState;
26
99
  export declare function listPreferenceScopeId(scope: ListPreferenceScope): string;
@@ -1,3 +1,4 @@
1
+ import { snapshotPlainData } from '@svadmin/core/schema';
1
2
  const STORAGE_VERSION = 1;
2
3
  const MAX_SAVED_VIEWS = 25;
3
4
  const MAX_FILTER_NODES = 200;
@@ -91,7 +92,63 @@ function parseState(value, allowedColumnIds) {
91
92
  columnOrder,
92
93
  };
93
94
  }
94
- export function readSavedListViews(raw, allowedColumnIds) {
95
+ function parseAccess(value) {
96
+ if (!isRecord(value) || Object.keys(value).some(key => key !== 'mode' && key !== 'subjectIds'))
97
+ return;
98
+ const mode = value['mode'];
99
+ const ids = value['subjectIds'];
100
+ if ((mode !== 'team' && mode !== 'organization' && mode !== 'restricted')
101
+ || !Array.isArray(ids) || ids.length > 200)
102
+ return;
103
+ const subjectIds = [];
104
+ for (const id of ids) {
105
+ if (typeof id !== 'string' || !id.trim() || id !== id.trim() || id.length > 200
106
+ || subjectIds.includes(id))
107
+ return;
108
+ subjectIds.push(id);
109
+ }
110
+ if ((mode === 'restricted') !== (subjectIds.length > 0))
111
+ return;
112
+ return { mode, subjectIds };
113
+ }
114
+ export function decodeSavedListViewAccess(value) {
115
+ try {
116
+ return parseAccess(snapshotPlainData(value));
117
+ }
118
+ catch {
119
+ return;
120
+ }
121
+ }
122
+ export function decodeSavedListViewSubjects(value) {
123
+ try {
124
+ const snapshot = snapshotPlainData(value);
125
+ if (!Array.isArray(snapshot) || snapshot.length > 200)
126
+ return;
127
+ const seen = new Set();
128
+ const subjects = [];
129
+ for (const entry of snapshot) {
130
+ if (!isRecord(entry)
131
+ || Object.keys(entry).some(key => !['id', 'label', 'description'].includes(key))
132
+ || typeof entry['id'] !== 'string' || !entry['id'].trim() || entry['id'] !== entry['id'].trim()
133
+ || entry['id'].length > 200 || seen.has(entry['id'])
134
+ || typeof entry['label'] !== 'string' || !entry['label'].trim() || entry['label'].length > 200
135
+ || (entry['description'] !== undefined
136
+ && (typeof entry['description'] !== 'string' || entry['description'].length > 500)))
137
+ return;
138
+ seen.add(entry['id']);
139
+ subjects.push({
140
+ id: entry['id'],
141
+ label: entry['label'].trim(),
142
+ ...(entry['description'] === undefined ? {} : { description: entry['description'] }),
143
+ });
144
+ }
145
+ return subjects;
146
+ }
147
+ catch {
148
+ return;
149
+ }
150
+ }
151
+ export function readSavedListViews(raw, allowedColumnIds, source = 'local') {
95
152
  if (!raw)
96
153
  return [];
97
154
  try {
@@ -110,8 +167,20 @@ export function readSavedListViews(raw, allowedColumnIds) {
110
167
  const state = parseState(entry['state'], allowedColumnIds);
111
168
  if (!state)
112
169
  continue;
170
+ const access = entry['access'] === undefined ? undefined : parseAccess(entry['access']);
171
+ if (entry['access'] !== undefined && !access)
172
+ continue;
113
173
  seenIds.add(entry['id']);
114
- views.push({ id: entry['id'], name: entry['name'].trim(), state });
174
+ views.push({
175
+ id: entry['id'], name: entry['name'].trim(), state,
176
+ ...(isPositiveInteger(entry['version'], Number.MAX_SAFE_INTEGER) ? { version: entry['version'] } : {}),
177
+ ...(source !== 'local' ? {
178
+ source: entry['source'] === 'system' ? 'system' : 'team',
179
+ readOnly: true,
180
+ ...(entry['default'] === true ? { default: true } : {}),
181
+ ...(access === undefined ? {} : { access }),
182
+ } : {}),
183
+ });
115
184
  }
116
185
  return views;
117
186
  }
@@ -121,6 +190,124 @@ export function readSavedListViews(raw, allowedColumnIds) {
121
190
  throw error;
122
191
  }
123
192
  }
193
+ export function decodeSavedListViewMutationResult(value, allowedColumnIds, expected) {
194
+ try {
195
+ if (expected && (!expected.id.trim()
196
+ || !['team', 'system'].includes(expected.source)
197
+ || (expected.expectedVersion !== null
198
+ && !isPositiveInteger(expected.expectedVersion, Number.MAX_SAFE_INTEGER))))
199
+ return;
200
+ const snapshot = snapshotPlainData(value);
201
+ if (!isRecord(snapshot) || typeof snapshot['ok'] !== 'boolean')
202
+ return;
203
+ const keys = snapshot['ok'] ? ['ok', 'version', 'view'] : ['ok', 'code', 'version', 'current'];
204
+ if (Object.keys(snapshot).some(key => !keys.includes(key)))
205
+ return;
206
+ const parseReceiptView = (candidate, version) => {
207
+ if (!isRecord(candidate)
208
+ || Object.keys(candidate).some(key => !['id', 'name', 'state', 'version', 'source', 'readOnly', 'default', 'access'].includes(key))
209
+ || candidate['version'] !== version
210
+ || (candidate['readOnly'] !== undefined && typeof candidate['readOnly'] !== 'boolean')
211
+ || (candidate['default'] !== undefined && typeof candidate['default'] !== 'boolean')
212
+ || (candidate['source'] !== undefined && candidate['source'] !== 'team' && candidate['source'] !== 'system'))
213
+ return;
214
+ const access = candidate['access'] === undefined ? undefined : parseAccess(candidate['access']);
215
+ if (candidate['access'] !== undefined && !access)
216
+ return;
217
+ const state = candidate['state'];
218
+ if (!isRecord(state) || Object.keys(state).some(key => !['search', 'filters', 'sorters', 'pagination', 'columnVisibility', 'columnOrder'].includes(key)))
219
+ return;
220
+ if (!isRecord(state['pagination']) || Object.keys(state['pagination']).some(key => !['current', 'pageSize'].includes(key)))
221
+ return;
222
+ if (!isRecord(state['columnVisibility']) || Object.entries(state['columnVisibility'])
223
+ .some(([key, visible]) => !allowedColumnIds.has(key) || typeof visible !== 'boolean'))
224
+ return;
225
+ if (!Array.isArray(state['columnOrder']) || state['columnOrder'].some(key => typeof key !== 'string' || !allowedColumnIds.has(key))
226
+ || new Set(state['columnOrder']).size !== state['columnOrder'].length)
227
+ return;
228
+ if (!Array.isArray(state['sorters']) || state['sorters'].some(sorter => !isRecord(sorter) || Object.keys(sorter).some(key => !['field', 'order'].includes(key))))
229
+ return;
230
+ const exactFilter = (filter, depth = 0) => {
231
+ if (!isRecord(filter) || depth > 20)
232
+ return false;
233
+ if ('field' in filter)
234
+ return Object.keys(filter).every(key => ['field', 'operator', 'value'].includes(key));
235
+ return Object.keys(filter).every(key => ['operator', 'value'].includes(key))
236
+ && Array.isArray(filter['value']) && filter['value'].every(child => exactFilter(child, depth + 1));
237
+ };
238
+ if (!Array.isArray(state['filters']) || !state['filters'].every(filter => exactFilter(filter)))
239
+ return;
240
+ const views = readSavedListViews(JSON.stringify({ version: STORAGE_VERSION, views: [candidate] }), allowedColumnIds);
241
+ const view = views[0];
242
+ if (!view || view.name !== candidate['name'])
243
+ return;
244
+ if (expected && (view.id !== expected.id || candidate['source'] !== expected.source))
245
+ return;
246
+ return {
247
+ ...view,
248
+ ...(candidate['source'] === undefined ? {} : { source: candidate['source'] }),
249
+ ...(candidate['readOnly'] === undefined ? {} : { readOnly: candidate['readOnly'] }),
250
+ ...(candidate['default'] === undefined ? {} : { default: candidate['default'] }),
251
+ ...(access === undefined ? {} : { access }),
252
+ };
253
+ };
254
+ if (snapshot['ok'] === true) {
255
+ if (!isPositiveInteger(snapshot['version'], Number.MAX_SAFE_INTEGER))
256
+ return;
257
+ if (expected?.expectedVersion !== undefined && expected.expectedVersion !== null
258
+ && snapshot['version'] <= expected.expectedVersion)
259
+ return;
260
+ const view = parseReceiptView(snapshot['view'], snapshot['version']);
261
+ if (!view)
262
+ return;
263
+ return { ok: true, view, version: snapshot['version'] };
264
+ }
265
+ if (snapshot['code'] !== 'VERSION_CONFLICT' || !isPositiveInteger(snapshot['version'], Number.MAX_SAFE_INTEGER))
266
+ return;
267
+ const current = parseReceiptView(snapshot['current'], snapshot['version']);
268
+ if (!current)
269
+ return;
270
+ return { ok: false, code: 'VERSION_CONFLICT', current, version: snapshot['version'] };
271
+ }
272
+ catch {
273
+ return;
274
+ }
275
+ }
276
+ export function decodeSavedListViewRemoveResult(value, expected) {
277
+ try {
278
+ const snapshot = snapshotPlainData(value);
279
+ if (!isRecord(snapshot) || snapshot['ok'] !== true
280
+ || Object.keys(snapshot).some(key => !['ok', 'id', 'version'].includes(key))
281
+ || snapshot['id'] !== expected.id
282
+ || !isPositiveInteger(expected.expectedVersion, Number.MAX_SAFE_INTEGER)
283
+ || !isPositiveInteger(snapshot['version'], Number.MAX_SAFE_INTEGER)
284
+ || snapshot['version'] <= expected.expectedVersion)
285
+ return;
286
+ return { ok: true, id: expected.id, version: snapshot['version'] };
287
+ }
288
+ catch {
289
+ return;
290
+ }
291
+ }
292
+ export function decodeRemoteSavedListViews(value, allowedColumnIds, writable = false) {
293
+ try {
294
+ const snapshot = snapshotPlainData(value);
295
+ if (!Array.isArray(snapshot))
296
+ return [];
297
+ return readSavedListViews(JSON.stringify({ version: STORAGE_VERSION, views: snapshot }), allowedColumnIds, 'team')
298
+ .map(view => {
299
+ const entry = snapshot.find(entry => isRecord(entry) && entry['id'] === view.id);
300
+ return {
301
+ ...view,
302
+ readOnly: !writable || !view.version || !isRecord(entry) || entry['readOnly'] !== false,
303
+ ...(isRecord(entry) && entry['default'] === true ? { default: true } : {}),
304
+ };
305
+ });
306
+ }
307
+ catch {
308
+ return [];
309
+ }
310
+ }
124
311
  export function serializeSavedListViews(views) {
125
312
  return JSON.stringify({ version: STORAGE_VERSION, views: views.slice(0, MAX_SAVED_VIEWS) });
126
313
  }
@@ -137,10 +324,11 @@ export function listPreferenceScopeId(scope) {
137
324
  `r:${encodeURIComponent(scope.resourceName)}`,
138
325
  `p:${encodeURIComponent(scope.providerName)}`,
139
326
  `t:${encodeScopeValue(scope.tenantIdentity)}`,
327
+ ...(scope.identityKey === undefined ? [] : [`u:${encodeScopeValue(scope.identityKey)}`]),
140
328
  ].join('|');
141
329
  }
142
330
  export function canMigrateLegacyListPreferences(scope) {
143
- return scope.providerName === 'default' && scope.tenantIdentity === undefined;
331
+ return scope.providerName === 'default' && scope.tenantIdentity === undefined && scope.identityKey === undefined;
144
332
  }
145
333
  export function savedListViewsStorageKey(scope) {
146
334
  return `svadmin-list-views-v2-${listPreferenceScopeId(scope)}`;
@@ -0,0 +1,14 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { SvarRecordId } from './svar-grid-operations.js';
3
+ export interface SvarCellContent {
4
+ readonly id: SvarRecordId;
5
+ readonly field: string;
6
+ readonly value: unknown;
7
+ readonly record: Record<string, unknown>;
8
+ }
9
+ export interface SvarCellContext {
10
+ readonly render: () => Snippet<[SvarCellContent]> | undefined;
11
+ readonly resolve: (row: unknown, column: unknown) => SvarCellContent | undefined;
12
+ }
13
+ /** 仅可信宿主可提供原生 snippet;不把引擎 api 或 exec 传给内容组件。 */
14
+ export declare const SVAR_CELL_CONTEXT: unique symbol;
@@ -0,0 +1,2 @@
1
+ /** 仅可信宿主可提供原生 snippet;不把引擎 api 或 exec 传给内容组件。 */
2
+ export const SVAR_CELL_CONTEXT = Symbol('svadmin.svar.cell');