@poirazis/supercomponents-shared 1.0.11 → 1.0.18
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/dist/index.js +5798 -5760
- package/dist/index.umd.cjs +10 -10
- package/dist/style.css +1 -1
- package/package.json +4 -4
- package/src/lib/SuperForm/InnerForm.svelte +77 -124
- package/src/lib/SuperForm/SuperForm.svelte +38 -42
- package/src/lib/SuperTable/SuperTable.svelte +17 -35
- package/src/lib/SuperTableCells/CellCommon.css +2 -0
- package/src/lib/SuperTableCells/CellIcon.svelte +0 -1
- package/src/lib/SuperTableCells/CellString.svelte +12 -1
- package/src/lib/SuperTableCells/CellStringSimple.svelte +2 -2
- package/src/lib/SuperTableColumn/parts/SuperColumnBody.svelte +1 -1
- package/src/lib/SuperTableColumn/parts/SuperColumnRow.svelte +15 -8
- package/src/lib/SuperForm/index.js +0 -0
@@ -1,14 +1,22 @@
|
|
1
1
|
<script lang="ts">
|
2
|
-
import { setContext, getContext } from "svelte";
|
2
|
+
import { setContext, getContext, createEventDispatcher } from "svelte";
|
3
3
|
import type { Readable, Writable } from "svelte/store";
|
4
4
|
import { derived, get, writable } from "svelte/store";
|
5
|
-
|
6
|
-
|
5
|
+
import type {
|
6
|
+
DataFetchDatasource,
|
7
|
+
FieldSchema,
|
8
|
+
FieldType,
|
9
|
+
Table,
|
10
|
+
TableSchema,
|
11
|
+
UIFieldValidationRule,
|
12
|
+
} from "@budibase/types";
|
13
|
+
|
14
|
+
const dispatch = createEventDispatcher();
|
7
15
|
|
8
16
|
type FieldInfo<T = any> = {
|
9
17
|
name: string;
|
10
18
|
step: number;
|
11
|
-
type: FieldType
|
19
|
+
type: `${FieldType}`;
|
12
20
|
fieldState: {
|
13
21
|
fieldId: string;
|
14
22
|
value: T;
|
@@ -27,28 +35,23 @@
|
|
27
35
|
fieldSchema: FieldSchema | {};
|
28
36
|
};
|
29
37
|
|
30
|
-
export let dataSource:
|
38
|
+
export let dataSource: DataFetchDatasource | undefined = undefined;
|
31
39
|
export let disabled: boolean = false;
|
32
40
|
export let readonly: boolean = false;
|
33
41
|
export let initialValues: Record<string, any> | undefined = undefined;
|
34
42
|
export let size: "Medium" | "Large" | undefined = undefined;
|
35
|
-
export let schema:
|
36
|
-
export let definition:
|
43
|
+
export let schema: TableSchema | undefined = undefined;
|
44
|
+
export let definition: Table | undefined = undefined;
|
37
45
|
export let disableSchemaValidation: boolean = false;
|
38
46
|
export let editAutoColumns: boolean = false;
|
39
|
-
|
40
|
-
// For internal use only, to disable context when being used with standalone fields
|
41
47
|
export let provideContext: boolean = true;
|
42
|
-
|
43
|
-
// We export this store so that when we remount the inner form we can still
|
44
|
-
// persist what step we're on
|
45
48
|
export let currentStep: Writable<number>;
|
46
49
|
|
47
|
-
const
|
48
|
-
|
50
|
+
const { Provider, ActionTypes, createValidatorFromConstraints } =
|
51
|
+
getContext("sdk");
|
49
52
|
|
50
53
|
let fields: Writable<FieldInfo>[] = [];
|
51
|
-
const formState = writable({
|
54
|
+
export const formState = writable({
|
52
55
|
values: {},
|
53
56
|
errors: {},
|
54
57
|
valid: true,
|
@@ -56,23 +59,12 @@
|
|
56
59
|
currentStep: get(currentStep),
|
57
60
|
});
|
58
61
|
|
59
|
-
// Reactive derived stores to derive form state from field array
|
60
62
|
$: values = deriveFieldProperty(fields, (f) => f.fieldState.value);
|
61
63
|
$: errors = deriveFieldProperty(fields, (f) => f.fieldState.error);
|
62
64
|
$: enrichments = deriveBindingEnrichments(fields);
|
63
65
|
$: valid = !Object.values($errors).some((error) => error != null);
|
64
|
-
|
65
|
-
$: dirty = derived(
|
66
|
-
fields,
|
67
|
-
(fieldsValue) => fieldsValue.some((field) => {
|
68
|
-
const { value, defaultValue } = field.fieldState;
|
69
|
-
// Compare current value with default value to determine if field is dirty
|
70
|
-
// Using JSON.stringify for deep comparison of objects and arrays
|
71
|
-
return JSON.stringify(value) !== JSON.stringify(defaultValue);
|
72
|
-
})
|
73
|
-
);
|
66
|
+
$: dirty = deriveDirtyStatus(fields, initialValues);
|
74
67
|
|
75
|
-
// Derive whether the current form step is valid
|
76
68
|
$: currentStepValid = derived(
|
77
69
|
[currentStep, ...fields],
|
78
70
|
([currentStepValue, ...fieldsValue]) => {
|
@@ -82,7 +74,14 @@
|
|
82
74
|
}
|
83
75
|
);
|
84
76
|
|
85
|
-
//
|
77
|
+
// Offer the form as a bindable property so it can be puppeteered by parent components
|
78
|
+
export let form;
|
79
|
+
$: form = {
|
80
|
+
formState,
|
81
|
+
formApi,
|
82
|
+
dataSource,
|
83
|
+
};
|
84
|
+
|
86
85
|
$: {
|
87
86
|
formState.set({
|
88
87
|
values: $values,
|
@@ -93,14 +92,10 @@
|
|
93
92
|
});
|
94
93
|
}
|
95
94
|
|
96
|
-
// Derive value of whole form
|
97
95
|
$: formValue = deriveFormValue(initialValues, $values, $enrichments);
|
98
96
|
|
99
|
-
// Create data context to provide
|
100
97
|
$: dataContext = {
|
101
98
|
...formValue,
|
102
|
-
|
103
|
-
// These static values are prefixed to avoid clashes with actual columns
|
104
99
|
__value: formValue,
|
105
100
|
__valid: valid,
|
106
101
|
__dirty: $dirty,
|
@@ -108,8 +103,6 @@
|
|
108
103
|
__currentStepValid: $currentStepValid,
|
109
104
|
};
|
110
105
|
|
111
|
-
// Generates a derived store from an array of fields, comprised of a map of
|
112
|
-
// extracted values from the field array
|
113
106
|
const deriveFieldProperty = (
|
114
107
|
fieldStores: Readable<FieldInfo>[],
|
115
108
|
getProp: (_field: FieldInfo) => any
|
@@ -122,8 +115,19 @@
|
|
122
115
|
});
|
123
116
|
};
|
124
117
|
|
125
|
-
|
126
|
-
|
118
|
+
const deriveDirtyStatus = (
|
119
|
+
fieldStores: Readable<FieldInfo>[],
|
120
|
+
initialValues: Record<string, any> | undefined
|
121
|
+
) => {
|
122
|
+
return derived(fieldStores, (fieldValues) => {
|
123
|
+
return fieldValues.some((field) => {
|
124
|
+
const initial =
|
125
|
+
deepGet(initialValues, field.name) ?? field.fieldState.defaultValue;
|
126
|
+
return field.fieldState.value !== initial;
|
127
|
+
});
|
128
|
+
});
|
129
|
+
};
|
130
|
+
|
127
131
|
const deriveBindingEnrichments = (fieldStores: Readable<FieldInfo>[]) => {
|
128
132
|
return derived(fieldStores, (fieldValues) => {
|
129
133
|
const enrichments: Record<string, string> = {};
|
@@ -141,16 +145,12 @@
|
|
141
145
|
});
|
142
146
|
};
|
143
147
|
|
144
|
-
// Derive the overall form value and deeply set all field paths so that we
|
145
|
-
// can support things like JSON fields.
|
146
148
|
const deriveFormValue = (
|
147
149
|
initialValues: Record<string, any> | undefined,
|
148
150
|
values: Record<string, any>,
|
149
151
|
enrichments: Record<string, string>
|
150
152
|
) => {
|
151
153
|
let formValue = cloneDeep(initialValues || {});
|
152
|
-
|
153
|
-
// We need to sort the keys to avoid a JSON field overwriting a nested field
|
154
154
|
const sortedFields = Object.entries(values || {})
|
155
155
|
.map(([key, value]) => {
|
156
156
|
const field = getField(key);
|
@@ -164,7 +164,6 @@
|
|
164
164
|
return a.lastUpdate - b.lastUpdate;
|
165
165
|
});
|
166
166
|
|
167
|
-
// Merge all values and enrichments into a single value
|
168
167
|
sortedFields.forEach(({ key, value }) => {
|
169
168
|
deepSet(formValue, key, value);
|
170
169
|
});
|
@@ -174,19 +173,15 @@
|
|
174
173
|
return formValue;
|
175
174
|
};
|
176
175
|
|
177
|
-
// Searches the field array for a certain field
|
178
176
|
const getField = (name: string) => {
|
179
177
|
return fields.find((field) => get(field).name === name)!;
|
180
178
|
};
|
181
179
|
|
182
|
-
// Sanitises a value by ensuring it doesn't contain any invalid data
|
183
180
|
const sanitiseValue = (
|
184
181
|
value: any,
|
185
182
|
schema: FieldSchema | undefined,
|
186
|
-
type: FieldType
|
183
|
+
type: `${FieldType}`
|
187
184
|
) => {
|
188
|
-
// Check arrays - remove any values not present in the field schema and
|
189
|
-
// convert any values supplied to strings
|
190
185
|
if (Array.isArray(value) && type === "array" && schema) {
|
191
186
|
const options = schema?.constraints?.inclusion || [];
|
192
187
|
return value
|
@@ -209,7 +204,6 @@
|
|
209
204
|
if (!field) {
|
210
205
|
return;
|
211
206
|
}
|
212
|
-
// Create validation function based on field schema
|
213
207
|
const schemaConstraints = disableSchemaValidation
|
214
208
|
? null
|
215
209
|
: schema?.[field]?.constraints;
|
@@ -220,10 +214,8 @@
|
|
220
214
|
definition
|
221
215
|
);
|
222
216
|
|
223
|
-
// Sanitise the default value to ensure it doesn't contain invalid data
|
224
217
|
defaultValue = sanitiseValue(defaultValue, schema?.[field], type);
|
225
218
|
|
226
|
-
// If we've already registered this field then keep some existing state
|
227
219
|
let initialValue = deepGet(initialValues, field) ?? defaultValue;
|
228
220
|
let initialError = null;
|
229
221
|
let fieldId = `id-${uuid()}`;
|
@@ -231,24 +223,16 @@
|
|
231
223
|
if (existingField) {
|
232
224
|
const { fieldState } = get(existingField);
|
233
225
|
fieldId = fieldState.fieldId;
|
234
|
-
|
235
|
-
// Determine the initial value for this field, reusing the current
|
236
|
-
// value if one exists
|
237
226
|
if (fieldState.value != null && fieldState.value !== "") {
|
238
227
|
initialValue = fieldState.value;
|
239
228
|
}
|
240
|
-
|
241
|
-
// If this field has already been registered and we previously had an
|
242
|
-
// error set, then re-run the validator to see if we can unset it
|
243
229
|
if (fieldState.error) {
|
244
230
|
initialError = validator?.(initialValue);
|
245
231
|
}
|
246
232
|
}
|
247
233
|
|
248
|
-
// Auto columns are always disabled
|
249
234
|
const isAutoColumn = !!schema?.[field]?.autocolumn;
|
250
235
|
|
251
|
-
// Construct field info
|
252
236
|
const fieldInfo = writable<FieldInfo>({
|
253
237
|
name: field,
|
254
238
|
type,
|
@@ -269,7 +253,6 @@
|
|
269
253
|
fieldSchema: schema?.[field] ?? {},
|
270
254
|
});
|
271
255
|
|
272
|
-
// Add this field
|
273
256
|
if (existingField) {
|
274
257
|
const otherFields = fields.filter((info) => get(info).name !== field);
|
275
258
|
fields = [...otherFields, fieldInfo];
|
@@ -283,8 +266,6 @@
|
|
283
266
|
const stepFields = fields.filter(
|
284
267
|
(field) => get(field).step === get(currentStep)
|
285
268
|
);
|
286
|
-
// We want to validate every field (even if validation fails early) to
|
287
|
-
// ensure that all fields are populated with errors if invalid
|
288
269
|
let valid = true;
|
289
270
|
let hasScrolled = false;
|
290
271
|
stepFields.forEach((field) => {
|
@@ -295,14 +276,13 @@
|
|
295
276
|
hasScrolled = true;
|
296
277
|
}
|
297
278
|
});
|
298
|
-
|
299
279
|
return valid;
|
300
280
|
},
|
301
281
|
reset: () => {
|
302
|
-
// Reset the form by resetting each individual field
|
303
282
|
fields.forEach((field) => {
|
304
283
|
get(field).fieldApi.reset();
|
305
284
|
});
|
285
|
+
dispatch("reset");
|
306
286
|
},
|
307
287
|
changeStep: ({
|
308
288
|
type,
|
@@ -344,20 +324,16 @@
|
|
344
324
|
},
|
345
325
|
};
|
346
326
|
|
347
|
-
// Creates an API for a specific field
|
348
327
|
const makeFieldApi = (field: string) => {
|
349
|
-
// Sets the value for a certain field and invokes validation
|
350
328
|
const setValue = (value: any, skipCheck = false) => {
|
351
329
|
const fieldInfo = getField(field);
|
352
330
|
const { fieldState } = get(fieldInfo);
|
353
331
|
const { validator } = fieldState;
|
354
332
|
|
355
|
-
// Skip if the value is the same
|
356
333
|
if (!skipCheck && fieldState.value === value) {
|
357
334
|
return false;
|
358
335
|
}
|
359
336
|
|
360
|
-
// Update field state
|
361
337
|
const error = validator?.(value);
|
362
338
|
fieldInfo.update((state) => {
|
363
339
|
state.fieldState.value = value;
|
@@ -365,17 +341,15 @@
|
|
365
341
|
state.fieldState.lastUpdate = Date.now();
|
366
342
|
return state;
|
367
343
|
});
|
368
|
-
|
344
|
+
dispatch("change", { field, value });
|
369
345
|
return true;
|
370
346
|
};
|
371
347
|
|
372
|
-
// Clears the value of a certain field back to the default value
|
373
348
|
const reset = () => {
|
374
349
|
const fieldInfo = getField(field);
|
375
350
|
const { fieldState } = get(fieldInfo);
|
376
351
|
const newValue = fieldState.defaultValue;
|
377
352
|
|
378
|
-
// Update field state
|
379
353
|
fieldInfo.update((state) => {
|
380
354
|
state.fieldState.value = newValue;
|
381
355
|
state.fieldState.error = null;
|
@@ -384,8 +358,6 @@
|
|
384
358
|
});
|
385
359
|
};
|
386
360
|
|
387
|
-
// We don't want to actually remove the field state when deregistering, just
|
388
|
-
// remove any errors and validation
|
389
361
|
const deregister = () => {
|
390
362
|
const fieldInfo = getField(field);
|
391
363
|
fieldInfo.update((state) => {
|
@@ -395,14 +367,9 @@
|
|
395
367
|
});
|
396
368
|
};
|
397
369
|
|
398
|
-
// Updates the disabled state of a certain field
|
399
370
|
const setDisabled = (fieldDisabled: boolean) => {
|
400
371
|
const fieldInfo = getField(field);
|
401
|
-
|
402
|
-
// Auto columns are always disabled
|
403
372
|
const isAutoColumn = !!schema?.[field]?.autocolumn;
|
404
|
-
|
405
|
-
// Update disabled state
|
406
373
|
fieldInfo.update((state) => {
|
407
374
|
state.fieldState.disabled = disabled || fieldDisabled || isAutoColumn;
|
408
375
|
return state;
|
@@ -415,7 +382,6 @@
|
|
415
382
|
setDisabled,
|
416
383
|
deregister,
|
417
384
|
validate: () => {
|
418
|
-
// Validate the field by force setting the same value again
|
419
385
|
const fieldInfo = getField(field);
|
420
386
|
setValue(get(fieldInfo).fieldState.value, true);
|
421
387
|
return !get(fieldInfo).fieldState.error;
|
@@ -423,18 +389,12 @@
|
|
423
389
|
};
|
424
390
|
};
|
425
391
|
|
426
|
-
// Provide form state and api for full control by children
|
427
392
|
setContext("form", {
|
428
393
|
formState,
|
429
394
|
formApi,
|
430
|
-
|
431
|
-
// Datasource is needed by attachment fields to be able to upload files
|
432
|
-
// to the correct table ID
|
433
395
|
dataSource,
|
434
396
|
});
|
435
397
|
|
436
|
-
// Provide form step context so that forms without any step components
|
437
|
-
// register their fields to step 1
|
438
398
|
setContext("form-step", writable(1));
|
439
399
|
|
440
400
|
const handleUpdateFieldValue = ({
|
@@ -474,7 +434,6 @@
|
|
474
434
|
}
|
475
435
|
};
|
476
436
|
|
477
|
-
// Action context to pass to children
|
478
437
|
const actions = [
|
479
438
|
{ type: ActionTypes.ValidateForm, callback: formApi.validate },
|
480
439
|
{ type: ActionTypes.ClearForm, callback: formApi.reset },
|
@@ -483,27 +442,23 @@
|
|
483
442
|
{ type: ActionTypes.ScrollTo, callback: handleScrollToField },
|
484
443
|
];
|
485
444
|
|
486
|
-
//
|
487
|
-
function uuid() {
|
488
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
return v.toString(16);
|
494
|
-
}
|
495
|
-
);
|
445
|
+
// Generate a UUID (simplified version for brevity)
|
446
|
+
function uuid(): string {
|
447
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
448
|
+
const r = (Math.random() * 16) | 0;
|
449
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
450
|
+
return v.toString(16);
|
451
|
+
});
|
496
452
|
}
|
497
453
|
|
498
|
-
|
499
|
-
|
454
|
+
// Deep clone an object
|
455
|
+
function cloneDeep<T>(obj: T): T {
|
456
|
+
if (obj == null || typeof obj !== "object") {
|
500
457
|
return obj;
|
501
458
|
}
|
502
|
-
|
503
459
|
if (Array.isArray(obj)) {
|
504
|
-
return obj.map(
|
460
|
+
return obj.map(cloneDeep) as any;
|
505
461
|
}
|
506
|
-
|
507
462
|
const cloned: any = {};
|
508
463
|
for (const key in obj) {
|
509
464
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
@@ -513,46 +468,44 @@
|
|
513
468
|
return cloned;
|
514
469
|
}
|
515
470
|
|
516
|
-
|
517
|
-
|
518
|
-
|
471
|
+
// Get a value from an object using a dot-notation path
|
472
|
+
function deepGet(obj: any, path: string | string[]): any {
|
473
|
+
if (!obj || !path) {
|
474
|
+
return undefined;
|
475
|
+
}
|
476
|
+
const pathArray = Array.isArray(path) ? path : path.split(".");
|
519
477
|
let current = obj;
|
520
|
-
|
521
|
-
|
522
|
-
if (current === null || current === undefined) {
|
478
|
+
for (const key of pathArray) {
|
479
|
+
if (current == null) {
|
523
480
|
return undefined;
|
524
481
|
}
|
525
|
-
current = current[
|
482
|
+
current = current[key];
|
526
483
|
}
|
527
|
-
|
528
484
|
return current;
|
529
485
|
}
|
530
486
|
|
531
|
-
|
532
|
-
|
533
|
-
|
487
|
+
// Set a value in an object using a dot-notation path
|
488
|
+
function deepSet(obj: any, path: string | string[], value: any): void {
|
489
|
+
if (!obj || !path) {
|
490
|
+
return;
|
491
|
+
}
|
492
|
+
const pathArray = Array.isArray(path) ? path : path.split(".");
|
534
493
|
let current = obj;
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
current[part] = {};
|
494
|
+
for (let i = 0; i < pathArray.length - 1; i++) {
|
495
|
+
const key = pathArray[i];
|
496
|
+
if (!current[key] || typeof current[key] !== "object") {
|
497
|
+
current[key] = {};
|
540
498
|
}
|
541
|
-
current = current[
|
499
|
+
current = current[key];
|
542
500
|
}
|
543
|
-
|
544
|
-
current[parts[parts.length - 1]] = value;
|
501
|
+
current[pathArray[pathArray.length - 1]] = value;
|
545
502
|
}
|
546
503
|
</script>
|
547
504
|
|
548
505
|
{#if provideContext}
|
549
506
|
<Provider {actions} data={dataContext}>
|
550
|
-
<
|
551
|
-
<slot />
|
552
|
-
</div>
|
507
|
+
<slot />
|
553
508
|
</Provider>
|
554
509
|
{:else}
|
555
|
-
<
|
556
|
-
<slot />
|
557
|
-
</div>
|
510
|
+
<slot />
|
558
511
|
{/if}
|
@@ -2,23 +2,37 @@
|
|
2
2
|
import { getContext } from "svelte";
|
3
3
|
import InnerForm from "./InnerForm.svelte";
|
4
4
|
import { writable } from "svelte/store";
|
5
|
-
import type {
|
5
|
+
import type {
|
6
|
+
DataFetchDatasource,
|
7
|
+
Table,
|
8
|
+
TableSchema,
|
9
|
+
} from "@budibase/types";
|
6
10
|
|
7
|
-
|
8
|
-
|
11
|
+
// Local utility function
|
12
|
+
const hashString = (str: string): string => {
|
13
|
+
let hash = 0;
|
14
|
+
for (let i = 0; i < str.length; i++) {
|
15
|
+
const char = str.charCodeAt(i);
|
16
|
+
hash = (hash << 5) - hash + char;
|
17
|
+
hash = hash & hash; // Convert to 32-bit integer
|
18
|
+
}
|
19
|
+
return hash.toString(16);
|
20
|
+
};
|
21
|
+
|
22
|
+
export let dataSource: DataFetchDatasource;
|
23
|
+
export let size: "Medium" | "Large";
|
9
24
|
export let disabled: boolean = false;
|
10
25
|
export let readonly: boolean = false;
|
11
|
-
export let actionType: "Create"
|
26
|
+
export let actionType: "Create" = "Create";
|
12
27
|
export let initialFormStep: string | number = 1;
|
13
|
-
|
14
|
-
// Not exposed as a builder setting. Used internally to disable validation
|
15
|
-
// for fields rendered in things like search blocks.
|
16
28
|
export let disableSchemaValidation: boolean = false;
|
17
|
-
|
18
|
-
// Not exposed as a builder setting. Used internally to allow searching on
|
19
|
-
// auto columns.
|
20
29
|
export let editAutoColumns: boolean = false;
|
21
30
|
|
31
|
+
// Export the full form API to be used by parents
|
32
|
+
export let form;
|
33
|
+
export let formState;
|
34
|
+
export let row;
|
35
|
+
|
22
36
|
const context = getContext("context");
|
23
37
|
const component = getContext("component");
|
24
38
|
const { fetchDatasourceSchema, fetchDatasourceDefinition } =
|
@@ -32,8 +46,8 @@
|
|
32
46
|
return parsedFormStep;
|
33
47
|
};
|
34
48
|
|
35
|
-
let definition:
|
36
|
-
let schema:
|
49
|
+
let definition: Table | undefined;
|
50
|
+
let schema: TableSchema | undefined;
|
37
51
|
let loaded = false;
|
38
52
|
let currentStep =
|
39
53
|
getContext("current-step") || writable(getInitialFormStep());
|
@@ -50,34 +64,30 @@
|
|
50
64
|
schemaKey + JSON.stringify(initialValues) + disabled + readonly
|
51
65
|
);
|
52
66
|
|
53
|
-
// Returns the closes data context which isn't a built in context
|
54
67
|
const getInitialValues = (
|
55
68
|
type: string,
|
56
|
-
dataSource:
|
69
|
+
dataSource: DataFetchDatasource,
|
57
70
|
path: string[],
|
58
71
|
context: Record<string, any>
|
59
72
|
) => {
|
60
|
-
// Only inherit values for update forms
|
61
73
|
if (type !== "Update") {
|
62
74
|
return {};
|
63
75
|
}
|
64
|
-
// Only inherit values for forms targeting internal tables
|
65
76
|
const dsType = dataSource?.type;
|
66
77
|
if (dsType !== "table" && dsType !== "viewV2") {
|
67
78
|
return {};
|
68
79
|
}
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
80
|
+
|
81
|
+
if (row && dsType === "table" && row?.tableId === dataSource.tableId) {
|
82
|
+
return row;
|
83
|
+
}
|
84
|
+
for (let id of path.toReversed().slice(1)) {
|
74
85
|
if (
|
75
86
|
dataSource.type === "viewV2" &&
|
76
87
|
context[id]?._viewId === dataSource.id
|
77
88
|
) {
|
78
89
|
return context[id];
|
79
90
|
}
|
80
|
-
// Check for matching table datasource
|
81
91
|
if (
|
82
92
|
dataSource.type === "table" &&
|
83
93
|
context[id]?.tableId === dataSource.tableId
|
@@ -88,8 +98,7 @@
|
|
88
98
|
return {};
|
89
99
|
};
|
90
100
|
|
91
|
-
|
92
|
-
const fetchSchema = async (dataSource: any) => {
|
101
|
+
const fetchSchema = async (dataSource: DataFetchDatasource) => {
|
93
102
|
try {
|
94
103
|
definition = await fetchDatasourceDefinition(dataSource);
|
95
104
|
} catch (error) {
|
@@ -102,12 +111,7 @@
|
|
102
111
|
}
|
103
112
|
};
|
104
113
|
|
105
|
-
|
106
|
-
// simply stringify the whole schema as there are array fields which have
|
107
|
-
// random order.
|
108
|
-
const generateSchemaKey = (
|
109
|
-
schema: Record<string, FieldSchema> | undefined
|
110
|
-
) => {
|
114
|
+
const generateSchemaKey = (schema: TableSchema | undefined) => {
|
111
115
|
if (!schema) {
|
112
116
|
return null;
|
113
117
|
}
|
@@ -115,23 +119,13 @@
|
|
115
119
|
fields.sort();
|
116
120
|
return fields.map((field) => `${field}:${schema[field].type}`).join("-");
|
117
121
|
};
|
118
|
-
|
119
|
-
// Helper function to generate a hash string from input
|
120
|
-
function hashString(str: string) {
|
121
|
-
let hash = 0;
|
122
|
-
if (str.length === 0) return hash.toString();
|
123
|
-
for (let i = 0; i < str.length; i++) {
|
124
|
-
const char = str.charCodeAt(i);
|
125
|
-
hash = (hash << 5) - hash + char;
|
126
|
-
hash = hash & hash; // Convert to 32bit integer
|
127
|
-
}
|
128
|
-
return hash.toString();
|
129
|
-
}
|
130
122
|
</script>
|
131
123
|
|
132
124
|
{#if loaded}
|
133
125
|
{#key resetKey}
|
134
126
|
<InnerForm
|
127
|
+
bind:form
|
128
|
+
bind:formState
|
135
129
|
{dataSource}
|
136
130
|
{size}
|
137
131
|
{disabled}
|
@@ -142,6 +136,8 @@
|
|
142
136
|
{disableSchemaValidation}
|
143
137
|
{editAutoColumns}
|
144
138
|
{currentStep}
|
139
|
+
on:change
|
140
|
+
on:reset
|
145
141
|
>
|
146
142
|
<slot />
|
147
143
|
</InnerForm>
|