@reventlessdev/reventless-core 3.0.0-alpha.236 → 3.0.0-alpha.237
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/CHANGELOG.md +11 -0
- package/package.json +7 -7
- package/src/admin/Platform_Admin_Structure.res +5 -1
- package/src/admin/Platform_Admin_Structure.res.mjs +4 -2
- package/src/admin/Platform_ComponentDefinitionsApi.res +4 -2
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +11 -3
- package/src/components/Api/GraphQL_FragmentGenerator.res +14 -1
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +1 -1
- package/src/components/Api/QueryDbListQuery.res +25 -1
- package/src/components/Api/QueryDbListQuery.res.mjs +11 -4
- package/src/components/Api/SuryToJsonSchema.res +39 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +34 -3
- package/src/plugin/component/Plugin_Structure.res +112 -15
- package/src/plugin/component/Plugin_Structure.res.mjs +77 -9
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +3 -2
- package/tests/admin/Platform_Admin_StructureTest.res +49 -0
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +24 -0
- package/tests/admin/Platform_BakedManifestTest.res +3 -1
- package/tests/admin/Platform_BakedManifestTest.res.mjs +3 -1
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +14 -8
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +24 -12
- package/tests/admin/Platform_PluginStructuresApiTest.res +3 -1
- package/tests/admin/Platform_PluginStructuresApiTest.res.mjs +6 -2
- package/tests/api/Api_IdsTest.res.mjs +1 -1
- package/tests/api/SuryToJsonSchemaTest.res +141 -1
- package/tests/api/SuryToJsonSchemaTest.res.mjs +269 -54
- package/tests/plugin/PluginStructureTest.res +168 -12
- package/tests/plugin/PluginStructureTest.res.mjs +146 -9
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +3 -2
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +2 -0
|
@@ -39,7 +39,7 @@ function isLabelShape(_t) {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
function
|
|
42
|
+
function isLifecycleShape(_t) {
|
|
43
43
|
while (true) {
|
|
44
44
|
let t = _t;
|
|
45
45
|
if (typeof t !== "object") {
|
|
@@ -68,15 +68,15 @@ function shapeOfItem(entityName, item) {
|
|
|
68
68
|
return SchemaType$ReventlessCore.fromSury(entityName, item.location, item.schema);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
function
|
|
71
|
+
function lifecycleFieldFromStateSchema(entityName, stateSchema) {
|
|
72
72
|
let spec = StateAnnotations$Reventless.getSpec(stateSchema);
|
|
73
|
-
let annotated = spec !== undefined ? spec.
|
|
73
|
+
let annotated = spec !== undefined ? spec.lifecycle : undefined;
|
|
74
74
|
if (annotated !== undefined) {
|
|
75
75
|
return annotated;
|
|
76
76
|
} else if (stateSchema.type === "object") {
|
|
77
77
|
return Stdlib_Option.map(stateSchema.items.find(item => {
|
|
78
|
-
if (item.location === "
|
|
79
|
-
return
|
|
78
|
+
if (item.location === "lifecycle") {
|
|
79
|
+
return isLifecycleShape(shapeOfItem(entityName, item));
|
|
80
80
|
} else {
|
|
81
81
|
return false;
|
|
82
82
|
}
|
|
@@ -86,6 +86,64 @@ function statusFieldFromStateSchema(entityName, stateSchema) {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
function retiredFromStateSchema(stateSchema) {
|
|
90
|
+
let spec = StateAnnotations$Reventless.getSpec(stateSchema);
|
|
91
|
+
if (spec !== undefined) {
|
|
92
|
+
return spec.retired;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function retiredFieldFromStateSchema(stateSchema) {
|
|
97
|
+
return Stdlib_Option.map(retiredFromStateSchema(stateSchema), r => r.field);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function retiredValuesFromStateSchema(stateSchema) {
|
|
101
|
+
return Stdlib_Option.flatMap(retiredFromStateSchema(stateSchema), r => r.values);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function checkRetiredValue(entityName, stateSchema) {
|
|
105
|
+
let match = retiredFromStateSchema(stateSchema);
|
|
106
|
+
if (match === undefined) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
let values = match.values;
|
|
110
|
+
if (values === undefined) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
let field = match.field;
|
|
114
|
+
let named = values.join(", ");
|
|
115
|
+
let lifecycle = lifecycleFieldFromStateSchema(entityName, stateSchema);
|
|
116
|
+
if (Primitive_object.notequal(lifecycle, field)) {
|
|
117
|
+
log.warn("Plugin_Structure", undefined, entityName + `: @retired(` + named + `) is on "` + field + `", which is not this record's lifecycle field` + Stdlib_Option.getOr(Stdlib_Option.map(lifecycle, f => ` (that is "` + f + `")`), " (it declares none)") + `. A retirement state no command's @allowedStates can name loses the command filtering the state form exists for.`);
|
|
118
|
+
}
|
|
119
|
+
let declared;
|
|
120
|
+
declared = stateSchema.type === "object" ? Stdlib_Option.getOr(Stdlib_Option.map(stateSchema.items.find(item => item.location === field), item => {
|
|
121
|
+
let match = shapeOfItem(entityName, item);
|
|
122
|
+
if (typeof match !== "object") {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
switch (match.TAG) {
|
|
126
|
+
case "Nullable" :
|
|
127
|
+
let match$1 = match._0;
|
|
128
|
+
if (typeof match$1 !== "object") {
|
|
129
|
+
return [];
|
|
130
|
+
} else if (match$1.TAG === "Enum") {
|
|
131
|
+
return match$1._1;
|
|
132
|
+
} else {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
case "Enum" :
|
|
136
|
+
return match._1;
|
|
137
|
+
default:
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
}), []) : [];
|
|
141
|
+
if (declared.length !== 0) {
|
|
142
|
+
values.filter(v => !declared.includes(v)).forEach(v => log.warn("Plugin_Structure", undefined, entityName + `: @retired(` + v + `) names a state "` + field + `" does not declare — known values: ` + declared.join(", ") + `.`));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
89
147
|
function labelFieldSourceToString(s) {
|
|
90
148
|
switch (s) {
|
|
91
149
|
case "Annotation" :
|
|
@@ -535,6 +593,7 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
535
593
|
let label = labelFieldsFromStateSchema(R.Spec.name, stateSchema);
|
|
536
594
|
let keyField = GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField(R.Spec.name, stateSchema);
|
|
537
595
|
let consumed = qualify(name, R.consumedEventNames);
|
|
596
|
+
checkRetiredValue(R.Spec.name, stateSchema);
|
|
538
597
|
return {
|
|
539
598
|
name: R.Spec.name,
|
|
540
599
|
queryField: qf.listFieldName,
|
|
@@ -544,8 +603,10 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
544
603
|
labelField: label.field,
|
|
545
604
|
searchableFields: label.searchableFields,
|
|
546
605
|
labelFieldSource: labelFieldSourceToString(label.source),
|
|
547
|
-
|
|
606
|
+
lifecycleField: lifecycleFieldFromStateSchema(R.Spec.name, stateSchema),
|
|
548
607
|
ownerField: Owner$Reventless.fieldNames(stateSchema)[0],
|
|
608
|
+
retiredField: retiredFieldFromStateSchema(stateSchema),
|
|
609
|
+
retiredValues: retiredValuesFromStateSchema(stateSchema),
|
|
549
610
|
visibility: visibilityTag(R.Spec.visibility),
|
|
550
611
|
chapter: componentChapters[R.Spec.name],
|
|
551
612
|
singleQueryField: qf.singleFieldName,
|
|
@@ -561,6 +622,7 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
561
622
|
let stateSchema = SVS.Spec.stateSchema;
|
|
562
623
|
let label = labelFieldsFromStateSchema(SVS.Spec.name, stateSchema);
|
|
563
624
|
let keyField = GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField(SVS.Spec.name, stateSchema);
|
|
625
|
+
checkRetiredValue(SVS.Spec.name, stateSchema);
|
|
564
626
|
return {
|
|
565
627
|
name: SVS.Spec.name,
|
|
566
628
|
queryField: qf.listFieldName,
|
|
@@ -570,8 +632,10 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
570
632
|
labelField: label.field,
|
|
571
633
|
searchableFields: label.searchableFields,
|
|
572
634
|
labelFieldSource: labelFieldSourceToString(label.source),
|
|
573
|
-
|
|
635
|
+
lifecycleField: lifecycleFieldFromStateSchema(SVS.Spec.name, stateSchema),
|
|
574
636
|
ownerField: Owner$Reventless.fieldNames(stateSchema)[0],
|
|
637
|
+
retiredField: retiredFieldFromStateSchema(stateSchema),
|
|
638
|
+
retiredValues: retiredValuesFromStateSchema(stateSchema),
|
|
575
639
|
visibility: visibilityTag(SVS.Spec.visibility),
|
|
576
640
|
chapter: componentChapters[SVS.Spec.name],
|
|
577
641
|
singleQueryField: qf.singleFieldName,
|
|
@@ -689,10 +753,14 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
689
753
|
export {
|
|
690
754
|
log,
|
|
691
755
|
isLabelShape,
|
|
692
|
-
|
|
756
|
+
isLifecycleShape,
|
|
693
757
|
conventionalLabelNames,
|
|
694
758
|
shapeOfItem,
|
|
695
|
-
|
|
759
|
+
lifecycleFieldFromStateSchema,
|
|
760
|
+
retiredFromStateSchema,
|
|
761
|
+
retiredFieldFromStateSchema,
|
|
762
|
+
retiredValuesFromStateSchema,
|
|
763
|
+
checkRetiredValue,
|
|
696
764
|
labelFieldSourceToString,
|
|
697
765
|
labelFieldsFromStateSchema,
|
|
698
766
|
extractReferences,
|
|
@@ -48,10 +48,11 @@ let stateSchema$1 = S.Metadata.set(stateSchema, StateAnnotations$Reventless.stat
|
|
|
48
48
|
scanSort: [],
|
|
49
49
|
semantic: [],
|
|
50
50
|
metric: [],
|
|
51
|
-
|
|
51
|
+
lifecycle: undefined,
|
|
52
52
|
groupBy: "kind",
|
|
53
53
|
visibility: undefined,
|
|
54
|
-
live: undefined
|
|
54
|
+
live: undefined,
|
|
55
|
+
retired: undefined
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
let name = "Plugins";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The platform's own admin components, as `Platform_ComponentDefinitions` serves
|
|
2
|
+
// them. The Plugins read model is a framework-generated queryable: its field names
|
|
3
|
+
// are chosen here and read by every client, so the rule that applies to it is the
|
|
4
|
+
// opposite of the one that applies to an authored record.
|
|
5
|
+
//
|
|
6
|
+
// An authored record may follow the convention — name the field `lifecycle` and
|
|
7
|
+
// write no annotation. A generated row cannot, because its field name is a
|
|
8
|
+
// published wire name: `status` in the SDL, in stored QueryDb rows, and in any
|
|
9
|
+
// client selecting it. Renaming it to satisfy a convention would move the
|
|
10
|
+
// contract, break selecting clients and require re-projection. So it declares
|
|
11
|
+
// instead, and the declaration is what this asserts — the failure mode otherwise
|
|
12
|
+
// is silent (a board loses its columns, a command menu stops filtering, and
|
|
13
|
+
// nothing fails to compile).
|
|
14
|
+
|
|
15
|
+
open JestGlobals
|
|
16
|
+
open Reventless.Plugin
|
|
17
|
+
|
|
18
|
+
describe("the Plugins read model declares its lifecycle", () => {
|
|
19
|
+
let rm: queryableDef = Platform_Admin_Structure.pluginReadModel
|
|
20
|
+
|
|
21
|
+
testSync("names the field commands branch on", () =>
|
|
22
|
+
expect(rm.lifecycleField)->toEqual(Some("status"))
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
testSync("and the published wire name is unchanged by the rename", () => {
|
|
26
|
+
// Stated as its own assertion rather than folded into the one above: the two
|
|
27
|
+
// say different things. That the field is declared is the fix; that it is
|
|
28
|
+
// still called `status` is the constraint the fix had to respect.
|
|
29
|
+
let sdlDeclaresStatus =
|
|
30
|
+
rm.lifecycleField->Option.mapOr(false, f => f == "status") &&
|
|
31
|
+
rm.queryField->String.startsWith("Platform_")
|
|
32
|
+
expect(sdlDeclaresStatus)->toEqual(true)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
testSync("is served on the encoded def under the new key", () => {
|
|
36
|
+
let json =
|
|
37
|
+
rm->Platform_ComponentDefinitionsApi.encodeQueryableDef->JSON.stringify
|
|
38
|
+
expect(json->String.includes(`"lifecycleField":"status"`))->toEqual(true)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
testSync("and never under the old one", () =>
|
|
42
|
+
expect(
|
|
43
|
+
rm
|
|
44
|
+
->Platform_ComponentDefinitionsApi.encodeQueryableDef
|
|
45
|
+
->JSON.stringify
|
|
46
|
+
->String.includes(`"statusField"`),
|
|
47
|
+
)->toEqual(false)
|
|
48
|
+
)
|
|
49
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
import * as Platform_Admin_Structure$ReventlessCore from "../../src/admin/Platform_Admin_Structure.res.mjs";
|
|
5
|
+
import * as Platform_ComponentDefinitionsApi$ReventlessCore from "../../src/admin/Platform_ComponentDefinitionsApi.res.mjs";
|
|
6
|
+
|
|
7
|
+
globalThis.describe("the Plugins read model declares its lifecycle", () => {
|
|
8
|
+
globalThis.test("names the field commands branch on", () => {
|
|
9
|
+
globalThis.expect(Platform_Admin_Structure$ReventlessCore.pluginReadModel.lifecycleField).toEqual("status");
|
|
10
|
+
});
|
|
11
|
+
globalThis.test("and the published wire name is unchanged by the rename", () => {
|
|
12
|
+
let sdlDeclaresStatus = Stdlib_Option.mapOr(Platform_Admin_Structure$ReventlessCore.pluginReadModel.lifecycleField, false, f => f === "status") && Platform_Admin_Structure$ReventlessCore.pluginReadModel.queryField.startsWith("Platform_");
|
|
13
|
+
globalThis.expect(sdlDeclaresStatus).toEqual(true);
|
|
14
|
+
});
|
|
15
|
+
globalThis.test("is served on the encoded def under the new key", () => {
|
|
16
|
+
let json = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodeQueryableDef(Platform_Admin_Structure$ReventlessCore.pluginReadModel));
|
|
17
|
+
globalThis.expect(json.includes(`"lifecycleField":"status"`)).toEqual(true);
|
|
18
|
+
});
|
|
19
|
+
globalThis.test("and never under the old one", () => {
|
|
20
|
+
globalThis.expect(JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodeQueryableDef(Platform_Admin_Structure$ReventlessCore.pluginReadModel)).includes(`"statusField"`)).toEqual(false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/* Not a pure module */
|
|
@@ -15,7 +15,7 @@ let queryable = (~name, ~visibility=?, ~ownerField=?, ()): queryableDef => {
|
|
|
15
15
|
labelField: "displayName",
|
|
16
16
|
searchableFields: ["displayName"],
|
|
17
17
|
labelFieldSource: None,
|
|
18
|
-
|
|
18
|
+
lifecycleField: None,
|
|
19
19
|
visibility,
|
|
20
20
|
chapter: None,
|
|
21
21
|
singleQueryField: Some(`Ordering_${name}Single`),
|
|
@@ -23,6 +23,8 @@ let queryable = (~name, ~visibility=?, ~ownerField=?, ()): queryableDef => {
|
|
|
23
23
|
idFieldSource: Some("convention"),
|
|
24
24
|
requiredAccess: None,
|
|
25
25
|
ownerField,
|
|
26
|
+
retiredField: None,
|
|
27
|
+
retiredValues: None,
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
let command = (~name, ~references=[], ~ownerField=?, ()): commandDef => {
|
|
@@ -18,8 +18,10 @@ function queryable(name, visibility, ownerField, param) {
|
|
|
18
18
|
labelField: "displayName",
|
|
19
19
|
searchableFields: ["displayName"],
|
|
20
20
|
labelFieldSource: undefined,
|
|
21
|
-
|
|
21
|
+
lifecycleField: undefined,
|
|
22
22
|
ownerField: ownerField,
|
|
23
|
+
retiredField: undefined,
|
|
24
|
+
retiredValues: undefined,
|
|
23
25
|
visibility: visibility,
|
|
24
26
|
chapter: undefined,
|
|
25
27
|
singleQueryField: `Ordering_` + name + `Single`,
|
|
@@ -30,7 +30,7 @@ let qbl: queryableDef = {
|
|
|
30
30
|
labelField: "displayName",
|
|
31
31
|
searchableFields: ["displayName"],
|
|
32
32
|
labelFieldSource: Some("annotation"),
|
|
33
|
-
|
|
33
|
+
lifecycleField: None,
|
|
34
34
|
visibility: None,
|
|
35
35
|
chapter: None,
|
|
36
36
|
singleQueryField: Some("Catalog_Product"),
|
|
@@ -38,6 +38,8 @@ let qbl: queryableDef = {
|
|
|
38
38
|
idFieldSource: Some("convention"),
|
|
39
39
|
requiredAccess: None,
|
|
40
40
|
ownerField: None,
|
|
41
|
+
retiredField: None,
|
|
42
|
+
retiredValues: None,
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
let wbl: writableDef = {
|
|
@@ -162,8 +164,8 @@ describe("encodePluginStructureEntry", () => {
|
|
|
162
164
|
expect(json->String.includes("\"apiExposed\":true"))->toEqual(true)
|
|
163
165
|
)
|
|
164
166
|
|
|
165
|
-
testSync("encodes None
|
|
166
|
-
expect(json->String.includes("\"
|
|
167
|
+
testSync("encodes None lifecycleField as null", () =>
|
|
168
|
+
expect(json->String.includes("\"lifecycleField\":null"))->toEqual(true)
|
|
167
169
|
)
|
|
168
170
|
|
|
169
171
|
// Phase 6.3: write-side emitted-event field schemas.
|
|
@@ -256,7 +258,7 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
|
|
|
256
258
|
labelField: "name",
|
|
257
259
|
searchableFields: ["name"],
|
|
258
260
|
labelFieldSource: Some("convention"),
|
|
259
|
-
|
|
261
|
+
lifecycleField: None,
|
|
260
262
|
visibility: Some("Internal"),
|
|
261
263
|
chapter: None,
|
|
262
264
|
singleQueryField: Some("Ordering_AvailableProduct"),
|
|
@@ -264,6 +266,8 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
|
|
|
264
266
|
idFieldSource: Some("sole"),
|
|
265
267
|
requiredAccess: None,
|
|
266
268
|
ownerField: None,
|
|
269
|
+
retiredField: None,
|
|
270
|
+
retiredValues: None,
|
|
267
271
|
}
|
|
268
272
|
// A distinct name per source array: the complement has to be fed by both, and
|
|
269
273
|
// reusing one def would hide a version that only walks `readModels`.
|
|
@@ -329,7 +333,7 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
|
|
|
329
333
|
})
|
|
330
334
|
})
|
|
331
335
|
|
|
332
|
-
describe("allowedStates +
|
|
336
|
+
describe("allowedStates + lifecycleField populated", () => {
|
|
333
337
|
let cmdWithStates: commandDef = {
|
|
334
338
|
name: "Activate",
|
|
335
339
|
schema: "{}",
|
|
@@ -353,7 +357,7 @@ describe("allowedStates + statusField populated", () => {
|
|
|
353
357
|
labelField: "name",
|
|
354
358
|
searchableFields: ["name"],
|
|
355
359
|
labelFieldSource: Some("convention"),
|
|
356
|
-
|
|
360
|
+
lifecycleField: Some("status"),
|
|
357
361
|
visibility: None,
|
|
358
362
|
chapter: None,
|
|
359
363
|
singleQueryField: Some("Platform_Plugin"),
|
|
@@ -361,6 +365,8 @@ describe("allowedStates + statusField populated", () => {
|
|
|
361
365
|
idFieldSource: None,
|
|
362
366
|
requiredAccess: None,
|
|
363
367
|
ownerField: None,
|
|
368
|
+
retiredField: None,
|
|
369
|
+
retiredValues: None,
|
|
364
370
|
}
|
|
365
371
|
|
|
366
372
|
let wblWithStates: writableDef = {
|
|
@@ -402,8 +408,8 @@ describe("allowedStates + statusField populated", () => {
|
|
|
402
408
|
expect(json->String.includes("\"targetState\":\"Active\""))->toEqual(true)
|
|
403
409
|
)
|
|
404
410
|
|
|
405
|
-
testSync("encodes populated
|
|
406
|
-
expect(json->String.includes("\"
|
|
411
|
+
testSync("encodes populated lifecycleField as the field name string", () =>
|
|
412
|
+
expect(json->String.includes("\"lifecycleField\":\"status\""))->toEqual(true)
|
|
407
413
|
)
|
|
408
414
|
|
|
409
415
|
// "declares no errors" is an empty list, never null — the SDL types `errors` as
|
|
@@ -51,8 +51,10 @@ let qbl = {
|
|
|
51
51
|
labelField: "displayName",
|
|
52
52
|
searchableFields: qbl_searchableFields,
|
|
53
53
|
labelFieldSource: qbl_labelFieldSource,
|
|
54
|
-
|
|
54
|
+
lifecycleField: undefined,
|
|
55
55
|
ownerField: undefined,
|
|
56
|
+
retiredField: undefined,
|
|
57
|
+
retiredValues: undefined,
|
|
56
58
|
visibility: undefined,
|
|
57
59
|
chapter: undefined,
|
|
58
60
|
singleQueryField: qbl_singleQueryField,
|
|
@@ -198,8 +200,8 @@ globalThis.describe("encodePluginStructureEntry", () => {
|
|
|
198
200
|
globalThis.test("encodes the command's apiExposed flag (drives the event-graph API badge)", () => {
|
|
199
201
|
globalThis.expect(json.includes("\"apiExposed\":true")).toEqual(true);
|
|
200
202
|
});
|
|
201
|
-
globalThis.test("encodes None
|
|
202
|
-
globalThis.expect(json.includes("\"
|
|
203
|
+
globalThis.test("encodes None lifecycleField as null", () => {
|
|
204
|
+
globalThis.expect(json.includes("\"lifecycleField\":null")).toEqual(true);
|
|
203
205
|
});
|
|
204
206
|
globalThis.test("encodes writableDef events", () => {
|
|
205
207
|
globalThis.expect(json.includes("\"events\":[{\"name\":\"ProductAdded\"")).toEqual(true);
|
|
@@ -282,8 +284,10 @@ globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", ()
|
|
|
282
284
|
labelField: "name",
|
|
283
285
|
searchableFields: internalQbl_searchableFields,
|
|
284
286
|
labelFieldSource: internalQbl_labelFieldSource,
|
|
285
|
-
|
|
287
|
+
lifecycleField: undefined,
|
|
286
288
|
ownerField: undefined,
|
|
289
|
+
retiredField: undefined,
|
|
290
|
+
retiredValues: undefined,
|
|
287
291
|
visibility: internalQbl_visibility,
|
|
288
292
|
chapter: undefined,
|
|
289
293
|
singleQueryField: internalQbl_singleQueryField,
|
|
@@ -308,8 +312,10 @@ globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", ()
|
|
|
308
312
|
labelField: "name",
|
|
309
313
|
searchableFields: internalSlice_searchableFields,
|
|
310
314
|
labelFieldSource: internalSlice_labelFieldSource,
|
|
311
|
-
|
|
315
|
+
lifecycleField: undefined,
|
|
312
316
|
ownerField: undefined,
|
|
317
|
+
retiredField: undefined,
|
|
318
|
+
retiredValues: undefined,
|
|
313
319
|
visibility: internalSlice_visibility,
|
|
314
320
|
chapter: undefined,
|
|
315
321
|
singleQueryField: internalSlice_singleQueryField,
|
|
@@ -378,7 +384,7 @@ globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", ()
|
|
|
378
384
|
});
|
|
379
385
|
});
|
|
380
386
|
|
|
381
|
-
globalThis.describe("allowedStates +
|
|
387
|
+
globalThis.describe("allowedStates + lifecycleField populated", () => {
|
|
382
388
|
let cmdWithStates_aggregateIdField = "id";
|
|
383
389
|
let cmdWithStates_references = [];
|
|
384
390
|
let cmdWithStates_allowedStates = ["Inactive"];
|
|
@@ -401,7 +407,7 @@ globalThis.describe("allowedStates + statusField populated", () => {
|
|
|
401
407
|
let qblWithStatus_linkedWriteSide = ["Plugin"];
|
|
402
408
|
let qblWithStatus_searchableFields = ["name"];
|
|
403
409
|
let qblWithStatus_labelFieldSource = "convention";
|
|
404
|
-
let
|
|
410
|
+
let qblWithStatus_lifecycleField = "status";
|
|
405
411
|
let qblWithStatus_singleQueryField = "Platform_Plugin";
|
|
406
412
|
let qblWithStatus = {
|
|
407
413
|
name: "Plugin",
|
|
@@ -412,8 +418,10 @@ globalThis.describe("allowedStates + statusField populated", () => {
|
|
|
412
418
|
labelField: "name",
|
|
413
419
|
searchableFields: qblWithStatus_searchableFields,
|
|
414
420
|
labelFieldSource: qblWithStatus_labelFieldSource,
|
|
415
|
-
|
|
421
|
+
lifecycleField: qblWithStatus_lifecycleField,
|
|
416
422
|
ownerField: undefined,
|
|
423
|
+
retiredField: undefined,
|
|
424
|
+
retiredValues: undefined,
|
|
417
425
|
visibility: undefined,
|
|
418
426
|
chapter: undefined,
|
|
419
427
|
singleQueryField: qblWithStatus_singleQueryField,
|
|
@@ -466,8 +474,8 @@ globalThis.describe("allowedStates + statusField populated", () => {
|
|
|
466
474
|
globalThis.test("round-trips a declared targetState as the status string", () => {
|
|
467
475
|
globalThis.expect(json.includes("\"targetState\":\"Active\"")).toEqual(true);
|
|
468
476
|
});
|
|
469
|
-
globalThis.test("encodes populated
|
|
470
|
-
globalThis.expect(json.includes("\"
|
|
477
|
+
globalThis.test("encodes populated lifecycleField as the field name string", () => {
|
|
478
|
+
globalThis.expect(json.includes("\"lifecycleField\":\"status\"")).toEqual(true);
|
|
471
479
|
});
|
|
472
480
|
globalThis.test("encodes a component with no declared errors as an empty array, not null", () => {
|
|
473
481
|
globalThis.expect(json.includes("\"errors\":[]")).toEqual(true);
|
|
@@ -491,8 +499,10 @@ globalThis.describe("singleQueryField reaches the caller", () => {
|
|
|
491
499
|
labelField: "displayName",
|
|
492
500
|
searchableFields: qbl_searchableFields,
|
|
493
501
|
labelFieldSource: "annotation",
|
|
494
|
-
|
|
502
|
+
lifecycleField: undefined,
|
|
495
503
|
ownerField: undefined,
|
|
504
|
+
retiredField: undefined,
|
|
505
|
+
retiredValues: undefined,
|
|
496
506
|
visibility: undefined,
|
|
497
507
|
chapter: undefined,
|
|
498
508
|
singleQueryField: undefined,
|
|
@@ -536,8 +546,10 @@ globalThis.describe("idField / idFieldSource reach the caller", () => {
|
|
|
536
546
|
labelField: "displayName",
|
|
537
547
|
searchableFields: qbl_searchableFields,
|
|
538
548
|
labelFieldSource: "annotation",
|
|
539
|
-
|
|
549
|
+
lifecycleField: undefined,
|
|
540
550
|
ownerField: undefined,
|
|
551
|
+
retiredField: undefined,
|
|
552
|
+
retiredValues: undefined,
|
|
541
553
|
visibility: undefined,
|
|
542
554
|
chapter: undefined,
|
|
543
555
|
singleQueryField: "Catalog_Product",
|
|
@@ -16,7 +16,7 @@ let publicRm: queryableDef = {
|
|
|
16
16
|
labelField: "displayName",
|
|
17
17
|
searchableFields: ["displayName"],
|
|
18
18
|
labelFieldSource: Some("annotation"),
|
|
19
|
-
|
|
19
|
+
lifecycleField: None,
|
|
20
20
|
visibility: None,
|
|
21
21
|
chapter: Some("Inventory"),
|
|
22
22
|
singleQueryField: Some("Catalog_Product"),
|
|
@@ -24,6 +24,8 @@ let publicRm: queryableDef = {
|
|
|
24
24
|
idFieldSource: Some("convention"),
|
|
25
25
|
requiredAccess: None,
|
|
26
26
|
ownerField: None,
|
|
27
|
+
retiredField: None,
|
|
28
|
+
retiredValues: None,
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
// The component `Platform_ComponentDefinitions` drops and this query must keep.
|
|
@@ -31,8 +31,10 @@ let publicRm = {
|
|
|
31
31
|
labelField: "displayName",
|
|
32
32
|
searchableFields: publicRm_searchableFields,
|
|
33
33
|
labelFieldSource: publicRm_labelFieldSource,
|
|
34
|
-
|
|
34
|
+
lifecycleField: undefined,
|
|
35
35
|
ownerField: undefined,
|
|
36
|
+
retiredField: undefined,
|
|
37
|
+
retiredValues: undefined,
|
|
36
38
|
visibility: undefined,
|
|
37
39
|
chapter: publicRm_chapter,
|
|
38
40
|
singleQueryField: publicRm_singleQueryField,
|
|
@@ -68,8 +70,10 @@ let internalRm = {
|
|
|
68
70
|
labelField: "displayName",
|
|
69
71
|
searchableFields: internalRm_searchableFields,
|
|
70
72
|
labelFieldSource: internalRm_labelFieldSource,
|
|
71
|
-
|
|
73
|
+
lifecycleField: undefined,
|
|
72
74
|
ownerField: undefined,
|
|
75
|
+
retiredField: undefined,
|
|
76
|
+
retiredValues: undefined,
|
|
73
77
|
visibility: internalRm_visibility,
|
|
74
78
|
chapter: internalRm_chapter,
|
|
75
79
|
singleQueryField: internalRm_singleQueryField,
|
|
@@ -77,7 +77,7 @@ globalThis.describe("filter.ids matches whichever form each side holds", () => {
|
|
|
77
77
|
"ids",
|
|
78
78
|
filterIds.map(prim => prim)
|
|
79
79
|
]]);
|
|
80
|
-
let conn = QueryDbListQuery$ReventlessCore.run([row(rowId)], args, GraphQL_FragmentGenerator$ReventlessCore.emptyCapability, "name", undefined, undefined);
|
|
80
|
+
let conn = QueryDbListQuery$ReventlessCore.run([row(rowId)], args, GraphQL_FragmentGenerator$ReventlessCore.emptyCapability, "name", undefined, undefined, undefined);
|
|
81
81
|
return Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(conn), d => d["edges"]), Stdlib_JSON.Decode.array), []).length;
|
|
82
82
|
};
|
|
83
83
|
globalThis.test("storage key row, storage key filter", () => {
|