@routevn/creator-model 1.1.4 → 1.1.6
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/package.json +1 -1
- package/src/model.js +777 -30
- package/src/systemVariables.js +27 -0
package/package.json
CHANGED
package/src/model.js
CHANGED
|
@@ -38,6 +38,7 @@ const createEmptyCollectionState = () => ({
|
|
|
38
38
|
items: {},
|
|
39
39
|
tree: [],
|
|
40
40
|
});
|
|
41
|
+
|
|
41
42
|
const normalizeStateCollections = (state) => {
|
|
42
43
|
if (!isPlainObject(state)) {
|
|
43
44
|
return state;
|
|
@@ -108,7 +109,15 @@ const ANIMATION_EASING_KEYS = [
|
|
|
108
109
|
];
|
|
109
110
|
const VARIABLE_SCOPE_KEYS = ["context", "global-device", "global-account"];
|
|
110
111
|
const VARIABLE_TYPE_KEYS = ["string", "number", "boolean"];
|
|
111
|
-
const LAYOUT_TYPE_KEYS = [
|
|
112
|
+
const LAYOUT_TYPE_KEYS = [
|
|
113
|
+
"normal",
|
|
114
|
+
"save-load",
|
|
115
|
+
"confirmDialog",
|
|
116
|
+
"dialogue",
|
|
117
|
+
"nvl",
|
|
118
|
+
"choice",
|
|
119
|
+
"history",
|
|
120
|
+
];
|
|
112
121
|
const LAYOUT_ELEMENT_TEXT_STYLE_ALIGN_KEYS = ["left", "center", "right"];
|
|
113
122
|
const LAYOUT_TEXT_REVEAL_EFFECT_KEYS = ["typewriter", "softWipe", "none"];
|
|
114
123
|
const LAYOUT_ELEMENT_BASE_TYPES = [
|
|
@@ -122,17 +131,30 @@ const LAYOUT_ELEMENT_BASE_TYPES = [
|
|
|
122
131
|
"text-ref-character-name",
|
|
123
132
|
"text-revealing-ref-dialogue-content",
|
|
124
133
|
"text-ref-choice-item-content",
|
|
134
|
+
"text-ref-save-load-slot-date",
|
|
125
135
|
"text-ref-dialogue-line-character-name",
|
|
126
136
|
"text-ref-dialogue-line-content",
|
|
137
|
+
"text-ref-history-line-character-name",
|
|
138
|
+
"text-ref-history-line-content",
|
|
139
|
+
"sprite-ref-save-load-slot-image",
|
|
140
|
+
"fragment-ref",
|
|
127
141
|
"container-ref-choice-item",
|
|
142
|
+
"container-ref-save-load-slot",
|
|
128
143
|
"container-ref-dialogue-line",
|
|
144
|
+
"container-ref-history-line",
|
|
145
|
+
"container-ref-confirm-dialog-ok",
|
|
146
|
+
"container-ref-confirm-dialog-cancel",
|
|
129
147
|
];
|
|
130
148
|
export const SCHEMA_VERSION = 2;
|
|
131
149
|
const LAYOUT_CONTAINER_ELEMENT_TYPES = [
|
|
132
150
|
"folder",
|
|
133
151
|
"container",
|
|
134
152
|
"container-ref-choice-item",
|
|
153
|
+
"container-ref-save-load-slot",
|
|
135
154
|
"container-ref-dialogue-line",
|
|
155
|
+
"container-ref-history-line",
|
|
156
|
+
"container-ref-confirm-dialog-ok",
|
|
157
|
+
"container-ref-confirm-dialog-cancel",
|
|
136
158
|
];
|
|
137
159
|
const DOMAIN_ERROR_KIND_BY_NAME = {
|
|
138
160
|
PayloadValidationError: "payload",
|
|
@@ -230,6 +252,81 @@ const isVariableReferenceTarget = (state, variableId) => {
|
|
|
230
252
|
return isPlainObject(variable) && variable.type !== "folder";
|
|
231
253
|
};
|
|
232
254
|
|
|
255
|
+
const LAYOUT_CONDITION_TARGET_SET = new Set([
|
|
256
|
+
"item.savedAt",
|
|
257
|
+
"isLineCompleted",
|
|
258
|
+
"autoMode",
|
|
259
|
+
"skipMode",
|
|
260
|
+
]);
|
|
261
|
+
const VARIABLE_TARGET_DOT_PATTERN = /^variables\.([A-Za-z_$][A-Za-z0-9_$]*)$/;
|
|
262
|
+
const VARIABLE_TARGET_BRACKET_PATTERN = /^variables\[(.+)\]$/;
|
|
263
|
+
|
|
264
|
+
const parseLayoutConditionTarget = (target) => {
|
|
265
|
+
if (!isNonEmptyString(target)) {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (LAYOUT_CONDITION_TARGET_SET.has(target)) {
|
|
270
|
+
return {
|
|
271
|
+
kind: "runtime",
|
|
272
|
+
target,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const dotMatch = target.match(VARIABLE_TARGET_DOT_PATTERN);
|
|
277
|
+
if (dotMatch) {
|
|
278
|
+
return {
|
|
279
|
+
kind: "variable",
|
|
280
|
+
target,
|
|
281
|
+
variableId: dotMatch[1],
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const bracketMatch = target.match(VARIABLE_TARGET_BRACKET_PATTERN);
|
|
286
|
+
if (!bracketMatch) {
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const rawValue = bracketMatch[1].trim();
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
const variableId = JSON.parse(rawValue);
|
|
294
|
+
if (isNonEmptyString(variableId)) {
|
|
295
|
+
return {
|
|
296
|
+
kind: "variable",
|
|
297
|
+
target,
|
|
298
|
+
variableId,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
} catch {}
|
|
302
|
+
|
|
303
|
+
if (rawValue.startsWith("'") && rawValue.endsWith("'")) {
|
|
304
|
+
const variableId = rawValue.slice(1, -1);
|
|
305
|
+
if (isNonEmptyString(variableId)) {
|
|
306
|
+
return {
|
|
307
|
+
kind: "variable",
|
|
308
|
+
target,
|
|
309
|
+
variableId,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return undefined;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const isLayoutConditionTarget = (state, target) => {
|
|
318
|
+
const parsedTarget = parseLayoutConditionTarget(target);
|
|
319
|
+
if (!parsedTarget) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (parsedTarget.kind === "runtime") {
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return isVariableReferenceTarget(state, parsedTarget.variableId);
|
|
328
|
+
};
|
|
329
|
+
|
|
233
330
|
const toDomainErrorDetails = (publicError) => {
|
|
234
331
|
const details = isPlainObject(publicError?.details)
|
|
235
332
|
? { ...publicError.details }
|
|
@@ -2181,6 +2278,29 @@ const validateLayoutElementBorder = ({ border, path, errorFactory }) => {
|
|
|
2181
2278
|
}
|
|
2182
2279
|
};
|
|
2183
2280
|
|
|
2281
|
+
const validateLayoutElementInteraction = ({
|
|
2282
|
+
interaction,
|
|
2283
|
+
path,
|
|
2284
|
+
errorFactory,
|
|
2285
|
+
}) => {
|
|
2286
|
+
if (!isPlainObject(interaction)) {
|
|
2287
|
+
return invalidFromErrorFactory(
|
|
2288
|
+
errorFactory,
|
|
2289
|
+
`${path} must be an object when provided`,
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
if (
|
|
2294
|
+
interaction.inheritToChildren !== undefined &&
|
|
2295
|
+
typeof interaction.inheritToChildren !== "boolean"
|
|
2296
|
+
) {
|
|
2297
|
+
return invalidFromErrorFactory(
|
|
2298
|
+
errorFactory,
|
|
2299
|
+
`${path}.inheritToChildren must be a boolean when provided`,
|
|
2300
|
+
);
|
|
2301
|
+
}
|
|
2302
|
+
};
|
|
2303
|
+
|
|
2184
2304
|
const validateLayoutElementData = ({
|
|
2185
2305
|
data,
|
|
2186
2306
|
path,
|
|
@@ -2216,10 +2336,14 @@ const validateLayoutElementData = ({
|
|
|
2216
2336
|
"textStyleId",
|
|
2217
2337
|
"hoverTextStyleId",
|
|
2218
2338
|
"clickTextStyleId",
|
|
2339
|
+
"conditionalOverrides",
|
|
2219
2340
|
"direction",
|
|
2220
2341
|
"gap",
|
|
2221
2342
|
"containerType",
|
|
2222
2343
|
"scroll",
|
|
2344
|
+
"hover",
|
|
2345
|
+
"click",
|
|
2346
|
+
"rightClick",
|
|
2223
2347
|
"anchorToBottom",
|
|
2224
2348
|
"thumbImageId",
|
|
2225
2349
|
"barImageId",
|
|
@@ -2230,9 +2354,11 @@ const validateLayoutElementData = ({
|
|
|
2230
2354
|
"step",
|
|
2231
2355
|
"initialValue",
|
|
2232
2356
|
"variableId",
|
|
2357
|
+
"fragmentLayoutId",
|
|
2358
|
+
"paginationMode",
|
|
2359
|
+
"paginationVariableId",
|
|
2360
|
+
"paginationSize",
|
|
2233
2361
|
"$when",
|
|
2234
|
-
"click",
|
|
2235
|
-
"rightClick",
|
|
2236
2362
|
"change",
|
|
2237
2363
|
];
|
|
2238
2364
|
|
|
@@ -2281,6 +2407,7 @@ const validateLayoutElementData = ({
|
|
|
2281
2407
|
"min",
|
|
2282
2408
|
"max",
|
|
2283
2409
|
"step",
|
|
2410
|
+
"paginationSize",
|
|
2284
2411
|
"opacity",
|
|
2285
2412
|
]) {
|
|
2286
2413
|
if (data[key] !== undefined && !isFiniteNumber(data[key])) {
|
|
@@ -2322,6 +2449,9 @@ const validateLayoutElementData = ({
|
|
|
2322
2449
|
"clickTextStyleId",
|
|
2323
2450
|
"containerType",
|
|
2324
2451
|
"variableId",
|
|
2452
|
+
"fragmentLayoutId",
|
|
2453
|
+
"paginationMode",
|
|
2454
|
+
"paginationVariableId",
|
|
2325
2455
|
"revealEffect",
|
|
2326
2456
|
"thumbImageId",
|
|
2327
2457
|
"barImageId",
|
|
@@ -2337,6 +2467,191 @@ const validateLayoutElementData = ({
|
|
|
2337
2467
|
}
|
|
2338
2468
|
}
|
|
2339
2469
|
|
|
2470
|
+
if (data.conditionalOverrides !== undefined) {
|
|
2471
|
+
if (!Array.isArray(data.conditionalOverrides)) {
|
|
2472
|
+
return invalidFromErrorFactory(
|
|
2473
|
+
errorFactory,
|
|
2474
|
+
`${path}.conditionalOverrides must be an array when provided`,
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
for (let index = 0; index < data.conditionalOverrides.length; index += 1) {
|
|
2479
|
+
const rule = data.conditionalOverrides[index];
|
|
2480
|
+
const rulePath = `${path}.conditionalOverrides.${index}`;
|
|
2481
|
+
|
|
2482
|
+
if (!isPlainObject(rule)) {
|
|
2483
|
+
return invalidFromErrorFactory(
|
|
2484
|
+
errorFactory,
|
|
2485
|
+
`${rulePath} must be an object`,
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
{
|
|
2490
|
+
const result = validateAllowedKeys({
|
|
2491
|
+
value: rule,
|
|
2492
|
+
allowedKeys: ["when", "set"],
|
|
2493
|
+
path: rulePath,
|
|
2494
|
+
errorFactory,
|
|
2495
|
+
});
|
|
2496
|
+
if (result?.valid === false) {
|
|
2497
|
+
return result;
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
if (!isPlainObject(rule.when)) {
|
|
2502
|
+
return invalidFromErrorFactory(
|
|
2503
|
+
errorFactory,
|
|
2504
|
+
`${rulePath}.when must be an object`,
|
|
2505
|
+
);
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
{
|
|
2509
|
+
const result = validateAllowedKeys({
|
|
2510
|
+
value: rule.when,
|
|
2511
|
+
allowedKeys: ["target", "op", "value"],
|
|
2512
|
+
path: `${rulePath}.when`,
|
|
2513
|
+
errorFactory,
|
|
2514
|
+
});
|
|
2515
|
+
if (result?.valid === false) {
|
|
2516
|
+
return result;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
if (!isNonEmptyString(rule.when.target)) {
|
|
2521
|
+
return invalidFromErrorFactory(
|
|
2522
|
+
errorFactory,
|
|
2523
|
+
`${rulePath}.when.target must be a non-empty string`,
|
|
2524
|
+
);
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
if (!parseLayoutConditionTarget(rule.when.target)) {
|
|
2528
|
+
return invalidFromErrorFactory(
|
|
2529
|
+
errorFactory,
|
|
2530
|
+
`${rulePath}.when.target must be a supported layout condition target`,
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2534
|
+
if (
|
|
2535
|
+
!isString(rule.when.value) &&
|
|
2536
|
+
typeof rule.when.value !== "boolean" &&
|
|
2537
|
+
!isFiniteNumber(rule.when.value)
|
|
2538
|
+
) {
|
|
2539
|
+
return invalidFromErrorFactory(
|
|
2540
|
+
errorFactory,
|
|
2541
|
+
`${rulePath}.when.value must be a string, boolean, or finite number`,
|
|
2542
|
+
);
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
if (rule.when.op !== "eq") {
|
|
2546
|
+
return invalidFromErrorFactory(
|
|
2547
|
+
errorFactory,
|
|
2548
|
+
`${rulePath}.when.op must be "eq"`,
|
|
2549
|
+
);
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
if (!isPlainObject(rule.set)) {
|
|
2553
|
+
return invalidFromErrorFactory(
|
|
2554
|
+
errorFactory,
|
|
2555
|
+
`${rulePath}.set must be an object`,
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
{
|
|
2560
|
+
const result = validateAllowedKeys({
|
|
2561
|
+
value: rule.set,
|
|
2562
|
+
allowedKeys: [
|
|
2563
|
+
"textStyleId",
|
|
2564
|
+
"hoverTextStyleId",
|
|
2565
|
+
"clickTextStyleId",
|
|
2566
|
+
"imageId",
|
|
2567
|
+
"hoverImageId",
|
|
2568
|
+
"clickImageId",
|
|
2569
|
+
"opacity",
|
|
2570
|
+
"anchorX",
|
|
2571
|
+
"anchorY",
|
|
2572
|
+
"visible",
|
|
2573
|
+
"textStyle",
|
|
2574
|
+
],
|
|
2575
|
+
path: `${rulePath}.set`,
|
|
2576
|
+
errorFactory,
|
|
2577
|
+
});
|
|
2578
|
+
if (result?.valid === false) {
|
|
2579
|
+
return result;
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
for (const field of [
|
|
2584
|
+
"textStyleId",
|
|
2585
|
+
"hoverTextStyleId",
|
|
2586
|
+
"clickTextStyleId",
|
|
2587
|
+
"imageId",
|
|
2588
|
+
"hoverImageId",
|
|
2589
|
+
"clickImageId",
|
|
2590
|
+
]) {
|
|
2591
|
+
if (
|
|
2592
|
+
rule.set[field] !== undefined &&
|
|
2593
|
+
!isNonEmptyString(rule.set[field])
|
|
2594
|
+
) {
|
|
2595
|
+
return invalidFromErrorFactory(
|
|
2596
|
+
errorFactory,
|
|
2597
|
+
`${rulePath}.set.${field} must be a non-empty string when provided`,
|
|
2598
|
+
);
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
if (
|
|
2603
|
+
rule.set.opacity !== undefined &&
|
|
2604
|
+
(!isFiniteNumber(rule.set.opacity) ||
|
|
2605
|
+
rule.set.opacity < 0 ||
|
|
2606
|
+
rule.set.opacity > 1)
|
|
2607
|
+
) {
|
|
2608
|
+
return invalidFromErrorFactory(
|
|
2609
|
+
errorFactory,
|
|
2610
|
+
`${rulePath}.set.opacity must be a finite number between 0 and 1 when provided`,
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2614
|
+
for (const field of ["anchorX", "anchorY"]) {
|
|
2615
|
+
if (rule.set[field] !== undefined && !isFiniteNumber(rule.set[field])) {
|
|
2616
|
+
return invalidFromErrorFactory(
|
|
2617
|
+
errorFactory,
|
|
2618
|
+
`${rulePath}.set.${field} must be a finite number when provided`,
|
|
2619
|
+
);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
if (
|
|
2624
|
+
rule.set.visible !== undefined &&
|
|
2625
|
+
typeof rule.set.visible !== "boolean"
|
|
2626
|
+
) {
|
|
2627
|
+
return invalidFromErrorFactory(
|
|
2628
|
+
errorFactory,
|
|
2629
|
+
`${rulePath}.set.visible must be a boolean when provided`,
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
if (rule.set.textStyle !== undefined) {
|
|
2634
|
+
if (!isPlainObject(rule.set.textStyle)) {
|
|
2635
|
+
return invalidFromErrorFactory(
|
|
2636
|
+
errorFactory,
|
|
2637
|
+
`${rulePath}.set.textStyle must be an object when provided`,
|
|
2638
|
+
);
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
{
|
|
2642
|
+
const result = validateLayoutElementTextStyle({
|
|
2643
|
+
textStyle: rule.set.textStyle,
|
|
2644
|
+
path: `${rulePath}.set.textStyle`,
|
|
2645
|
+
errorFactory,
|
|
2646
|
+
});
|
|
2647
|
+
if (result?.valid === false) {
|
|
2648
|
+
return result;
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2340
2655
|
if (data.fill !== undefined && !isString(data.fill)) {
|
|
2341
2656
|
return invalidFromErrorFactory(
|
|
2342
2657
|
errorFactory,
|
|
@@ -2365,6 +2680,17 @@ const validateLayoutElementData = ({
|
|
|
2365
2680
|
);
|
|
2366
2681
|
}
|
|
2367
2682
|
|
|
2683
|
+
if (
|
|
2684
|
+
data.paginationMode !== undefined &&
|
|
2685
|
+
data.paginationMode !== "continuous" &&
|
|
2686
|
+
data.paginationMode !== "paginated"
|
|
2687
|
+
) {
|
|
2688
|
+
return invalidFromErrorFactory(
|
|
2689
|
+
errorFactory,
|
|
2690
|
+
`${path}.paginationMode must be 'continuous' or 'paginated' when provided`,
|
|
2691
|
+
);
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2368
2694
|
if (data.scroll !== undefined && typeof data.scroll !== "boolean") {
|
|
2369
2695
|
return invalidFromErrorFactory(
|
|
2370
2696
|
errorFactory,
|
|
@@ -2372,6 +2698,45 @@ const validateLayoutElementData = ({
|
|
|
2372
2698
|
);
|
|
2373
2699
|
}
|
|
2374
2700
|
|
|
2701
|
+
if (data.hover !== undefined) {
|
|
2702
|
+
{
|
|
2703
|
+
const result = validateLayoutElementInteraction({
|
|
2704
|
+
interaction: data.hover,
|
|
2705
|
+
path: `${path}.hover`,
|
|
2706
|
+
errorFactory,
|
|
2707
|
+
});
|
|
2708
|
+
if (result?.valid === false) {
|
|
2709
|
+
return result;
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
if (data.click !== undefined) {
|
|
2715
|
+
{
|
|
2716
|
+
const result = validateLayoutElementInteraction({
|
|
2717
|
+
interaction: data.click,
|
|
2718
|
+
path: `${path}.click`,
|
|
2719
|
+
errorFactory,
|
|
2720
|
+
});
|
|
2721
|
+
if (result?.valid === false) {
|
|
2722
|
+
return result;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
if (data.rightClick !== undefined) {
|
|
2728
|
+
{
|
|
2729
|
+
const result = validateLayoutElementInteraction({
|
|
2730
|
+
interaction: data.rightClick,
|
|
2731
|
+
path: `${path}.rightClick`,
|
|
2732
|
+
errorFactory,
|
|
2733
|
+
});
|
|
2734
|
+
if (result?.valid === false) {
|
|
2735
|
+
return result;
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2375
2740
|
if (
|
|
2376
2741
|
data.anchorToBottom !== undefined &&
|
|
2377
2742
|
typeof data.anchorToBottom !== "boolean"
|
|
@@ -2415,20 +2780,6 @@ const validateLayoutElementData = ({
|
|
|
2415
2780
|
}
|
|
2416
2781
|
}
|
|
2417
2782
|
|
|
2418
|
-
if (data.click !== undefined && !isPlainObject(data.click)) {
|
|
2419
|
-
return invalidFromErrorFactory(
|
|
2420
|
-
errorFactory,
|
|
2421
|
-
`${path}.click must be an object when provided`,
|
|
2422
|
-
);
|
|
2423
|
-
}
|
|
2424
|
-
|
|
2425
|
-
if (data.rightClick !== undefined && !isPlainObject(data.rightClick)) {
|
|
2426
|
-
return invalidFromErrorFactory(
|
|
2427
|
-
errorFactory,
|
|
2428
|
-
`${path}.rightClick must be an object when provided`,
|
|
2429
|
-
);
|
|
2430
|
-
}
|
|
2431
|
-
|
|
2432
2783
|
if (data.change !== undefined && !isPlainObject(data.change)) {
|
|
2433
2784
|
return invalidFromErrorFactory(
|
|
2434
2785
|
errorFactory,
|
|
@@ -2470,10 +2821,14 @@ const validateLayoutElementItems = ({ items, path, errorFactory }) => {
|
|
|
2470
2821
|
"textStyleId",
|
|
2471
2822
|
"hoverTextStyleId",
|
|
2472
2823
|
"clickTextStyleId",
|
|
2824
|
+
"conditionalOverrides",
|
|
2473
2825
|
"direction",
|
|
2474
2826
|
"gap",
|
|
2475
2827
|
"containerType",
|
|
2476
2828
|
"scroll",
|
|
2829
|
+
"hover",
|
|
2830
|
+
"click",
|
|
2831
|
+
"rightClick",
|
|
2477
2832
|
"anchorToBottom",
|
|
2478
2833
|
"thumbImageId",
|
|
2479
2834
|
"barImageId",
|
|
@@ -2484,9 +2839,11 @@ const validateLayoutElementItems = ({ items, path, errorFactory }) => {
|
|
|
2484
2839
|
"step",
|
|
2485
2840
|
"initialValue",
|
|
2486
2841
|
"variableId",
|
|
2842
|
+
"fragmentLayoutId",
|
|
2843
|
+
"paginationMode",
|
|
2844
|
+
"paginationVariableId",
|
|
2845
|
+
"paginationSize",
|
|
2487
2846
|
"$when",
|
|
2488
|
-
"click",
|
|
2489
|
-
"rightClick",
|
|
2490
2847
|
"change",
|
|
2491
2848
|
],
|
|
2492
2849
|
path: itemPath,
|
|
@@ -2684,7 +3041,16 @@ const validateLayoutItems = ({ items, path, errorFactory }) => {
|
|
|
2684
3041
|
allowedKeys:
|
|
2685
3042
|
item.type === "folder"
|
|
2686
3043
|
? ["id", "type", "name"]
|
|
2687
|
-
: [
|
|
3044
|
+
: [
|
|
3045
|
+
"id",
|
|
3046
|
+
"type",
|
|
3047
|
+
"name",
|
|
3048
|
+
"description",
|
|
3049
|
+
"layoutType",
|
|
3050
|
+
"isFragment",
|
|
3051
|
+
"thumbnailFileId",
|
|
3052
|
+
"elements",
|
|
3053
|
+
],
|
|
2688
3054
|
path: itemPath,
|
|
2689
3055
|
errorFactory,
|
|
2690
3056
|
});
|
|
@@ -2714,11 +3080,38 @@ const validateLayoutItems = ({ items, path, errorFactory }) => {
|
|
|
2714
3080
|
);
|
|
2715
3081
|
}
|
|
2716
3082
|
|
|
3083
|
+
if (item.description !== undefined && !isString(item.description)) {
|
|
3084
|
+
return invalidFromErrorFactory(
|
|
3085
|
+
errorFactory,
|
|
3086
|
+
`${itemPath}.description must be a string when provided`,
|
|
3087
|
+
);
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
if (
|
|
3091
|
+
item.thumbnailFileId !== undefined &&
|
|
3092
|
+
!isNonEmptyString(item.thumbnailFileId)
|
|
3093
|
+
) {
|
|
3094
|
+
return invalidFromErrorFactory(
|
|
3095
|
+
errorFactory,
|
|
3096
|
+
`${itemPath}.thumbnailFileId must be a non-empty string when provided`,
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
|
|
2717
3100
|
if (item.type === "layout") {
|
|
2718
3101
|
if (!LAYOUT_TYPE_KEYS.includes(item.layoutType)) {
|
|
2719
3102
|
return invalidFromErrorFactory(
|
|
2720
3103
|
errorFactory,
|
|
2721
|
-
`${itemPath}.layoutType must be 'normal', 'dialogue', 'nvl', or '
|
|
3104
|
+
`${itemPath}.layoutType must be 'normal', 'save-load', 'confirmDialog', 'dialogue', 'nvl', 'choice', or 'history'`,
|
|
3105
|
+
);
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
if (
|
|
3109
|
+
item.isFragment !== undefined &&
|
|
3110
|
+
typeof item.isFragment !== "boolean"
|
|
3111
|
+
) {
|
|
3112
|
+
return invalidFromErrorFactory(
|
|
3113
|
+
errorFactory,
|
|
3114
|
+
`${itemPath}.isFragment must be a boolean when provided`,
|
|
2722
3115
|
);
|
|
2723
3116
|
}
|
|
2724
3117
|
|
|
@@ -2755,7 +3148,7 @@ const validateControlItems = ({ items, path, errorFactory }) => {
|
|
|
2755
3148
|
allowedKeys:
|
|
2756
3149
|
item.type === "folder"
|
|
2757
3150
|
? ["id", "type", "name"]
|
|
2758
|
-
: ["id", "type", "name", "elements", "keyboard"],
|
|
3151
|
+
: ["id", "type", "name", "thumbnailFileId", "elements", "keyboard"],
|
|
2759
3152
|
path: itemPath,
|
|
2760
3153
|
errorFactory,
|
|
2761
3154
|
});
|
|
@@ -2785,6 +3178,16 @@ const validateControlItems = ({ items, path, errorFactory }) => {
|
|
|
2785
3178
|
);
|
|
2786
3179
|
}
|
|
2787
3180
|
|
|
3181
|
+
if (
|
|
3182
|
+
item.thumbnailFileId !== undefined &&
|
|
3183
|
+
!isNonEmptyString(item.thumbnailFileId)
|
|
3184
|
+
) {
|
|
3185
|
+
return invalidFromErrorFactory(
|
|
3186
|
+
errorFactory,
|
|
3187
|
+
`${itemPath}.thumbnailFileId must be a non-empty string when provided`,
|
|
3188
|
+
);
|
|
3189
|
+
}
|
|
3190
|
+
|
|
2788
3191
|
if (item.type === "control") {
|
|
2789
3192
|
{
|
|
2790
3193
|
const result = validateNestedCollection({
|
|
@@ -3854,6 +4257,40 @@ export const assertInvariants = ({ state }) => {
|
|
|
3854
4257
|
}
|
|
3855
4258
|
}
|
|
3856
4259
|
|
|
4260
|
+
for (const [layoutId, layout] of Object.entries(state.layouts.items)) {
|
|
4261
|
+
if (layout.type !== "layout" || layout.thumbnailFileId === undefined) {
|
|
4262
|
+
continue;
|
|
4263
|
+
}
|
|
4264
|
+
|
|
4265
|
+
const result = validateFileReference({
|
|
4266
|
+
state,
|
|
4267
|
+
fileId: layout.thumbnailFileId,
|
|
4268
|
+
path: "layout.thumbnailFileId",
|
|
4269
|
+
details: { layoutId, thumbnailFileId: layout.thumbnailFileId },
|
|
4270
|
+
errorFactory: createInvariantValidationError,
|
|
4271
|
+
});
|
|
4272
|
+
if (!result.valid) {
|
|
4273
|
+
return result;
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4276
|
+
|
|
4277
|
+
for (const [controlId, control] of Object.entries(state.controls.items)) {
|
|
4278
|
+
if (control.type !== "control" || control.thumbnailFileId === undefined) {
|
|
4279
|
+
continue;
|
|
4280
|
+
}
|
|
4281
|
+
|
|
4282
|
+
const result = validateFileReference({
|
|
4283
|
+
state,
|
|
4284
|
+
fileId: control.thumbnailFileId,
|
|
4285
|
+
path: "control.thumbnailFileId",
|
|
4286
|
+
details: { controlId, thumbnailFileId: control.thumbnailFileId },
|
|
4287
|
+
errorFactory: createInvariantValidationError,
|
|
4288
|
+
});
|
|
4289
|
+
if (!result.valid) {
|
|
4290
|
+
return result;
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
|
|
3857
4294
|
const assertImageReference = ({
|
|
3858
4295
|
ownerIdField,
|
|
3859
4296
|
ownerId,
|
|
@@ -3923,6 +4360,32 @@ export const assertInvariants = ({ state }) => {
|
|
|
3923
4360
|
return VALID_RESULT;
|
|
3924
4361
|
};
|
|
3925
4362
|
|
|
4363
|
+
const assertFragmentLayoutReference = ({
|
|
4364
|
+
ownerIdField,
|
|
4365
|
+
ownerId,
|
|
4366
|
+
ownerLabel,
|
|
4367
|
+
elementId,
|
|
4368
|
+
targetId,
|
|
4369
|
+
}) => {
|
|
4370
|
+
const layout = state.layouts.items[targetId];
|
|
4371
|
+
if (
|
|
4372
|
+
!isPlainObject(layout) ||
|
|
4373
|
+
layout.type !== "layout" ||
|
|
4374
|
+
layout.isFragment !== true
|
|
4375
|
+
) {
|
|
4376
|
+
return invalidInvariant(
|
|
4377
|
+
`${ownerLabel} element fragmentLayoutId must reference an existing fragment layout`,
|
|
4378
|
+
{
|
|
4379
|
+
[ownerIdField]: ownerId,
|
|
4380
|
+
elementId,
|
|
4381
|
+
fragmentLayoutId: targetId,
|
|
4382
|
+
},
|
|
4383
|
+
);
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
return VALID_RESULT;
|
|
4387
|
+
};
|
|
4388
|
+
|
|
3926
4389
|
const assertElementReferencesForCollection = ({
|
|
3927
4390
|
items,
|
|
3928
4391
|
ownerIdField,
|
|
@@ -3979,6 +4442,51 @@ export const assertInvariants = ({ state }) => {
|
|
|
3979
4442
|
}
|
|
3980
4443
|
}
|
|
3981
4444
|
|
|
4445
|
+
if (Array.isArray(element.conditionalOverrides)) {
|
|
4446
|
+
for (
|
|
4447
|
+
let index = 0;
|
|
4448
|
+
index < element.conditionalOverrides.length;
|
|
4449
|
+
index += 1
|
|
4450
|
+
) {
|
|
4451
|
+
const rule = element.conditionalOverrides[index];
|
|
4452
|
+
|
|
4453
|
+
for (const field of [
|
|
4454
|
+
"textStyleId",
|
|
4455
|
+
"hoverTextStyleId",
|
|
4456
|
+
"clickTextStyleId",
|
|
4457
|
+
]) {
|
|
4458
|
+
if (rule?.set?.[field] !== undefined) {
|
|
4459
|
+
const result = assertTextStyleReference({
|
|
4460
|
+
ownerIdField,
|
|
4461
|
+
ownerId,
|
|
4462
|
+
ownerLabel,
|
|
4463
|
+
elementId,
|
|
4464
|
+
field: `conditionalOverrides.${index}.set.${field}`,
|
|
4465
|
+
targetId: rule.set[field],
|
|
4466
|
+
});
|
|
4467
|
+
if (!result.valid) {
|
|
4468
|
+
return result;
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4473
|
+
if (
|
|
4474
|
+
rule?.when?.target !== undefined &&
|
|
4475
|
+
!isLayoutConditionTarget(state, rule.when.target)
|
|
4476
|
+
) {
|
|
4477
|
+
return invalidInvariant(
|
|
4478
|
+
`${ownerLabel} element conditionalOverrides when target must reference an existing variable or supported runtime condition`,
|
|
4479
|
+
{
|
|
4480
|
+
[ownerIdField]: ownerId,
|
|
4481
|
+
elementId,
|
|
4482
|
+
field: `conditionalOverrides.${index}.when.target`,
|
|
4483
|
+
targetId: rule.when.target,
|
|
4484
|
+
},
|
|
4485
|
+
);
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
|
|
3982
4490
|
if (element.variableId !== undefined) {
|
|
3983
4491
|
const result = assertVariableReference({
|
|
3984
4492
|
ownerIdField,
|
|
@@ -3991,6 +4499,19 @@ export const assertInvariants = ({ state }) => {
|
|
|
3991
4499
|
return result;
|
|
3992
4500
|
}
|
|
3993
4501
|
}
|
|
4502
|
+
|
|
4503
|
+
if (element.fragmentLayoutId !== undefined) {
|
|
4504
|
+
const result = assertFragmentLayoutReference({
|
|
4505
|
+
ownerIdField,
|
|
4506
|
+
ownerId,
|
|
4507
|
+
ownerLabel,
|
|
4508
|
+
elementId,
|
|
4509
|
+
targetId: element.fragmentLayoutId,
|
|
4510
|
+
});
|
|
4511
|
+
if (!result.valid) {
|
|
4512
|
+
return result;
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
3994
4515
|
}
|
|
3995
4516
|
}
|
|
3996
4517
|
|
|
@@ -6136,7 +6657,15 @@ const validateLayoutCreateData = ({ data, errorFactory }) => {
|
|
|
6136
6657
|
allowedKeys:
|
|
6137
6658
|
data.type === "folder"
|
|
6138
6659
|
? ["type", "name"]
|
|
6139
|
-
: [
|
|
6660
|
+
: [
|
|
6661
|
+
"type",
|
|
6662
|
+
"name",
|
|
6663
|
+
"description",
|
|
6664
|
+
"layoutType",
|
|
6665
|
+
"isFragment",
|
|
6666
|
+
"thumbnailFileId",
|
|
6667
|
+
"elements",
|
|
6668
|
+
],
|
|
6140
6669
|
path: "payload.data",
|
|
6141
6670
|
errorFactory,
|
|
6142
6671
|
});
|
|
@@ -6152,11 +6681,35 @@ const validateLayoutCreateData = ({ data, errorFactory }) => {
|
|
|
6152
6681
|
);
|
|
6153
6682
|
}
|
|
6154
6683
|
|
|
6684
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
6685
|
+
return invalidFromErrorFactory(
|
|
6686
|
+
errorFactory,
|
|
6687
|
+
"payload.data.description must be a string when provided",
|
|
6688
|
+
);
|
|
6689
|
+
}
|
|
6690
|
+
|
|
6691
|
+
if (
|
|
6692
|
+
data.thumbnailFileId !== undefined &&
|
|
6693
|
+
!isNonEmptyString(data.thumbnailFileId)
|
|
6694
|
+
) {
|
|
6695
|
+
return invalidFromErrorFactory(
|
|
6696
|
+
errorFactory,
|
|
6697
|
+
"payload.data.thumbnailFileId must be a non-empty string when provided",
|
|
6698
|
+
);
|
|
6699
|
+
}
|
|
6700
|
+
|
|
6155
6701
|
if (data.type === "layout") {
|
|
6156
6702
|
if (!LAYOUT_TYPE_KEYS.includes(data.layoutType)) {
|
|
6157
6703
|
return invalidFromErrorFactory(
|
|
6158
6704
|
errorFactory,
|
|
6159
|
-
"payload.data.layoutType must be 'normal', 'dialogue', 'nvl', or '
|
|
6705
|
+
"payload.data.layoutType must be 'normal', 'save-load', 'confirmDialog', 'dialogue', 'nvl', 'choice', or 'history'",
|
|
6706
|
+
);
|
|
6707
|
+
}
|
|
6708
|
+
|
|
6709
|
+
if (data.isFragment !== undefined && typeof data.isFragment !== "boolean") {
|
|
6710
|
+
return invalidFromErrorFactory(
|
|
6711
|
+
errorFactory,
|
|
6712
|
+
"payload.data.isFragment must be a boolean when provided",
|
|
6160
6713
|
);
|
|
6161
6714
|
}
|
|
6162
6715
|
|
|
@@ -6179,7 +6732,13 @@ const validateLayoutUpdateData = ({ data, errorFactory }) => {
|
|
|
6179
6732
|
{
|
|
6180
6733
|
const result = validateAllowedKeys({
|
|
6181
6734
|
value: data,
|
|
6182
|
-
allowedKeys: [
|
|
6735
|
+
allowedKeys: [
|
|
6736
|
+
"name",
|
|
6737
|
+
"description",
|
|
6738
|
+
"layoutType",
|
|
6739
|
+
"isFragment",
|
|
6740
|
+
"thumbnailFileId",
|
|
6741
|
+
],
|
|
6183
6742
|
path: "payload.data",
|
|
6184
6743
|
errorFactory,
|
|
6185
6744
|
});
|
|
@@ -6202,13 +6761,37 @@ const validateLayoutUpdateData = ({ data, errorFactory }) => {
|
|
|
6202
6761
|
);
|
|
6203
6762
|
}
|
|
6204
6763
|
|
|
6764
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
6765
|
+
return invalidFromErrorFactory(
|
|
6766
|
+
errorFactory,
|
|
6767
|
+
"payload.data.description must be a string when provided",
|
|
6768
|
+
);
|
|
6769
|
+
}
|
|
6770
|
+
|
|
6771
|
+
if (
|
|
6772
|
+
data.thumbnailFileId !== undefined &&
|
|
6773
|
+
!isNonEmptyString(data.thumbnailFileId)
|
|
6774
|
+
) {
|
|
6775
|
+
return invalidFromErrorFactory(
|
|
6776
|
+
errorFactory,
|
|
6777
|
+
"payload.data.thumbnailFileId must be a non-empty string when provided",
|
|
6778
|
+
);
|
|
6779
|
+
}
|
|
6780
|
+
|
|
6205
6781
|
if (
|
|
6206
6782
|
data.layoutType !== undefined &&
|
|
6207
6783
|
!LAYOUT_TYPE_KEYS.includes(data.layoutType)
|
|
6208
6784
|
) {
|
|
6209
6785
|
return invalidFromErrorFactory(
|
|
6210
6786
|
errorFactory,
|
|
6211
|
-
"payload.data.layoutType must be 'normal', 'dialogue', 'nvl', or '
|
|
6787
|
+
"payload.data.layoutType must be 'normal', 'save-load', 'confirmDialog', 'dialogue', 'nvl', 'choice', or 'history' when provided",
|
|
6788
|
+
);
|
|
6789
|
+
}
|
|
6790
|
+
|
|
6791
|
+
if (data.isFragment !== undefined && typeof data.isFragment !== "boolean") {
|
|
6792
|
+
return invalidFromErrorFactory(
|
|
6793
|
+
errorFactory,
|
|
6794
|
+
"payload.data.isFragment must be a boolean when provided",
|
|
6212
6795
|
);
|
|
6213
6796
|
}
|
|
6214
6797
|
};
|
|
@@ -6234,7 +6817,7 @@ const validateControlCreateData = ({ data, errorFactory }) => {
|
|
|
6234
6817
|
allowedKeys:
|
|
6235
6818
|
data.type === "folder"
|
|
6236
6819
|
? ["type", "name"]
|
|
6237
|
-
: ["type", "name", "elements", "keyboard"],
|
|
6820
|
+
: ["type", "name", "thumbnailFileId", "elements", "keyboard"],
|
|
6238
6821
|
path: "payload.data",
|
|
6239
6822
|
errorFactory,
|
|
6240
6823
|
});
|
|
@@ -6250,6 +6833,16 @@ const validateControlCreateData = ({ data, errorFactory }) => {
|
|
|
6250
6833
|
);
|
|
6251
6834
|
}
|
|
6252
6835
|
|
|
6836
|
+
if (
|
|
6837
|
+
data.thumbnailFileId !== undefined &&
|
|
6838
|
+
!isNonEmptyString(data.thumbnailFileId)
|
|
6839
|
+
) {
|
|
6840
|
+
return invalidFromErrorFactory(
|
|
6841
|
+
errorFactory,
|
|
6842
|
+
"payload.data.thumbnailFileId must be a non-empty string when provided",
|
|
6843
|
+
);
|
|
6844
|
+
}
|
|
6845
|
+
|
|
6253
6846
|
if (data.type === "control") {
|
|
6254
6847
|
{
|
|
6255
6848
|
const result = validateNestedCollection({
|
|
@@ -6281,7 +6874,7 @@ const validateControlUpdateData = ({ data, errorFactory }) => {
|
|
|
6281
6874
|
{
|
|
6282
6875
|
const result = validateAllowedKeys({
|
|
6283
6876
|
value: data,
|
|
6284
|
-
allowedKeys: ["name", "keyboard"],
|
|
6877
|
+
allowedKeys: ["name", "keyboard", "thumbnailFileId"],
|
|
6285
6878
|
path: "payload.data",
|
|
6286
6879
|
errorFactory,
|
|
6287
6880
|
});
|
|
@@ -6304,6 +6897,16 @@ const validateControlUpdateData = ({ data, errorFactory }) => {
|
|
|
6304
6897
|
);
|
|
6305
6898
|
}
|
|
6306
6899
|
|
|
6900
|
+
if (
|
|
6901
|
+
data.thumbnailFileId !== undefined &&
|
|
6902
|
+
!isNonEmptyString(data.thumbnailFileId)
|
|
6903
|
+
) {
|
|
6904
|
+
return invalidFromErrorFactory(
|
|
6905
|
+
errorFactory,
|
|
6906
|
+
"payload.data.thumbnailFileId must be a non-empty string when provided",
|
|
6907
|
+
);
|
|
6908
|
+
}
|
|
6909
|
+
|
|
6307
6910
|
{
|
|
6308
6911
|
const result = validateKeyboardMap({
|
|
6309
6912
|
value: data.keyboard,
|
|
@@ -6519,6 +7122,69 @@ const validateVisualElementReferenceTargets = ({
|
|
|
6519
7122
|
}
|
|
6520
7123
|
}
|
|
6521
7124
|
|
|
7125
|
+
if (Array.isArray(data.conditionalOverrides)) {
|
|
7126
|
+
for (let index = 0; index < data.conditionalOverrides.length; index += 1) {
|
|
7127
|
+
const rule = data.conditionalOverrides[index];
|
|
7128
|
+
|
|
7129
|
+
for (const field of [
|
|
7130
|
+
"textStyleId",
|
|
7131
|
+
"hoverTextStyleId",
|
|
7132
|
+
"clickTextStyleId",
|
|
7133
|
+
]) {
|
|
7134
|
+
if (rule?.set?.[field] === undefined) {
|
|
7135
|
+
continue;
|
|
7136
|
+
}
|
|
7137
|
+
|
|
7138
|
+
const textStyle = state.textStyles.items[rule.set[field]];
|
|
7139
|
+
if (!isPlainObject(textStyle) || textStyle.type === "folder") {
|
|
7140
|
+
return invalidFromErrorFactory(
|
|
7141
|
+
errorFactory,
|
|
7142
|
+
`${ownerLabel} element conditionalOverrides.${index}.set.${field} must reference an existing non-folder text style`,
|
|
7143
|
+
{
|
|
7144
|
+
[ownerIdField]: ownerId,
|
|
7145
|
+
elementId,
|
|
7146
|
+
field: `conditionalOverrides.${index}.set.${field}`,
|
|
7147
|
+
targetId: rule.set[field],
|
|
7148
|
+
},
|
|
7149
|
+
);
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
|
|
7153
|
+
for (const field of ["imageId", "hoverImageId", "clickImageId"]) {
|
|
7154
|
+
if (rule?.set?.[field] === undefined) {
|
|
7155
|
+
continue;
|
|
7156
|
+
}
|
|
7157
|
+
|
|
7158
|
+
const image = state.images.items[rule.set[field]];
|
|
7159
|
+
if (!isPlainObject(image) || image.type === "folder") {
|
|
7160
|
+
return invalidFromErrorFactory(
|
|
7161
|
+
errorFactory,
|
|
7162
|
+
`${ownerLabel} element conditionalOverrides.${index}.set.${field} must reference an existing non-folder image`,
|
|
7163
|
+
{
|
|
7164
|
+
[ownerIdField]: ownerId,
|
|
7165
|
+
elementId,
|
|
7166
|
+
field: `conditionalOverrides.${index}.set.${field}`,
|
|
7167
|
+
targetId: rule.set[field],
|
|
7168
|
+
},
|
|
7169
|
+
);
|
|
7170
|
+
}
|
|
7171
|
+
}
|
|
7172
|
+
|
|
7173
|
+
if (!isLayoutConditionTarget(state, rule?.when?.target)) {
|
|
7174
|
+
return invalidFromErrorFactory(
|
|
7175
|
+
errorFactory,
|
|
7176
|
+
`${ownerLabel} element conditionalOverrides.${index}.when.target must reference an existing variable or supported runtime condition`,
|
|
7177
|
+
{
|
|
7178
|
+
[ownerIdField]: ownerId,
|
|
7179
|
+
elementId,
|
|
7180
|
+
field: `conditionalOverrides.${index}.when.target`,
|
|
7181
|
+
targetId: rule?.when?.target,
|
|
7182
|
+
},
|
|
7183
|
+
);
|
|
7184
|
+
}
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
|
|
6522
7188
|
if (data.variableId !== undefined) {
|
|
6523
7189
|
if (!isVariableReferenceTarget(state, data.variableId)) {
|
|
6524
7190
|
return invalidFromErrorFactory(
|
|
@@ -6532,6 +7198,25 @@ const validateVisualElementReferenceTargets = ({
|
|
|
6532
7198
|
);
|
|
6533
7199
|
}
|
|
6534
7200
|
}
|
|
7201
|
+
|
|
7202
|
+
if (data.fragmentLayoutId !== undefined) {
|
|
7203
|
+
const fragmentLayout = state.layouts.items[data.fragmentLayoutId];
|
|
7204
|
+
if (
|
|
7205
|
+
!isPlainObject(fragmentLayout) ||
|
|
7206
|
+
fragmentLayout.type !== "layout" ||
|
|
7207
|
+
fragmentLayout.isFragment !== true
|
|
7208
|
+
) {
|
|
7209
|
+
return invalidFromErrorFactory(
|
|
7210
|
+
errorFactory,
|
|
7211
|
+
`${ownerLabel} element fragmentLayoutId must reference an existing fragment layout`,
|
|
7212
|
+
{
|
|
7213
|
+
[ownerIdField]: ownerId,
|
|
7214
|
+
elementId,
|
|
7215
|
+
fragmentLayoutId: data.fragmentLayoutId,
|
|
7216
|
+
},
|
|
7217
|
+
);
|
|
7218
|
+
}
|
|
7219
|
+
}
|
|
6535
7220
|
};
|
|
6536
7221
|
|
|
6537
7222
|
const getTreeIdsInOrder = ({ nodes }) => {
|
|
@@ -11198,12 +11883,33 @@ const COMMAND_DEFINITIONS = [
|
|
|
11198
11883
|
name: payload.data.name,
|
|
11199
11884
|
...(payload.data.type === "layout"
|
|
11200
11885
|
? {
|
|
11886
|
+
description: payload.data.description,
|
|
11201
11887
|
layoutType: payload.data.layoutType,
|
|
11888
|
+
isFragment: payload.data.isFragment,
|
|
11889
|
+
...(payload.data.thumbnailFileId !== undefined
|
|
11890
|
+
? {
|
|
11891
|
+
thumbnailFileId: payload.data.thumbnailFileId,
|
|
11892
|
+
}
|
|
11893
|
+
: {}),
|
|
11202
11894
|
elements: structuredClone(payload.data.elements),
|
|
11203
11895
|
}
|
|
11204
11896
|
: {}),
|
|
11205
11897
|
}),
|
|
11206
|
-
|
|
11898
|
+
validateCreateState: ({ state, payload }) => {
|
|
11899
|
+
if (payload.data.type !== "layout") {
|
|
11900
|
+
return;
|
|
11901
|
+
}
|
|
11902
|
+
|
|
11903
|
+
return validateReferencedFilesInData({
|
|
11904
|
+
state,
|
|
11905
|
+
data: payload.data,
|
|
11906
|
+
fields: ["thumbnailFileId"],
|
|
11907
|
+
details: {
|
|
11908
|
+
layoutId: payload.layoutId,
|
|
11909
|
+
},
|
|
11910
|
+
});
|
|
11911
|
+
},
|
|
11912
|
+
validateUpdateState: ({ state, payload, currentItem }) => {
|
|
11207
11913
|
if (
|
|
11208
11914
|
currentItem.type === "folder" &&
|
|
11209
11915
|
Object.keys(payload.data).some((key) => key !== "name")
|
|
@@ -11212,6 +11918,17 @@ const COMMAND_DEFINITIONS = [
|
|
|
11212
11918
|
"folder layout items cannot update layout fields",
|
|
11213
11919
|
);
|
|
11214
11920
|
}
|
|
11921
|
+
|
|
11922
|
+
if (currentItem.type === "layout") {
|
|
11923
|
+
return validateReferencedFilesInData({
|
|
11924
|
+
state,
|
|
11925
|
+
data: payload.data,
|
|
11926
|
+
fields: ["thumbnailFileId"],
|
|
11927
|
+
details: {
|
|
11928
|
+
layoutId: payload.layoutId,
|
|
11929
|
+
},
|
|
11930
|
+
});
|
|
11931
|
+
}
|
|
11215
11932
|
},
|
|
11216
11933
|
}),
|
|
11217
11934
|
...createFolderedCollectionCommandDefinitions({
|
|
@@ -11227,6 +11944,11 @@ const COMMAND_DEFINITIONS = [
|
|
|
11227
11944
|
name: payload.data.name,
|
|
11228
11945
|
...(payload.data.type === "control"
|
|
11229
11946
|
? {
|
|
11947
|
+
...(payload.data.thumbnailFileId !== undefined
|
|
11948
|
+
? {
|
|
11949
|
+
thumbnailFileId: payload.data.thumbnailFileId,
|
|
11950
|
+
}
|
|
11951
|
+
: {}),
|
|
11230
11952
|
elements: structuredClone(payload.data.elements),
|
|
11231
11953
|
...(payload.data.keyboard !== undefined
|
|
11232
11954
|
? {
|
|
@@ -11236,7 +11958,21 @@ const COMMAND_DEFINITIONS = [
|
|
|
11236
11958
|
}
|
|
11237
11959
|
: {}),
|
|
11238
11960
|
}),
|
|
11239
|
-
|
|
11961
|
+
validateCreateState: ({ state, payload }) => {
|
|
11962
|
+
if (payload.data.type !== "control") {
|
|
11963
|
+
return;
|
|
11964
|
+
}
|
|
11965
|
+
|
|
11966
|
+
return validateReferencedFilesInData({
|
|
11967
|
+
state,
|
|
11968
|
+
data: payload.data,
|
|
11969
|
+
fields: ["thumbnailFileId"],
|
|
11970
|
+
details: {
|
|
11971
|
+
controlId: payload.controlId,
|
|
11972
|
+
},
|
|
11973
|
+
});
|
|
11974
|
+
},
|
|
11975
|
+
validateUpdateState: ({ state, payload, currentItem }) => {
|
|
11240
11976
|
if (
|
|
11241
11977
|
currentItem.type === "folder" &&
|
|
11242
11978
|
Object.keys(payload.data).some((key) => key !== "name")
|
|
@@ -11245,6 +11981,17 @@ const COMMAND_DEFINITIONS = [
|
|
|
11245
11981
|
"folder control items cannot update control fields",
|
|
11246
11982
|
);
|
|
11247
11983
|
}
|
|
11984
|
+
|
|
11985
|
+
if (currentItem.type === "control") {
|
|
11986
|
+
return validateReferencedFilesInData({
|
|
11987
|
+
state,
|
|
11988
|
+
data: payload.data,
|
|
11989
|
+
fields: ["thumbnailFileId"],
|
|
11990
|
+
details: {
|
|
11991
|
+
controlId: payload.controlId,
|
|
11992
|
+
},
|
|
11993
|
+
});
|
|
11994
|
+
}
|
|
11248
11995
|
},
|
|
11249
11996
|
}),
|
|
11250
11997
|
{
|
package/src/systemVariables.js
CHANGED
|
@@ -21,6 +21,33 @@ export const SYSTEM_VARIABLE_GROUPS = Object.freeze([
|
|
|
21
21
|
description:
|
|
22
22
|
"Controls the default dialogue text speed stored for this device.",
|
|
23
23
|
},
|
|
24
|
+
{
|
|
25
|
+
id: "_currentSaveLoadPagination",
|
|
26
|
+
name: "Current Save/Load Pagination",
|
|
27
|
+
scope: "context",
|
|
28
|
+
type: "number",
|
|
29
|
+
default: 0,
|
|
30
|
+
description:
|
|
31
|
+
"The current save/load pagination index. Resolves to 0, 1, 2, 3, and so on for the active save/load page.",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "_currentMenuPage",
|
|
35
|
+
name: "Current Menu Page",
|
|
36
|
+
scope: "context",
|
|
37
|
+
type: "string",
|
|
38
|
+
default: "",
|
|
39
|
+
description:
|
|
40
|
+
"The current menu page id for the active UI flow. Typical values include options, save, load, and history.",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "_menuEntryPoint",
|
|
44
|
+
name: "Menu Entry Point",
|
|
45
|
+
scope: "context",
|
|
46
|
+
type: "string",
|
|
47
|
+
default: "",
|
|
48
|
+
description:
|
|
49
|
+
"Indicates how the current menu flow was opened. Typical values include title and read.",
|
|
50
|
+
},
|
|
24
51
|
]),
|
|
25
52
|
},
|
|
26
53
|
]);
|