@webiny/app-headless-cms 6.6.0-alpha.7 → 6.6.0-alpha.9
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/admin/components/ContentModelEditor/evaluateExpression.d.ts +1 -1
- package/admin/components/ContentModelEditor/evaluateExpression.js +6 -0
- package/admin/components/ContentModelEditor/evaluateExpression.js.map +1 -1
- package/admin/components/ContentModelEditor/operatorOptions.js +12 -0
- package/admin/components/ContentModelEditor/operatorOptions.js.map +1 -1
- package/features/formModel/CmsLayoutMapper.js +4 -4
- package/features/formModel/CmsLayoutMapper.js.map +1 -1
- package/features/formModel/feature.js +0 -2
- package/features/formModel/feature.js.map +1 -1
- package/features/formModel/mappers/applyFieldProps.js +1 -1
- package/features/formModel/mappers/applyFieldProps.js.map +1 -1
- package/features/formModel/mappers/applyFieldProps.test.js +2 -0
- package/features/formModel/mappers/applyFieldProps.test.js.map +1 -1
- package/package.json +19 -19
- package/presentation/cloneContentModel/CloneContentModelPresenter.d.ts +1 -0
- package/presentation/cloneContentModel/CloneContentModelPresenter.js +8 -6
- package/presentation/cloneContentModel/CloneContentModelPresenter.js.map +1 -1
- package/presentation/contentEntries/form/getFieldBuilders.test.js +2 -0
- package/presentation/contentEntries/form/getFieldBuilders.test.js.map +1 -1
- package/presentation/newContentModel/NewContentModelPresenter.d.ts +1 -0
- package/presentation/newContentModel/NewContentModelPresenter.js +8 -6
- package/presentation/newContentModel/NewContentModelPresenter.js.map +1 -1
- package/features/formModel/CmsAccessControlRuleEvaluator.d.ts +0 -9
- package/features/formModel/CmsAccessControlRuleEvaluator.js +0 -16
- package/features/formModel/CmsAccessControlRuleEvaluator.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type Operator = "==" | "!=" | ">" | "<" | ">=" | "<=" | "contains" | "startsWith" | "endsWith" | "isEmpty" | "isNotEmpty";
|
|
1
|
+
export type Operator = "==" | "!=" | ">" | "<" | ">=" | "<=" | "contains" | "notContains" | "startsWith" | "notStartsWith" | "endsWith" | "notEndsWith" | "isEmpty" | "isNotEmpty";
|
|
2
2
|
export interface ParsedExpression {
|
|
3
3
|
target: string;
|
|
4
4
|
operator: Operator;
|
|
@@ -39,10 +39,16 @@ function compareValues(operator, val, rhs) {
|
|
|
39
39
|
return Number(val) <= Number(rhs);
|
|
40
40
|
case "contains":
|
|
41
41
|
return String(val ?? "").includes(String(rhs ?? ""));
|
|
42
|
+
case "notContains":
|
|
43
|
+
return !String(val ?? "").includes(String(rhs ?? ""));
|
|
42
44
|
case "startsWith":
|
|
43
45
|
return String(val ?? "").startsWith(String(rhs ?? ""));
|
|
46
|
+
case "notStartsWith":
|
|
47
|
+
return !String(val ?? "").startsWith(String(rhs ?? ""));
|
|
44
48
|
case "endsWith":
|
|
45
49
|
return String(val ?? "").endsWith(String(rhs ?? ""));
|
|
50
|
+
case "notEndsWith":
|
|
51
|
+
return !String(val ?? "").endsWith(String(rhs ?? ""));
|
|
46
52
|
case "isEmpty":
|
|
47
53
|
return null == val || "" === val || Array.isArray(val) && 0 === val.length;
|
|
48
54
|
case "isNotEmpty":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin/components/ContentModelEditor/evaluateExpression.js","sources":["../../../../src/admin/components/ContentModelEditor/evaluateExpression.ts"],"sourcesContent":["export type Operator =\n | \"==\"\n | \"!=\"\n | \">\"\n | \"<\"\n | \">=\"\n | \"<=\"\n | \"contains\"\n | \"startsWith\"\n | \"endsWith\"\n | \"isEmpty\"\n | \"isNotEmpty\";\n\nexport interface ParsedExpression {\n target: string;\n operator: Operator;\n value: string | number | boolean | null;\n}\n\n/**\n * Resolve a fieldPath that may contain `$` placeholders using the bindParentName.\n *\n * The bindParentName gives us the concrete indices for the current list context.\n * For example, if fieldPath is `panorama.hotspots.$.title` and bindParentName\n * is `panorama.hotspots.2`, the result is `panorama.hotspots.2.title`.\n *\n * Supports multiple nested `$` segments for deeply nested list objects.\n */\nexport function resolveFieldPath(fieldPath: string, bindParentName?: string): string {\n if (!fieldPath.includes(\"$\")) {\n return fieldPath;\n }\n\n if (fieldPath.startsWith(\"$.\")) {\n const relative = fieldPath.slice(2);\n return bindParentName ? `${bindParentName}.${relative}` : relative;\n }\n\n if (!bindParentName) {\n // No parent context, replace $ with 0 as fallback\n return fieldPath.replace(/\\$/g, \"0\");\n }\n\n const pathParts = fieldPath.split(\".\");\n const parentParts = bindParentName.split(\".\");\n\n // Build a map of prefix -> index from the parent path.\n // E.g., parentName \"panorama.hotspots.2.items.1\" gives us:\n // \"panorama.hotspots\" -> \"2\"\n // \"panorama.hotspots.2.items\" -> \"1\"\n const indexMap = new Map<string, string>();\n const prefixParts: string[] = [];\n for (const part of parentParts) {\n if (/^\\d+$/.test(part)) {\n indexMap.set(prefixParts.join(\".\"), part);\n } else {\n prefixParts.push(part);\n }\n }\n\n // Walk through pathParts and replace each `$` with the corresponding index\n const resolved: string[] = [];\n const currentPrefix: string[] = [];\n for (const part of pathParts) {\n if (part === \"$\") {\n const key = currentPrefix.join(\".\");\n const index = indexMap.get(key) ?? \"0\";\n resolved.push(index);\n } else {\n currentPrefix.push(part);\n resolved.push(part);\n }\n }\n\n return resolved.join(\".\");\n}\n\nfunction compareValues(\n operator: string,\n val: unknown,\n rhs: string | number | boolean | null\n): boolean {\n switch (operator) {\n case \"==\":\n return val == rhs;\n case \"!=\":\n return val != rhs;\n case \">\":\n return Number(val) > Number(rhs);\n case \"<\":\n return Number(val) < Number(rhs);\n case \">=\":\n return Number(val) >= Number(rhs);\n case \"<=\":\n return Number(val) <= Number(rhs);\n case \"contains\":\n return String(val ?? \"\").includes(String(rhs ?? \"\"));\n case \"startsWith\":\n return String(val ?? \"\").startsWith(String(rhs ?? \"\"));\n case \"endsWith\":\n return String(val ?? \"\").endsWith(String(rhs ?? \"\"));\n case \"isEmpty\":\n return val == null || val === \"\" || (Array.isArray(val) && val.length === 0);\n case \"isNotEmpty\":\n return val != null && val !== \"\" && !(Array.isArray(val) && val.length === 0);\n default:\n return false;\n }\n}\n\n/**\n * Evaluate a parsed expression against form values.\n *\n * If the resolved fieldPath ends with `.length`, it reads the array at the parent\n * path and uses its length as the left-hand value.\n */\nexport function evaluateExpression(\n parsed: ParsedExpression,\n getFormValue: (path: string) => unknown\n): boolean {\n const { target, operator, value: rhs } = parsed;\n\n let val: unknown;\n if (target.endsWith(\".length\")) {\n const arrayPath = target.slice(0, -\".length\".length);\n const arr = getFormValue(arrayPath);\n val = Array.isArray(arr) ? arr.length : 0;\n } else {\n val = getFormValue(target);\n }\n\n return compareValues(operator, val, rhs);\n}\n"],"names":["resolveFieldPath","fieldPath","bindParentName","relative","pathParts","parentParts","indexMap","Map","prefixParts","part","resolved","currentPrefix","key","index","compareValues","operator","val","rhs","Number","String","Array","evaluateExpression","parsed","getFormValue","target","arrayPath","arr"],"mappings":"
|
|
1
|
+
{"version":3,"file":"admin/components/ContentModelEditor/evaluateExpression.js","sources":["../../../../src/admin/components/ContentModelEditor/evaluateExpression.ts"],"sourcesContent":["export type Operator =\n | \"==\"\n | \"!=\"\n | \">\"\n | \"<\"\n | \">=\"\n | \"<=\"\n | \"contains\"\n | \"notContains\"\n | \"startsWith\"\n | \"notStartsWith\"\n | \"endsWith\"\n | \"notEndsWith\"\n | \"isEmpty\"\n | \"isNotEmpty\";\n\nexport interface ParsedExpression {\n target: string;\n operator: Operator;\n value: string | number | boolean | null;\n}\n\n/**\n * Resolve a fieldPath that may contain `$` placeholders using the bindParentName.\n *\n * The bindParentName gives us the concrete indices for the current list context.\n * For example, if fieldPath is `panorama.hotspots.$.title` and bindParentName\n * is `panorama.hotspots.2`, the result is `panorama.hotspots.2.title`.\n *\n * Supports multiple nested `$` segments for deeply nested list objects.\n */\nexport function resolveFieldPath(fieldPath: string, bindParentName?: string): string {\n if (!fieldPath.includes(\"$\")) {\n return fieldPath;\n }\n\n if (fieldPath.startsWith(\"$.\")) {\n const relative = fieldPath.slice(2);\n return bindParentName ? `${bindParentName}.${relative}` : relative;\n }\n\n if (!bindParentName) {\n // No parent context, replace $ with 0 as fallback\n return fieldPath.replace(/\\$/g, \"0\");\n }\n\n const pathParts = fieldPath.split(\".\");\n const parentParts = bindParentName.split(\".\");\n\n // Build a map of prefix -> index from the parent path.\n // E.g., parentName \"panorama.hotspots.2.items.1\" gives us:\n // \"panorama.hotspots\" -> \"2\"\n // \"panorama.hotspots.2.items\" -> \"1\"\n const indexMap = new Map<string, string>();\n const prefixParts: string[] = [];\n for (const part of parentParts) {\n if (/^\\d+$/.test(part)) {\n indexMap.set(prefixParts.join(\".\"), part);\n } else {\n prefixParts.push(part);\n }\n }\n\n // Walk through pathParts and replace each `$` with the corresponding index\n const resolved: string[] = [];\n const currentPrefix: string[] = [];\n for (const part of pathParts) {\n if (part === \"$\") {\n const key = currentPrefix.join(\".\");\n const index = indexMap.get(key) ?? \"0\";\n resolved.push(index);\n } else {\n currentPrefix.push(part);\n resolved.push(part);\n }\n }\n\n return resolved.join(\".\");\n}\n\nfunction compareValues(\n operator: string,\n val: unknown,\n rhs: string | number | boolean | null\n): boolean {\n switch (operator) {\n case \"==\":\n return val == rhs;\n case \"!=\":\n return val != rhs;\n case \">\":\n return Number(val) > Number(rhs);\n case \"<\":\n return Number(val) < Number(rhs);\n case \">=\":\n return Number(val) >= Number(rhs);\n case \"<=\":\n return Number(val) <= Number(rhs);\n case \"contains\":\n return String(val ?? \"\").includes(String(rhs ?? \"\"));\n case \"notContains\":\n return !String(val ?? \"\").includes(String(rhs ?? \"\"));\n case \"startsWith\":\n return String(val ?? \"\").startsWith(String(rhs ?? \"\"));\n case \"notStartsWith\":\n return !String(val ?? \"\").startsWith(String(rhs ?? \"\"));\n case \"endsWith\":\n return String(val ?? \"\").endsWith(String(rhs ?? \"\"));\n case \"notEndsWith\":\n return !String(val ?? \"\").endsWith(String(rhs ?? \"\"));\n case \"isEmpty\":\n return val == null || val === \"\" || (Array.isArray(val) && val.length === 0);\n case \"isNotEmpty\":\n return val != null && val !== \"\" && !(Array.isArray(val) && val.length === 0);\n default:\n return false;\n }\n}\n\n/**\n * Evaluate a parsed expression against form values.\n *\n * If the resolved fieldPath ends with `.length`, it reads the array at the parent\n * path and uses its length as the left-hand value.\n */\nexport function evaluateExpression(\n parsed: ParsedExpression,\n getFormValue: (path: string) => unknown\n): boolean {\n const { target, operator, value: rhs } = parsed;\n\n let val: unknown;\n if (target.endsWith(\".length\")) {\n const arrayPath = target.slice(0, -\".length\".length);\n const arr = getFormValue(arrayPath);\n val = Array.isArray(arr) ? arr.length : 0;\n } else {\n val = getFormValue(target);\n }\n\n return compareValues(operator, val, rhs);\n}\n"],"names":["resolveFieldPath","fieldPath","bindParentName","relative","pathParts","parentParts","indexMap","Map","prefixParts","part","resolved","currentPrefix","key","index","compareValues","operator","val","rhs","Number","String","Array","evaluateExpression","parsed","getFormValue","target","arrayPath","arr"],"mappings":"AA+BO,SAASA,iBAAiBC,SAAiB,EAAEC,cAAuB;IACvE,IAAI,CAACD,UAAU,QAAQ,CAAC,MACpB,OAAOA;IAGX,IAAIA,UAAU,UAAU,CAAC,OAAO;QAC5B,MAAME,WAAWF,UAAU,KAAK,CAAC;QACjC,OAAOC,iBAAiB,GAAGA,eAAe,CAAC,EAAEC,UAAU,GAAGA;IAC9D;IAEA,IAAI,CAACD,gBAED,OAAOD,UAAU,OAAO,CAAC,OAAO;IAGpC,MAAMG,YAAYH,UAAU,KAAK,CAAC;IAClC,MAAMI,cAAcH,eAAe,KAAK,CAAC;IAMzC,MAAMI,WAAW,IAAIC;IACrB,MAAMC,cAAwB,EAAE;IAChC,KAAK,MAAMC,QAAQJ,YACf,IAAI,QAAQ,IAAI,CAACI,OACbH,SAAS,GAAG,CAACE,YAAY,IAAI,CAAC,MAAMC;SAEpCD,YAAY,IAAI,CAACC;IAKzB,MAAMC,WAAqB,EAAE;IAC7B,MAAMC,gBAA0B,EAAE;IAClC,KAAK,MAAMF,QAAQL,UACf,IAAIK,AAAS,QAATA,MAAc;QACd,MAAMG,MAAMD,cAAc,IAAI,CAAC;QAC/B,MAAME,QAAQP,SAAS,GAAG,CAACM,QAAQ;QACnCF,SAAS,IAAI,CAACG;IAClB,OAAO;QACHF,cAAc,IAAI,CAACF;QACnBC,SAAS,IAAI,CAACD;IAClB;IAGJ,OAAOC,SAAS,IAAI,CAAC;AACzB;AAEA,SAASI,cACLC,QAAgB,EAChBC,GAAY,EACZC,GAAqC;IAErC,OAAQF;QACJ,KAAK;YACD,OAAOC,OAAOC;QAClB,KAAK;YACD,OAAOD,OAAOC;QAClB,KAAK;YACD,OAAOC,OAAOF,OAAOE,OAAOD;QAChC,KAAK;YACD,OAAOC,OAAOF,OAAOE,OAAOD;QAChC,KAAK;YACD,OAAOC,OAAOF,QAAQE,OAAOD;QACjC,KAAK;YACD,OAAOC,OAAOF,QAAQE,OAAOD;QACjC,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACpD,KAAK;YACD,OAAO,CAACE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACrD,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,UAAU,CAACG,OAAOF,OAAO;QACtD,KAAK;YACD,OAAO,CAACE,OAAOH,OAAO,IAAI,UAAU,CAACG,OAAOF,OAAO;QACvD,KAAK;YACD,OAAOE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACpD,KAAK;YACD,OAAO,CAACE,OAAOH,OAAO,IAAI,QAAQ,CAACG,OAAOF,OAAO;QACrD,KAAK;YACD,OAAOD,AAAO,QAAPA,OAAeA,AAAQ,OAARA,OAAeI,MAAM,OAAO,CAACJ,QAAQA,AAAe,MAAfA,IAAI,MAAM;QACzE,KAAK;YACD,OAAOA,AAAO,QAAPA,OAAeA,AAAQ,OAARA,OAAc,CAAEI,CAAAA,MAAM,OAAO,CAACJ,QAAQA,AAAe,MAAfA,IAAI,MAAM,AAAK;QAC/E;YACI,OAAO;IACf;AACJ;AAQO,SAASK,mBACZC,MAAwB,EACxBC,YAAuC;IAEvC,MAAM,EAAEC,MAAM,EAAET,QAAQ,EAAE,OAAOE,GAAG,EAAE,GAAGK;IAEzC,IAAIN;IACJ,IAAIQ,OAAO,QAAQ,CAAC,YAAY;QAC5B,MAAMC,YAAYD,OAAO,KAAK,CAAC,GAAG;QAClC,MAAME,MAAMH,aAAaE;QACzBT,MAAMI,MAAM,OAAO,CAACM,OAAOA,IAAI,MAAM,GAAG;IAC5C,OACIV,MAAMO,aAAaC;IAGvB,OAAOV,cAAcC,UAAUC,KAAKC;AACxC"}
|
|
@@ -45,14 +45,26 @@ const TEXT_OPERATORS = [
|
|
|
45
45
|
value: "contains",
|
|
46
46
|
label: "Contains"
|
|
47
47
|
},
|
|
48
|
+
{
|
|
49
|
+
value: "notContains",
|
|
50
|
+
label: "Does not contain"
|
|
51
|
+
},
|
|
48
52
|
{
|
|
49
53
|
value: "startsWith",
|
|
50
54
|
label: "Starts with"
|
|
51
55
|
},
|
|
56
|
+
{
|
|
57
|
+
value: "notStartsWith",
|
|
58
|
+
label: "Does not start with"
|
|
59
|
+
},
|
|
52
60
|
{
|
|
53
61
|
value: "endsWith",
|
|
54
62
|
label: "Ends with"
|
|
55
63
|
},
|
|
64
|
+
{
|
|
65
|
+
value: "notEndsWith",
|
|
66
|
+
label: "Does not end with"
|
|
67
|
+
},
|
|
56
68
|
{
|
|
57
69
|
value: "isEmpty",
|
|
58
70
|
label: "Is empty"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin/components/ContentModelEditor/operatorOptions.js","sources":["../../../../src/admin/components/ContentModelEditor/operatorOptions.ts"],"sourcesContent":["import type { Operator } from \"./evaluateExpression.js\";\n\nexport interface OperatorOption {\n value: Operator;\n label: string;\n}\n\nconst NUMERIC_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" },\n { value: \">\", label: \"Greater than\" },\n { value: \"<\", label: \"Less than\" },\n { value: \">=\", label: \"Greater or equal\" },\n { value: \"<=\", label: \"Less or equal\" },\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst TEXT_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" },\n { value: \"contains\", label: \"Contains\" },\n { value: \"startsWith\", label: \"Starts with\" },\n { value: \"endsWith\", label: \"Ends with\" },\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst BOOLEAN_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" }\n];\n\nconst FILE_OPERATORS: OperatorOption[] = [\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst DEFAULT_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" },\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst OPERATORS_BY_TYPE: Record<string, OperatorOption[]> = {\n number: NUMERIC_OPERATORS,\n datetime: NUMERIC_OPERATORS,\n text: TEXT_OPERATORS,\n \"long-text\": TEXT_OPERATORS,\n boolean: BOOLEAN_OPERATORS,\n file: FILE_OPERATORS\n};\n\nexport function getOperatorOptions(fieldType: string): OperatorOption[] {\n return OPERATORS_BY_TYPE[fieldType] ?? DEFAULT_OPERATORS;\n}\n\n/**\n * Operators that don't need a value input (the value is implicit).\n */\nexport const VALUE_HIDDEN_OPERATORS: Set<Operator> = new Set([\"isEmpty\", \"isNotEmpty\"]);\n"],"names":["NUMERIC_OPERATORS","TEXT_OPERATORS","BOOLEAN_OPERATORS","FILE_OPERATORS","DEFAULT_OPERATORS","OPERATORS_BY_TYPE","getOperatorOptions","fieldType","VALUE_HIDDEN_OPERATORS","Set"],"mappings":"AAOA,MAAMA,oBAAsC;IACxC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;IACnC;QAAE,OAAO;QAAK,OAAO;IAAe;IACpC;QAAE,OAAO;QAAK,OAAO;IAAY;IACjC;QAAE,OAAO;QAAM,OAAO;IAAmB;IACzC;QAAE,OAAO;QAAM,OAAO;IAAgB;IACtC;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,iBAAmC;IACrC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;IACnC;QAAE,OAAO;QAAY,OAAO;IAAW;IACvC;QAAE,OAAO;QAAc,OAAO;IAAc;IAC5C;QAAE,OAAO;QAAY,OAAO;IAAY;IACxC;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,oBAAsC;IACxC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;CACtC;AAED,MAAMC,iBAAmC;IACrC;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,oBAAsC;IACxC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;IACnC;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,oBAAsD;IACxD,QAAQL;IACR,UAAUA;IACV,MAAMC;IACN,aAAaA;IACb,SAASC;IACT,MAAMC;AACV;AAEO,SAASG,mBAAmBC,SAAiB;IAChD,OAAOF,iBAAiB,CAACE,UAAU,IAAIH;AAC3C;AAKO,MAAMI,yBAAwC,IAAIC,IAAI;IAAC;IAAW;CAAa"}
|
|
1
|
+
{"version":3,"file":"admin/components/ContentModelEditor/operatorOptions.js","sources":["../../../../src/admin/components/ContentModelEditor/operatorOptions.ts"],"sourcesContent":["import type { Operator } from \"./evaluateExpression.js\";\n\nexport interface OperatorOption {\n value: Operator;\n label: string;\n}\n\nconst NUMERIC_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" },\n { value: \">\", label: \"Greater than\" },\n { value: \"<\", label: \"Less than\" },\n { value: \">=\", label: \"Greater or equal\" },\n { value: \"<=\", label: \"Less or equal\" },\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst TEXT_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" },\n { value: \"contains\", label: \"Contains\" },\n { value: \"notContains\", label: \"Does not contain\" },\n { value: \"startsWith\", label: \"Starts with\" },\n { value: \"notStartsWith\", label: \"Does not start with\" },\n { value: \"endsWith\", label: \"Ends with\" },\n { value: \"notEndsWith\", label: \"Does not end with\" },\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst BOOLEAN_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" }\n];\n\nconst FILE_OPERATORS: OperatorOption[] = [\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst DEFAULT_OPERATORS: OperatorOption[] = [\n { value: \"==\", label: \"Equals\" },\n { value: \"!=\", label: \"Not equals\" },\n { value: \"isEmpty\", label: \"Is empty\" },\n { value: \"isNotEmpty\", label: \"Is not empty\" }\n];\n\nconst OPERATORS_BY_TYPE: Record<string, OperatorOption[]> = {\n number: NUMERIC_OPERATORS,\n datetime: NUMERIC_OPERATORS,\n text: TEXT_OPERATORS,\n \"long-text\": TEXT_OPERATORS,\n boolean: BOOLEAN_OPERATORS,\n file: FILE_OPERATORS\n};\n\nexport function getOperatorOptions(fieldType: string): OperatorOption[] {\n return OPERATORS_BY_TYPE[fieldType] ?? DEFAULT_OPERATORS;\n}\n\n/**\n * Operators that don't need a value input (the value is implicit).\n */\nexport const VALUE_HIDDEN_OPERATORS: Set<Operator> = new Set([\"isEmpty\", \"isNotEmpty\"]);\n"],"names":["NUMERIC_OPERATORS","TEXT_OPERATORS","BOOLEAN_OPERATORS","FILE_OPERATORS","DEFAULT_OPERATORS","OPERATORS_BY_TYPE","getOperatorOptions","fieldType","VALUE_HIDDEN_OPERATORS","Set"],"mappings":"AAOA,MAAMA,oBAAsC;IACxC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;IACnC;QAAE,OAAO;QAAK,OAAO;IAAe;IACpC;QAAE,OAAO;QAAK,OAAO;IAAY;IACjC;QAAE,OAAO;QAAM,OAAO;IAAmB;IACzC;QAAE,OAAO;QAAM,OAAO;IAAgB;IACtC;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,iBAAmC;IACrC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;IACnC;QAAE,OAAO;QAAY,OAAO;IAAW;IACvC;QAAE,OAAO;QAAe,OAAO;IAAmB;IAClD;QAAE,OAAO;QAAc,OAAO;IAAc;IAC5C;QAAE,OAAO;QAAiB,OAAO;IAAsB;IACvD;QAAE,OAAO;QAAY,OAAO;IAAY;IACxC;QAAE,OAAO;QAAe,OAAO;IAAoB;IACnD;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,oBAAsC;IACxC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;CACtC;AAED,MAAMC,iBAAmC;IACrC;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,oBAAsC;IACxC;QAAE,OAAO;QAAM,OAAO;IAAS;IAC/B;QAAE,OAAO;QAAM,OAAO;IAAa;IACnC;QAAE,OAAO;QAAW,OAAO;IAAW;IACtC;QAAE,OAAO;QAAc,OAAO;IAAe;CAChD;AAED,MAAMC,oBAAsD;IACxD,QAAQL;IACR,UAAUA;IACV,MAAMC;IACN,aAAaA;IACb,SAASC;IACT,MAAMC;AACV;AAEO,SAASG,mBAAmBC,SAAiB;IAChD,OAAOF,iBAAiB,CAACE,UAAU,IAAIH;AAC3C;AAKO,MAAMI,yBAAwC,IAAIC,IAAI;IAAC;IAAW;CAAa"}
|
|
@@ -39,7 +39,7 @@ function mapSeparator(field, layoutBuilder) {
|
|
|
39
39
|
type: r.type,
|
|
40
40
|
target: r.target,
|
|
41
41
|
operator: r.operator,
|
|
42
|
-
value:
|
|
42
|
+
value: r.value ?? null,
|
|
43
43
|
action: r.action
|
|
44
44
|
})));
|
|
45
45
|
return builder;
|
|
@@ -57,7 +57,7 @@ function mapTabs(field, layoutBuilder, idToFieldId) {
|
|
|
57
57
|
type: r.type,
|
|
58
58
|
target: r.target,
|
|
59
59
|
operator: r.operator,
|
|
60
|
-
value:
|
|
60
|
+
value: r.value ?? null,
|
|
61
61
|
action: r.action
|
|
62
62
|
})));
|
|
63
63
|
});
|
|
@@ -65,7 +65,7 @@ function mapTabs(field, layoutBuilder, idToFieldId) {
|
|
|
65
65
|
type: r.type,
|
|
66
66
|
target: r.target,
|
|
67
67
|
operator: r.operator,
|
|
68
|
-
value:
|
|
68
|
+
value: r.value ?? null,
|
|
69
69
|
action: r.action
|
|
70
70
|
})));
|
|
71
71
|
return tabsBuilder;
|
|
@@ -78,7 +78,7 @@ function mapAlert(field, layoutBuilder) {
|
|
|
78
78
|
type: r.type,
|
|
79
79
|
target: r.target,
|
|
80
80
|
operator: r.operator,
|
|
81
|
-
value:
|
|
81
|
+
value: r.value ?? null,
|
|
82
82
|
action: r.action
|
|
83
83
|
})));
|
|
84
84
|
return builder;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/formModel/CmsLayoutMapper.js","sources":["../../../src/features/formModel/CmsLayoutMapper.ts"],"sourcesContent":["import {\n isLayoutField,\n type CmsEditorFieldsLayout,\n type CmsLayoutField,\n type CmsSeparatorLayoutField,\n type CmsTabLayoutField,\n type CmsAlertLayoutField\n} from \"~/types.js\";\nimport type {\n ILayoutBuilder,\n ILayoutNodeBuilder\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\nexport function mapCmsLayout(\n cmsLayout: CmsEditorFieldsLayout,\n layoutBuilder: ILayoutBuilder,\n idToFieldId: Map<string, string>\n): ILayoutNodeBuilder[] {\n const nodes: ILayoutNodeBuilder[] = [];\n\n for (const row of cmsLayout) {\n if (row.length === 0) {\n continue;\n }\n\n const firstCell = row[0];\n\n if (row.length === 1 && isLayoutField(firstCell)) {\n const layoutField = firstCell as CmsLayoutField;\n const node = mapLayoutField(layoutField, layoutBuilder, idToFieldId);\n if (node) {\n nodes.push(node);\n }\n continue;\n }\n\n const fieldIds: string[] = [];\n for (const cell of row) {\n if (typeof cell === \"string\") {\n const fieldId = idToFieldId.get(cell);\n if (fieldId) {\n fieldIds.push(fieldId);\n }\n }\n }\n\n if (fieldIds.length > 0) {\n nodes.push(layoutBuilder.row(...fieldIds));\n }\n }\n\n return nodes;\n}\n\nfunction mapLayoutField(\n field: CmsLayoutField,\n layoutBuilder: ILayoutBuilder,\n idToFieldId: Map<string, string>\n): ILayoutNodeBuilder | null {\n switch (field.type) {\n case \"separator\":\n return mapSeparator(field as CmsSeparatorLayoutField, layoutBuilder);\n\n case \"tabs\":\n return mapTabs(field as CmsTabLayoutField, layoutBuilder, idToFieldId);\n\n case \"alert\":\n return mapAlert(field as CmsAlertLayoutField, layoutBuilder);\n\n default:\n return null;\n }\n}\n\nfunction mapSeparator(\n field: CmsSeparatorLayoutField,\n layoutBuilder: ILayoutBuilder\n): ILayoutNodeBuilder {\n const builder = layoutBuilder.separator();\n if (field.label) {\n builder.title(field.label);\n }\n if (field.description) {\n builder.description(field.description);\n }\n if (field.rules) {\n builder.rules(\n field.rules.map(r => ({\n type: r.type,\n target: r.target,\n operator: r.operator,\n value: r.value
|
|
1
|
+
{"version":3,"file":"features/formModel/CmsLayoutMapper.js","sources":["../../../src/features/formModel/CmsLayoutMapper.ts"],"sourcesContent":["import {\n isLayoutField,\n type CmsEditorFieldsLayout,\n type CmsLayoutField,\n type CmsSeparatorLayoutField,\n type CmsTabLayoutField,\n type CmsAlertLayoutField\n} from \"~/types.js\";\nimport type {\n ILayoutBuilder,\n ILayoutNodeBuilder\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\nexport function mapCmsLayout(\n cmsLayout: CmsEditorFieldsLayout,\n layoutBuilder: ILayoutBuilder,\n idToFieldId: Map<string, string>\n): ILayoutNodeBuilder[] {\n const nodes: ILayoutNodeBuilder[] = [];\n\n for (const row of cmsLayout) {\n if (row.length === 0) {\n continue;\n }\n\n const firstCell = row[0];\n\n if (row.length === 1 && isLayoutField(firstCell)) {\n const layoutField = firstCell as CmsLayoutField;\n const node = mapLayoutField(layoutField, layoutBuilder, idToFieldId);\n if (node) {\n nodes.push(node);\n }\n continue;\n }\n\n const fieldIds: string[] = [];\n for (const cell of row) {\n if (typeof cell === \"string\") {\n const fieldId = idToFieldId.get(cell);\n if (fieldId) {\n fieldIds.push(fieldId);\n }\n }\n }\n\n if (fieldIds.length > 0) {\n nodes.push(layoutBuilder.row(...fieldIds));\n }\n }\n\n return nodes;\n}\n\nfunction mapLayoutField(\n field: CmsLayoutField,\n layoutBuilder: ILayoutBuilder,\n idToFieldId: Map<string, string>\n): ILayoutNodeBuilder | null {\n switch (field.type) {\n case \"separator\":\n return mapSeparator(field as CmsSeparatorLayoutField, layoutBuilder);\n\n case \"tabs\":\n return mapTabs(field as CmsTabLayoutField, layoutBuilder, idToFieldId);\n\n case \"alert\":\n return mapAlert(field as CmsAlertLayoutField, layoutBuilder);\n\n default:\n return null;\n }\n}\n\nfunction mapSeparator(\n field: CmsSeparatorLayoutField,\n layoutBuilder: ILayoutBuilder\n): ILayoutNodeBuilder {\n const builder = layoutBuilder.separator();\n if (field.label) {\n builder.title(field.label);\n }\n if (field.description) {\n builder.description(field.description);\n }\n if (field.rules) {\n builder.rules(\n field.rules.map(r => ({\n type: r.type,\n target: r.target,\n operator: r.operator,\n value: r.value ?? null,\n action: r.action as \"hide\" | \"disable\"\n }))\n );\n }\n return builder;\n}\n\nfunction mapTabs(\n field: CmsTabLayoutField,\n layoutBuilder: ILayoutBuilder,\n idToFieldId: Map<string, string>\n): ILayoutNodeBuilder {\n const tabsBuilder = layoutBuilder.tabs(field.id);\n\n for (const tab of field.tabs) {\n tabsBuilder.tab(tab.id, t => {\n t.label(tab.label);\n if (tab.icon) {\n t.icon({ type: \"icon\", name: tab.icon });\n }\n t.layout(l => mapCmsLayout(tab.layout, l, idToFieldId));\n if (tab.rules) {\n t.rules(\n tab.rules.map(r => ({\n type: r.type,\n target: r.target,\n operator: r.operator,\n value: r.value ?? null,\n action: r.action as \"hide\" | \"disable\"\n }))\n );\n }\n });\n }\n\n if (field.rules) {\n tabsBuilder.rules(\n field.rules.map(r => ({\n type: r.type,\n target: r.target,\n operator: r.operator,\n value: r.value ?? null,\n action: r.action as \"hide\" | \"disable\"\n }))\n );\n }\n\n return tabsBuilder;\n}\n\nfunction mapAlert(field: CmsAlertLayoutField, layoutBuilder: ILayoutBuilder): ILayoutNodeBuilder {\n const builder = layoutBuilder.alert();\n if (field.label) {\n builder.message(field.label);\n }\n if (field.alertType) {\n builder.alertType(field.alertType);\n }\n if (field.rules) {\n builder.rules(\n field.rules.map(r => ({\n type: r.type,\n target: r.target,\n operator: r.operator,\n value: r.value ?? null,\n action: r.action as \"hide\" | \"disable\"\n }))\n );\n }\n return builder;\n}\n"],"names":["mapCmsLayout","cmsLayout","layoutBuilder","idToFieldId","nodes","row","firstCell","isLayoutField","layoutField","node","mapLayoutField","fieldIds","cell","fieldId","field","mapSeparator","mapTabs","mapAlert","builder","r","tabsBuilder","tab","t","l"],"mappings":"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"}
|
|
@@ -2,13 +2,11 @@ import { createFeature } from "@webiny/feature/admin";
|
|
|
2
2
|
import { CmsFormModelBuilder } from "./abstractions.js";
|
|
3
3
|
import { CmsFormModelBuilder as external_CmsFormModelBuilder_js_CmsFormModelBuilder } from "./CmsFormModelBuilder.js";
|
|
4
4
|
import { CmsRefFieldType } from "./CmsRefFieldType.js";
|
|
5
|
-
import { CmsAccessControlRuleEvaluator } from "./CmsAccessControlRuleEvaluator.js";
|
|
6
5
|
const CmsFormModelFeature = createFeature({
|
|
7
6
|
name: "CmsFormModel",
|
|
8
7
|
register (container) {
|
|
9
8
|
container.register(external_CmsFormModelBuilder_js_CmsFormModelBuilder).inSingletonScope();
|
|
10
9
|
container.register(CmsRefFieldType);
|
|
11
|
-
container.register(CmsAccessControlRuleEvaluator);
|
|
12
10
|
},
|
|
13
11
|
resolve (container) {
|
|
14
12
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/formModel/feature.js","sources":["../../../src/features/formModel/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/admin\";\nimport { CmsFormModelBuilder as CmsFormModelBuilderAbstraction } from \"./abstractions.js\";\nimport { CmsFormModelBuilder } from \"./CmsFormModelBuilder.js\";\nimport { CmsRefFieldType } from \"./CmsRefFieldType.js\";\
|
|
1
|
+
{"version":3,"file":"features/formModel/feature.js","sources":["../../../src/features/formModel/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/admin\";\nimport { CmsFormModelBuilder as CmsFormModelBuilderAbstraction } from \"./abstractions.js\";\nimport { CmsFormModelBuilder } from \"./CmsFormModelBuilder.js\";\nimport { CmsRefFieldType } from \"./CmsRefFieldType.js\";\n\nexport const CmsFormModelFeature = createFeature({\n name: \"CmsFormModel\",\n register(container) {\n container.register(CmsFormModelBuilder).inSingletonScope();\n container.register(CmsRefFieldType);\n },\n resolve(container) {\n return {\n builder: container.resolve(CmsFormModelBuilderAbstraction)\n };\n }\n});\n"],"names":["CmsFormModelFeature","createFeature","container","CmsFormModelBuilder","CmsRefFieldType","CmsFormModelBuilderAbstraction"],"mappings":";;;;AAKO,MAAMA,sBAAsBC,cAAc;IAC7C,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,qDAAqB,gBAAgB;QACxDD,UAAU,QAAQ,CAACE;IACvB;IACA,SAAQF,SAAS;QACb,OAAO;YACH,SAASA,UAAU,OAAO,CAACG;QAC/B;IACJ;AACJ"}
|
|
@@ -39,7 +39,7 @@ function applyFieldProps(builder, field, rendererMap) {
|
|
|
39
39
|
type: r.type,
|
|
40
40
|
target: r.target,
|
|
41
41
|
operator: r.operator,
|
|
42
|
-
value:
|
|
42
|
+
value: r.value ?? null,
|
|
43
43
|
action: r.action
|
|
44
44
|
})));
|
|
45
45
|
if (field.tags && field.tags.length > 0) builder.tags(field.tags);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/formModel/mappers/applyFieldProps.js","sources":["../../../../src/features/formModel/mappers/applyFieldProps.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { IFieldBuilder } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { mapCmsValidators, mapCmsListValidators } from \"../CmsValidationMapper.js\";\n\nexport function applyFieldProps(\n builder: IFieldBuilder,\n field: CmsModelField,\n rendererMap: Map<string, string>\n): IFieldBuilder {\n if (field.label) {\n builder.label(field.label);\n }\n if (field.help) {\n builder.help(String(field.help));\n }\n if (field.description) {\n builder.description(String(field.description));\n }\n if (field.note) {\n builder.note(String(field.note));\n }\n if (field.placeholder) {\n builder.placeholder(field.placeholder);\n }\n\n if (Array.isArray(field.tags)) {\n builder.tags(field.tags);\n }\n\n if (field.settings?.defaultValue != null) {\n builder.defaultValue(field.settings.defaultValue);\n }\n\n if (field.list) {\n builder.list();\n }\n\n if (field.disabled) {\n builder.disabled(true);\n }\n\n if (field.predefinedValues?.enabled && field.predefinedValues.values) {\n const optionsBuilder = builder as any;\n if (typeof optionsBuilder.options === \"function\") {\n optionsBuilder.options(\n field.predefinedValues.values.map(\n (v: { label: string; value: string; selected?: boolean }) => ({\n label: v.label,\n value: v.value\n })\n )\n );\n }\n }\n\n if (field.list) {\n const itemResult = mapCmsValidators(field.validation);\n const listResult = mapCmsListValidators(field.listValidation);\n\n if (itemResult.required || listResult.required) {\n builder.required(itemResult.requiredMessage || listResult.requiredMessage);\n }\n\n const itemSchema = itemResult.schema ? z.array(itemResult.schema) : null;\n const listSchema = listResult.schema;\n\n if (itemSchema && listSchema) {\n builder.schema(z.intersection(itemSchema, listSchema));\n } else if (itemSchema) {\n builder.schema(itemSchema);\n } else if (listSchema) {\n builder.schema(listSchema);\n }\n } else {\n const { required, requiredMessage, schema } = mapCmsValidators(field.validation);\n if (required) {\n builder.required(requiredMessage);\n }\n if (schema) {\n builder.schema(schema);\n }\n }\n\n if (field.renderer && typeof field.renderer === \"object\") {\n const mappedRenderer = rendererMap.get(field.renderer.name);\n if (mappedRenderer) {\n builder.renderer(mappedRenderer as any, field.renderer.settings);\n }\n }\n\n if (field.rules && field.rules.length > 0) {\n builder.rules(\n field.rules.map(r => ({\n type: r.type,\n target: r.target,\n operator: r.operator,\n value: r.value
|
|
1
|
+
{"version":3,"file":"features/formModel/mappers/applyFieldProps.js","sources":["../../../../src/features/formModel/mappers/applyFieldProps.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { IFieldBuilder } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModelField } from \"~/types.js\";\nimport { mapCmsValidators, mapCmsListValidators } from \"../CmsValidationMapper.js\";\n\nexport function applyFieldProps(\n builder: IFieldBuilder,\n field: CmsModelField,\n rendererMap: Map<string, string>\n): IFieldBuilder {\n if (field.label) {\n builder.label(field.label);\n }\n if (field.help) {\n builder.help(String(field.help));\n }\n if (field.description) {\n builder.description(String(field.description));\n }\n if (field.note) {\n builder.note(String(field.note));\n }\n if (field.placeholder) {\n builder.placeholder(field.placeholder);\n }\n\n if (Array.isArray(field.tags)) {\n builder.tags(field.tags);\n }\n\n if (field.settings?.defaultValue != null) {\n builder.defaultValue(field.settings.defaultValue);\n }\n\n if (field.list) {\n builder.list();\n }\n\n if (field.disabled) {\n builder.disabled(true);\n }\n\n if (field.predefinedValues?.enabled && field.predefinedValues.values) {\n const optionsBuilder = builder as any;\n if (typeof optionsBuilder.options === \"function\") {\n optionsBuilder.options(\n field.predefinedValues.values.map(\n (v: { label: string; value: string; selected?: boolean }) => ({\n label: v.label,\n value: v.value\n })\n )\n );\n }\n }\n\n if (field.list) {\n const itemResult = mapCmsValidators(field.validation);\n const listResult = mapCmsListValidators(field.listValidation);\n\n if (itemResult.required || listResult.required) {\n builder.required(itemResult.requiredMessage || listResult.requiredMessage);\n }\n\n const itemSchema = itemResult.schema ? z.array(itemResult.schema) : null;\n const listSchema = listResult.schema;\n\n if (itemSchema && listSchema) {\n builder.schema(z.intersection(itemSchema, listSchema));\n } else if (itemSchema) {\n builder.schema(itemSchema);\n } else if (listSchema) {\n builder.schema(listSchema);\n }\n } else {\n const { required, requiredMessage, schema } = mapCmsValidators(field.validation);\n if (required) {\n builder.required(requiredMessage);\n }\n if (schema) {\n builder.schema(schema);\n }\n }\n\n if (field.renderer && typeof field.renderer === \"object\") {\n const mappedRenderer = rendererMap.get(field.renderer.name);\n if (mappedRenderer) {\n builder.renderer(mappedRenderer as any, field.renderer.settings);\n }\n }\n\n if (field.rules && field.rules.length > 0) {\n builder.rules(\n field.rules.map(r => ({\n type: r.type,\n target: r.target,\n operator: r.operator,\n value: r.value ?? null,\n action: r.action as \"hide\" | \"disable\"\n }))\n );\n }\n\n if (field.tags && field.tags.length > 0) {\n builder.tags(field.tags);\n }\n\n return builder;\n}\n"],"names":["applyFieldProps","builder","field","rendererMap","String","Array","optionsBuilder","v","itemResult","mapCmsValidators","listResult","mapCmsListValidators","itemSchema","z","listSchema","required","requiredMessage","schema","mappedRenderer","r"],"mappings":";;AAKO,SAASA,gBACZC,OAAsB,EACtBC,KAAoB,EACpBC,WAAgC;IAEhC,IAAID,MAAM,KAAK,EACXD,QAAQ,KAAK,CAACC,MAAM,KAAK;IAE7B,IAAIA,MAAM,IAAI,EACVD,QAAQ,IAAI,CAACG,OAAOF,MAAM,IAAI;IAElC,IAAIA,MAAM,WAAW,EACjBD,QAAQ,WAAW,CAACG,OAAOF,MAAM,WAAW;IAEhD,IAAIA,MAAM,IAAI,EACVD,QAAQ,IAAI,CAACG,OAAOF,MAAM,IAAI;IAElC,IAAIA,MAAM,WAAW,EACjBD,QAAQ,WAAW,CAACC,MAAM,WAAW;IAGzC,IAAIG,MAAM,OAAO,CAACH,MAAM,IAAI,GACxBD,QAAQ,IAAI,CAACC,MAAM,IAAI;IAG3B,IAAIA,MAAM,QAAQ,EAAE,gBAAgB,MAChCD,QAAQ,YAAY,CAACC,MAAM,QAAQ,CAAC,YAAY;IAGpD,IAAIA,MAAM,IAAI,EACVD,QAAQ,IAAI;IAGhB,IAAIC,MAAM,QAAQ,EACdD,QAAQ,QAAQ,CAAC;IAGrB,IAAIC,MAAM,gBAAgB,EAAE,WAAWA,MAAM,gBAAgB,CAAC,MAAM,EAAE;QAClE,MAAMI,iBAAiBL;QACvB,IAAI,AAAkC,cAAlC,OAAOK,eAAe,OAAO,EAC7BA,eAAe,OAAO,CAClBJ,MAAM,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAC7B,CAACK,IAA6D;gBAC1D,OAAOA,EAAE,KAAK;gBACd,OAAOA,EAAE,KAAK;YAClB;IAIhB;IAEA,IAAIL,MAAM,IAAI,EAAE;QACZ,MAAMM,aAAaC,iBAAiBP,MAAM,UAAU;QACpD,MAAMQ,aAAaC,qBAAqBT,MAAM,cAAc;QAE5D,IAAIM,WAAW,QAAQ,IAAIE,WAAW,QAAQ,EAC1CT,QAAQ,QAAQ,CAACO,WAAW,eAAe,IAAIE,WAAW,eAAe;QAG7E,MAAME,aAAaJ,WAAW,MAAM,GAAGK,EAAE,KAAK,CAACL,WAAW,MAAM,IAAI;QACpE,MAAMM,aAAaJ,WAAW,MAAM;QAEpC,IAAIE,cAAcE,YACdb,QAAQ,MAAM,CAACY,EAAE,YAAY,CAACD,YAAYE;aACvC,IAAIF,YACPX,QAAQ,MAAM,CAACW;aACZ,IAAIE,YACPb,QAAQ,MAAM,CAACa;IAEvB,OAAO;QACH,MAAM,EAAEC,QAAQ,EAAEC,eAAe,EAAEC,MAAM,EAAE,GAAGR,iBAAiBP,MAAM,UAAU;QAC/E,IAAIa,UACAd,QAAQ,QAAQ,CAACe;QAErB,IAAIC,QACAhB,QAAQ,MAAM,CAACgB;IAEvB;IAEA,IAAIf,MAAM,QAAQ,IAAI,AAA0B,YAA1B,OAAOA,MAAM,QAAQ,EAAe;QACtD,MAAMgB,iBAAiBf,YAAY,GAAG,CAACD,MAAM,QAAQ,CAAC,IAAI;QAC1D,IAAIgB,gBACAjB,QAAQ,QAAQ,CAACiB,gBAAuBhB,MAAM,QAAQ,CAAC,QAAQ;IAEvE;IAEA,IAAIA,MAAM,KAAK,IAAIA,MAAM,KAAK,CAAC,MAAM,GAAG,GACpCD,QAAQ,KAAK,CACTC,MAAM,KAAK,CAAC,GAAG,CAACiB,CAAAA,IAAM;YAClB,MAAMA,EAAE,IAAI;YACZ,QAAQA,EAAE,MAAM;YAChB,UAAUA,EAAE,QAAQ;YACpB,OAAOA,EAAE,KAAK,IAAI;YAClB,QAAQA,EAAE,MAAM;QACpB;IAIR,IAAIjB,MAAM,IAAI,IAAIA,MAAM,IAAI,CAAC,MAAM,GAAG,GAClCD,QAAQ,IAAI,CAACC,MAAM,IAAI;IAG3B,OAAOD;AACX"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { Container } from "@webiny/di";
|
|
3
3
|
import { FormModelFeature } from "@webiny/app-admin/features/formModel/feature.js";
|
|
4
|
+
import { IdentityContextFeature } from "@webiny/app-admin/features/security/IdentityContext/feature.js";
|
|
4
5
|
import { FormModelFactory } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
5
6
|
import { applyFieldProps } from "./applyFieldProps.js";
|
|
6
7
|
const createField = (overrides)=>({
|
|
@@ -18,6 +19,7 @@ const createField = (overrides)=>({
|
|
|
18
19
|
});
|
|
19
20
|
const buildForm = (field)=>{
|
|
20
21
|
const container = new Container();
|
|
22
|
+
IdentityContextFeature.register(container);
|
|
21
23
|
FormModelFeature.register(container);
|
|
22
24
|
return container.resolve(FormModelFactory).create({
|
|
23
25
|
fields: (registry)=>({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/formModel/mappers/applyFieldProps.test.js","sources":["../../../../src/features/formModel/mappers/applyFieldProps.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { applyFieldProps } from \"./applyFieldProps.js\";\nimport type { CmsModelField } from \"~/types.js\";\n\nconst createField = (overrides: Partial<CmsModelField>): CmsModelField =>\n ({\n id: \"externalId\",\n fieldId: \"externalId\",\n storageId: \"text@externalId\",\n type: \"text\",\n label: \"External ID\",\n renderer: { name: \"text-input\" },\n validation: [],\n listValidation: [],\n ...overrides\n }) as CmsModelField;\n\n/**\n * Builds a one-field form the way CmsFormModelBuilder does, so we assert on the\n * field the entry form actually renders rather than on the builder in isolation.\n */\nconst buildForm = (field: CmsModelField) => {\n const container = new Container();\n FormModelFeature.register(container);\n\n return container.resolve(FormModelFactory).create({\n fields: registry => ({\n [field.fieldId]: applyFieldProps(registry.text(), field, new Map())\n })\n });\n};\n\ndescribe(\"applyFieldProps disabled\", () => {\n it(\"disables the form field when the model field is disabled\", () => {\n const form = buildForm(createField({ disabled: true }));\n\n expect(form.field(\"externalId\").disabled).toBe(true);\n });\n\n it(\"leaves the field editable when disabled is false or absent\", () => {\n expect(buildForm(createField({ disabled: false })).field(\"externalId\").disabled).toBe(\n false\n );\n expect(buildForm(createField({})).field(\"externalId\").disabled).toBe(false);\n });\n\n it(\"keeps the field visible\", () => {\n const form = buildForm(createField({ disabled: true }));\n\n expect(form.field(\"externalId\").visible).toBe(true);\n });\n\n it(\"does not stop the field from holding a value\", () => {\n const form = buildForm(createField({ disabled: true }));\n form.field(\"externalId\").setValue(\"abc-123\");\n\n expect(form.field(\"externalId\").getValue()).toBe(\"abc-123\");\n expect(form.field(\"externalId\").disabled).toBe(true);\n });\n});\n"],"names":["createField","overrides","buildForm","field","container","Container","FormModelFeature","FormModelFactory","registry","applyFieldProps","Map","describe","it","form","expect"],"mappings":"
|
|
1
|
+
{"version":3,"file":"features/formModel/mappers/applyFieldProps.test.js","sources":["../../../../src/features/formModel/mappers/applyFieldProps.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { IdentityContextFeature } from \"@webiny/app-admin/features/security/IdentityContext/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { applyFieldProps } from \"./applyFieldProps.js\";\nimport type { CmsModelField } from \"~/types.js\";\n\nconst createField = (overrides: Partial<CmsModelField>): CmsModelField =>\n ({\n id: \"externalId\",\n fieldId: \"externalId\",\n storageId: \"text@externalId\",\n type: \"text\",\n label: \"External ID\",\n renderer: { name: \"text-input\" },\n validation: [],\n listValidation: [],\n ...overrides\n }) as CmsModelField;\n\n/**\n * Builds a one-field form the way CmsFormModelBuilder does, so we assert on the\n * field the entry form actually renders rather than on the builder in isolation.\n */\nconst buildForm = (field: CmsModelField) => {\n const container = new Container();\n IdentityContextFeature.register(container);\n FormModelFeature.register(container);\n\n return container.resolve(FormModelFactory).create({\n fields: registry => ({\n [field.fieldId]: applyFieldProps(registry.text(), field, new Map())\n })\n });\n};\n\ndescribe(\"applyFieldProps disabled\", () => {\n it(\"disables the form field when the model field is disabled\", () => {\n const form = buildForm(createField({ disabled: true }));\n\n expect(form.field(\"externalId\").disabled).toBe(true);\n });\n\n it(\"leaves the field editable when disabled is false or absent\", () => {\n expect(buildForm(createField({ disabled: false })).field(\"externalId\").disabled).toBe(\n false\n );\n expect(buildForm(createField({})).field(\"externalId\").disabled).toBe(false);\n });\n\n it(\"keeps the field visible\", () => {\n const form = buildForm(createField({ disabled: true }));\n\n expect(form.field(\"externalId\").visible).toBe(true);\n });\n\n it(\"does not stop the field from holding a value\", () => {\n const form = buildForm(createField({ disabled: true }));\n form.field(\"externalId\").setValue(\"abc-123\");\n\n expect(form.field(\"externalId\").getValue()).toBe(\"abc-123\");\n expect(form.field(\"externalId\").disabled).toBe(true);\n });\n});\n"],"names":["createField","overrides","buildForm","field","container","Container","IdentityContextFeature","FormModelFeature","FormModelFactory","registry","applyFieldProps","Map","describe","it","form","expect"],"mappings":";;;;;;AAQA,MAAMA,cAAc,CAACC,YAChB;QACG,IAAI;QACJ,SAAS;QACT,WAAW;QACX,MAAM;QACN,OAAO;QACP,UAAU;YAAE,MAAM;QAAa;QAC/B,YAAY,EAAE;QACd,gBAAgB,EAAE;QAClB,GAAGA,SAAS;IAChB;AAMJ,MAAMC,YAAY,CAACC;IACf,MAAMC,YAAY,IAAIC;IACtBC,uBAAuB,QAAQ,CAACF;IAChCG,iBAAiB,QAAQ,CAACH;IAE1B,OAAOA,UAAU,OAAO,CAACI,kBAAkB,MAAM,CAAC;QAC9C,QAAQC,CAAAA,WAAa;gBACjB,CAACN,MAAM,OAAO,CAAC,EAAEO,gBAAgBD,SAAS,IAAI,IAAIN,OAAO,IAAIQ;YACjE;IACJ;AACJ;AAEAC,SAAS,4BAA4B;IACjCC,GAAG,4DAA4D;QAC3D,MAAMC,OAAOZ,UAAUF,YAAY;YAAE,UAAU;QAAK;QAEpDe,OAAOD,KAAK,KAAK,CAAC,cAAc,QAAQ,EAAE,IAAI,CAAC;IACnD;IAEAD,GAAG,8DAA8D;QAC7DE,OAAOb,UAAUF,YAAY;YAAE,UAAU;QAAM,IAAI,KAAK,CAAC,cAAc,QAAQ,EAAE,IAAI,CACjF;QAEJe,OAAOb,UAAUF,YAAY,CAAC,IAAI,KAAK,CAAC,cAAc,QAAQ,EAAE,IAAI,CAAC;IACzE;IAEAa,GAAG,2BAA2B;QAC1B,MAAMC,OAAOZ,UAAUF,YAAY;YAAE,UAAU;QAAK;QAEpDe,OAAOD,KAAK,KAAK,CAAC,cAAc,OAAO,EAAE,IAAI,CAAC;IAClD;IAEAD,GAAG,gDAAgD;QAC/C,MAAMC,OAAOZ,UAAUF,YAAY;YAAE,UAAU;QAAK;QACpDc,KAAK,KAAK,CAAC,cAAc,QAAQ,CAAC;QAElCC,OAAOD,KAAK,KAAK,CAAC,cAAc,QAAQ,IAAI,IAAI,CAAC;QACjDC,OAAOD,KAAK,KAAK,CAAC,cAAc,QAAQ,EAAE,IAAI,CAAC;IACnD;AACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/app-headless-cms",
|
|
3
|
-
"version": "6.6.0-alpha.
|
|
3
|
+
"version": "6.6.0-alpha.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -28,24 +28,24 @@
|
|
|
28
28
|
"@fortawesome/react-fontawesome": "3.5.0",
|
|
29
29
|
"@lexical/utils": "0.49.0",
|
|
30
30
|
"@types/react": "18.3.31",
|
|
31
|
-
"@webiny/admin-ui": "6.6.0-alpha.
|
|
32
|
-
"@webiny/app": "6.6.0-alpha.
|
|
33
|
-
"@webiny/app-aco": "6.6.0-alpha.
|
|
34
|
-
"@webiny/app-admin": "6.6.0-alpha.
|
|
35
|
-
"@webiny/app-graphql-playground": "6.6.0-alpha.
|
|
36
|
-
"@webiny/app-headless-cms-common": "6.6.0-alpha.
|
|
37
|
-
"@webiny/cms-sdk": "6.6.0-alpha.
|
|
31
|
+
"@webiny/admin-ui": "6.6.0-alpha.9",
|
|
32
|
+
"@webiny/app": "6.6.0-alpha.9",
|
|
33
|
+
"@webiny/app-aco": "6.6.0-alpha.9",
|
|
34
|
+
"@webiny/app-admin": "6.6.0-alpha.9",
|
|
35
|
+
"@webiny/app-graphql-playground": "6.6.0-alpha.9",
|
|
36
|
+
"@webiny/app-headless-cms-common": "6.6.0-alpha.9",
|
|
37
|
+
"@webiny/cms-sdk": "6.6.0-alpha.9",
|
|
38
38
|
"@webiny/di": "1.1.0",
|
|
39
|
-
"@webiny/feature": "6.6.0-alpha.
|
|
40
|
-
"@webiny/form": "6.6.0-alpha.
|
|
41
|
-
"@webiny/icons": "6.6.0-alpha.
|
|
42
|
-
"@webiny/lexical-editor": "6.6.0-alpha.
|
|
43
|
-
"@webiny/lexical-nodes": "6.6.0-alpha.
|
|
44
|
-
"@webiny/plugins": "6.6.0-alpha.
|
|
45
|
-
"@webiny/react-composition": "6.6.0-alpha.
|
|
46
|
-
"@webiny/react-properties": "6.6.0-alpha.
|
|
47
|
-
"@webiny/utils": "6.6.0-alpha.
|
|
48
|
-
"@webiny/validation": "6.6.0-alpha.
|
|
39
|
+
"@webiny/feature": "6.6.0-alpha.9",
|
|
40
|
+
"@webiny/form": "6.6.0-alpha.9",
|
|
41
|
+
"@webiny/icons": "6.6.0-alpha.9",
|
|
42
|
+
"@webiny/lexical-editor": "6.6.0-alpha.9",
|
|
43
|
+
"@webiny/lexical-nodes": "6.6.0-alpha.9",
|
|
44
|
+
"@webiny/plugins": "6.6.0-alpha.9",
|
|
45
|
+
"@webiny/react-composition": "6.6.0-alpha.9",
|
|
46
|
+
"@webiny/react-properties": "6.6.0-alpha.9",
|
|
47
|
+
"@webiny/utils": "6.6.0-alpha.9",
|
|
48
|
+
"@webiny/validation": "6.6.0-alpha.9",
|
|
49
49
|
"dot-prop-immutable": "2.1.1",
|
|
50
50
|
"graphql": "16.14.2",
|
|
51
51
|
"graphql-tag": "2.12.7",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"zod": "4.4.3"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@webiny/build-tools": "6.6.0-alpha.
|
|
64
|
+
"@webiny/build-tools": "6.6.0-alpha.9",
|
|
65
65
|
"rimraf": "6.1.3",
|
|
66
66
|
"typescript": "7.0.2",
|
|
67
67
|
"vitest": "4.1.11"
|
|
@@ -17,6 +17,7 @@ declare class CloneContentModelPresenterImpl implements ICloneContentModelPresen
|
|
|
17
17
|
private sourceModel;
|
|
18
18
|
constructor(formModelFactory: FormModelFactory.Interface, listModelGroupsUseCase: ListModelGroupsUseCase.Interface, cloneModelUseCase: CloneModelUseCase.Interface, groupsCache: ModelGroupsCache.Interface, modelsCache: ModelsCache.Interface);
|
|
19
19
|
get vm(): ICloneContentModelPresenterViewModel;
|
|
20
|
+
private get groupOptions();
|
|
20
21
|
init(sourceModel: CmsModel): Promise<void>;
|
|
21
22
|
save(): Promise<CmsModel | null>;
|
|
22
23
|
reset(): void;
|
|
@@ -26,18 +26,20 @@ class CloneContentModelPresenterImpl {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
get vm() {
|
|
29
|
-
const groups = this.groupsCache.getItems().map((g)=>({
|
|
30
|
-
value: g.slug,
|
|
31
|
-
label: g.name
|
|
32
|
-
}));
|
|
33
29
|
return {
|
|
34
30
|
loading: this.loading,
|
|
35
31
|
saving: this.saving,
|
|
36
|
-
groups,
|
|
32
|
+
groups: this.groupOptions,
|
|
37
33
|
models: this.modelsCache.getItems(),
|
|
38
34
|
form: this.form.vm
|
|
39
35
|
};
|
|
40
36
|
}
|
|
37
|
+
get groupOptions() {
|
|
38
|
+
return this.groupsCache.getItems().map((group)=>({
|
|
39
|
+
value: group.slug,
|
|
40
|
+
label: group.name
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
41
43
|
async init(sourceModel) {
|
|
42
44
|
this.sourceModel = sourceModel;
|
|
43
45
|
try {
|
|
@@ -91,7 +93,7 @@ class CloneContentModelPresenterImpl {
|
|
|
91
93
|
name: fields.text().label("Name").required("Name is required."),
|
|
92
94
|
singularApiName: fields.text().label("Singular API Name").required("Singular API Name is required."),
|
|
93
95
|
pluralApiName: fields.text().label("Plural API Name").required("Plural API Name is required."),
|
|
94
|
-
group: fields.text().label("Content model group").required("Group is required."),
|
|
96
|
+
group: fields.text().label("Content model group").required("Group is required.").options(()=>this.groupOptions),
|
|
95
97
|
icon: fields.text().label("Icon").renderer("cmsIconPicker"),
|
|
96
98
|
description: fields.text().label("Description").renderer("textarea")
|
|
97
99
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/cloneContentModel/CloneContentModelPresenter.js","sources":["../../../src/presentation/cloneContentModel/CloneContentModelPresenter.ts"],"sourcesContent":["import { makeAutoObservable, runInAction, computed } from \"mobx\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { IFormModel } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModel } from \"~/types.js\";\nimport { ListModelGroupsUseCase } from \"~/features/modelGroup/listModelGroups/abstractions.js\";\nimport { CloneModelUseCase } from \"~/features/model/cloneModel/abstractions.js\";\nimport { ModelGroupsCache } from \"~/features/modelGroup/abstractions.js\";\nimport { ModelsCache } from \"~/features/model/abstractions.js\";\nimport {\n CloneContentModelPresenter as Abstraction,\n type ICloneContentModelPresenter,\n type ICloneContentModelPresenterViewModel\n} from \"./abstractions.js\";\n\nclass CloneContentModelPresenterImpl implements ICloneContentModelPresenter {\n private loading = true;\n private saving = false;\n private form: IFormModel;\n private sourceModel: CmsModel | null = null;\n\n constructor(\n private formModelFactory: FormModelFactory.Interface,\n private listModelGroupsUseCase: ListModelGroupsUseCase.Interface,\n private cloneModelUseCase: CloneModelUseCase.Interface,\n private groupsCache: ModelGroupsCache.Interface,\n private modelsCache: ModelsCache.Interface\n ) {\n this.form = this.buildForm();\n makeAutoObservable<\n CloneContentModelPresenterImpl,\n | \"formModelFactory\"\n | \"listModelGroupsUseCase\"\n | \"cloneModelUseCase\"\n | \"groupsCache\"\n | \"modelsCache\"\n >(this, {\n formModelFactory: false,\n listModelGroupsUseCase: false,\n cloneModelUseCase: false,\n groupsCache: false,\n modelsCache: false,\n vm: computed\n });\n }\n\n get vm(): ICloneContentModelPresenterViewModel {\n
|
|
1
|
+
{"version":3,"file":"presentation/cloneContentModel/CloneContentModelPresenter.js","sources":["../../../src/presentation/cloneContentModel/CloneContentModelPresenter.ts"],"sourcesContent":["import { makeAutoObservable, runInAction, computed } from \"mobx\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { IFormModel } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModel } from \"~/types.js\";\nimport { ListModelGroupsUseCase } from \"~/features/modelGroup/listModelGroups/abstractions.js\";\nimport { CloneModelUseCase } from \"~/features/model/cloneModel/abstractions.js\";\nimport { ModelGroupsCache } from \"~/features/modelGroup/abstractions.js\";\nimport { ModelsCache } from \"~/features/model/abstractions.js\";\nimport {\n CloneContentModelPresenter as Abstraction,\n type ICloneContentModelPresenter,\n type ICloneContentModelPresenterViewModel\n} from \"./abstractions.js\";\n\nclass CloneContentModelPresenterImpl implements ICloneContentModelPresenter {\n private loading = true;\n private saving = false;\n private form: IFormModel;\n private sourceModel: CmsModel | null = null;\n\n constructor(\n private formModelFactory: FormModelFactory.Interface,\n private listModelGroupsUseCase: ListModelGroupsUseCase.Interface,\n private cloneModelUseCase: CloneModelUseCase.Interface,\n private groupsCache: ModelGroupsCache.Interface,\n private modelsCache: ModelsCache.Interface\n ) {\n this.form = this.buildForm();\n makeAutoObservable<\n CloneContentModelPresenterImpl,\n | \"formModelFactory\"\n | \"listModelGroupsUseCase\"\n | \"cloneModelUseCase\"\n | \"groupsCache\"\n | \"modelsCache\"\n >(this, {\n formModelFactory: false,\n listModelGroupsUseCase: false,\n cloneModelUseCase: false,\n groupsCache: false,\n modelsCache: false,\n vm: computed\n });\n }\n\n get vm(): ICloneContentModelPresenterViewModel {\n return {\n loading: this.loading,\n saving: this.saving,\n groups: this.groupOptions,\n models: this.modelsCache.getItems(),\n form: this.form.vm\n };\n }\n\n private get groupOptions() {\n return this.groupsCache.getItems().map(group => ({\n value: group.slug,\n label: group.name\n }));\n }\n\n async init(sourceModel: CmsModel): Promise<void> {\n this.sourceModel = sourceModel;\n\n try {\n await this.listModelGroupsUseCase.execute();\n } finally {\n runInAction(() => {\n this.loading = false;\n this.form = this.buildForm();\n this.form.setData({\n name: sourceModel.name,\n group: sourceModel.group\n });\n });\n }\n }\n\n async save(): Promise<CmsModel | null> {\n if (!this.sourceModel) {\n return null;\n }\n\n const data = await this.form.submit<Record<string, any>>();\n if (!data) {\n return null;\n }\n\n runInAction(() => {\n this.saving = true;\n });\n\n try {\n const model = await this.cloneModelUseCase.execute({\n modelId: this.sourceModel.modelId,\n data: {\n name: data.name as string,\n singularApiName: data.singularApiName as string | undefined,\n pluralApiName: data.pluralApiName as string | undefined,\n group: data.group as string | undefined,\n icon: data.icon as string | undefined,\n description: data.description as string | undefined\n }\n });\n\n return model;\n } catch {\n return null;\n } finally {\n runInAction(() => {\n this.saving = false;\n });\n }\n }\n\n reset(): void {\n this.sourceModel = null;\n this.form = this.buildForm();\n }\n\n private buildForm(): IFormModel {\n return this.formModelFactory.create({\n fields: fields => ({\n name: fields.text().label(\"Name\").required(\"Name is required.\"),\n singularApiName: fields\n .text()\n .label(\"Singular API Name\")\n .required(\"Singular API Name is required.\"),\n pluralApiName: fields\n .text()\n .label(\"Plural API Name\")\n .required(\"Plural API Name is required.\"),\n group: fields\n .text()\n .label(\"Content model group\")\n .required(\"Group is required.\")\n /*\n * Options turn the text field into a select. The groups arrive after the form\n * is built, so they have to be read through a callback.\n */\n .options(() => this.groupOptions),\n icon: fields.text().label(\"Icon\").renderer(\"cmsIconPicker\"),\n description: fields.text().label(\"Description\").renderer(\"textarea\")\n }),\n layout: layout => [\n layout.row(\"name\"),\n layout.row(\"singularApiName\"),\n layout.row(\"pluralApiName\"),\n layout.row(\"group\"),\n layout.row(\"icon\"),\n layout.row(\"description\")\n ]\n });\n }\n}\n\nexport const CloneContentModelPresenter = Abstraction.createImplementation({\n implementation: CloneContentModelPresenterImpl,\n dependencies: [\n FormModelFactory,\n ListModelGroupsUseCase,\n CloneModelUseCase,\n ModelGroupsCache,\n ModelsCache\n ]\n});\n"],"names":["CloneContentModelPresenterImpl","formModelFactory","listModelGroupsUseCase","cloneModelUseCase","groupsCache","modelsCache","makeAutoObservable","computed","group","sourceModel","runInAction","data","model","fields","layout","CloneContentModelPresenter","Abstraction","FormModelFactory","ListModelGroupsUseCase","CloneModelUseCase","ModelGroupsCache","ModelsCache"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { Container } from "@webiny/di";
|
|
3
3
|
import { FormModelFeature } from "@webiny/app-admin/features/formModel/feature.js";
|
|
4
|
+
import { IdentityContextFeature } from "@webiny/app-admin/features/security/IdentityContext/feature.js";
|
|
4
5
|
import { FormModelFactory } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
5
6
|
import { CmsFormModelBuilder } from "../../../features/formModel/abstractions.js";
|
|
6
7
|
import { CmsFormModelFeature } from "../../../features/formModel/feature.js";
|
|
@@ -189,6 +190,7 @@ const model = {
|
|
|
189
190
|
};
|
|
190
191
|
function createCmsForm() {
|
|
191
192
|
const container = new Container();
|
|
193
|
+
IdentityContextFeature.register(container);
|
|
192
194
|
FormModelFeature.register(container);
|
|
193
195
|
CmsFormModelFeature.register(container);
|
|
194
196
|
const builder = container.resolve(CmsFormModelBuilder);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/contentEntries/form/getFieldBuilders.test.js","sources":["../../../../src/presentation/contentEntries/form/getFieldBuilders.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsFormModelFeature } from \"~/features/formModel/feature.js\";\n\nconst model = {\n modelId: \"test\",\n fields: [\n {\n id: \"textSingle\",\n fieldId: \"textSingle\",\n type: \"text\",\n label: \"Text\",\n tags: [],\n list: false,\n renderer: { name: \"text-input\", settings: {} },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n },\n {\n id: \"objectMultiple\",\n fieldId: \"objectMultiple\",\n type: \"object\",\n label: \"Object Multiple\",\n tags: [],\n list: true,\n renderer: { name: \"objects-accordion\", settings: {} },\n validation: [],\n listValidation: [],\n predefinedValues: { enabled: false, values: [] },\n settings: {\n fields: [\n {\n id: \"uuid\",\n fieldId: \"uuid\",\n type: \"text\",\n label: \"UUID\",\n tags: [\"uuid\"],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n },\n {\n id: \"name\",\n fieldId: \"name\",\n type: \"text\",\n label: \"Name\",\n tags: [],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n }\n ],\n layout: [[\"uuid\"], [\"name\"]]\n }\n },\n {\n id: \"dynamicZoneList\",\n fieldId: \"dynamicZoneList\",\n type: \"dynamicZone\",\n label: \"DZ List\",\n tags: [],\n list: true,\n renderer: { name: \"dynamicZone\", settings: {} },\n validation: [],\n listValidation: [],\n predefinedValues: { enabled: false, values: [] },\n settings: {\n templates: [\n {\n id: \"textBlock\",\n name: \"Text Block\",\n gqlTypeName: \"TextBlock\",\n fields: [\n {\n id: \"uuid\",\n fieldId: \"uuid\",\n type: \"text\",\n label: \"UUID\",\n tags: [\"uuid\"],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n },\n {\n id: \"title\",\n fieldId: \"title\",\n type: \"text\",\n label: \"Title\",\n tags: [],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n }\n ],\n layout: [[\"uuid\"], [\"title\"]],\n validation: []\n }\n ]\n }\n }\n ],\n layout: [[\"textSingle\"], [\"objectMultiple\"], [\"dynamicZoneList\"]]\n} as any;\n\nfunction createCmsForm() {\n const container = new Container();\n FormModelFeature.register(container);\n CmsFormModelFeature.register(container);\n\n const builder = container.resolve(CmsFormModelBuilder);\n const config = builder.build(model);\n const factory = container.resolve(FormModelFactory);\n return factory.create(config);\n}\n\ndescribe(\"getFieldBuilders with CMS model\", () => {\n it(\"traverse should visit all builders including nested\", () => {\n const form = createCmsForm();\n const visited: Array<{ fieldType: string; tags: string[] }> = [];\n form.traverse(builder => {\n visited.push({ fieldType: builder.getType(), tags: builder.getTags() });\n });\n // top-level: textSingle, objectMultiple, dynamicZoneList = 3\n // objectMultiple children: uuid, name = 2\n // dynamicZoneList template \"textBlock\" children: uuid, title = 2\n // Total = 7\n expect(visited.length).toBe(7);\n });\n\n it(\"traverse should find builders tagged 'uuid'\", () => {\n const form = createCmsForm();\n const uuidBuilders: any[] = [];\n form.traverse(builder => {\n if (builder.getTags().includes(\"uuid\")) {\n uuidBuilders.push(builder);\n }\n });\n // objectMultiple.uuid + dynamicZoneList.textBlock.uuid = 2\n expect(uuidBuilders.length).toBe(2);\n });\n\n it(\"traverse should allow modifying builders with defaultValue and cloneValue\", () => {\n const form = createCmsForm();\n let count = 0;\n form.traverse(builder => {\n if (builder.getTags().includes(\"uuid\")) {\n builder.defaultValue(() => String(Date.now()));\n builder.cloneValue(() => String(Date.now()));\n count++;\n }\n });\n expect(count).toBe(2);\n });\n\n it(\"getName should return the field name for all builders\", () => {\n const form = createCmsForm();\n const names: string[] = [];\n form.traverse(builder => {\n names.push(builder.getName());\n });\n expect(names).toContain(\"textSingle\");\n expect(names).toContain(\"objectMultiple\");\n expect(names).toContain(\"dynamicZoneList\");\n expect(names).toContain(\"uuid\");\n expect(names).toContain(\"name\");\n expect(names).toContain(\"title\");\n });\n\n it(\"getType should return the field type\", () => {\n const form = createCmsForm();\n const types: Record<string, string> = {};\n form.traverse(builder => {\n types[builder.getName()] = builder.getType();\n });\n expect(types[\"textSingle\"]).toBe(\"text\");\n expect(types[\"objectMultiple\"]).toBe(\"object\");\n expect(types[\"uuid\"]).toBe(\"text\");\n });\n\n it(\"should find builders by name using traverse\", () => {\n const form = createCmsForm();\n const matched: string[] = [];\n form.traverse(builder => {\n if (builder.getName() === \"uuid\") {\n matched.push(builder.getName());\n }\n });\n expect(matched.length).toBe(2);\n });\n\n it(\"should find builders by type using traverse\", () => {\n const form = createCmsForm();\n const textBuilders: string[] = [];\n form.traverse(builder => {\n if (builder.getType() === \"text\") {\n textBuilders.push(builder.getName());\n }\n });\n // textSingle + objectMultiple.uuid + objectMultiple.name + dz.textBlock.uuid + dz.textBlock.title = 5\n expect(textBuilders.length).toBe(5);\n });\n\n it(\"should combine getName, getType, and getTags for precise filtering\", () => {\n const form = createCmsForm();\n const matched: string[] = [];\n form.traverse(builder => {\n if (\n builder.getType() === \"text\" &&\n builder.getName() === \"uuid\" &&\n builder.getTags().includes(\"uuid\")\n ) {\n matched.push(builder.getName());\n }\n });\n expect(matched.length).toBe(2);\n });\n});\n"],"names":["model","createCmsForm","container","Container","FormModelFeature","CmsFormModelFeature","builder","CmsFormModelBuilder","config","factory","FormModelFactory","describe","it","form","visited","expect","uuidBuilders","count","String","Date","names","types","matched","textBuilders"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"presentation/contentEntries/form/getFieldBuilders.test.js","sources":["../../../../src/presentation/contentEntries/form/getFieldBuilders.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { IdentityContextFeature } from \"@webiny/app-admin/features/security/IdentityContext/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { CmsFormModelBuilder } from \"~/features/formModel/abstractions.js\";\nimport { CmsFormModelFeature } from \"~/features/formModel/feature.js\";\n\nconst model = {\n modelId: \"test\",\n fields: [\n {\n id: \"textSingle\",\n fieldId: \"textSingle\",\n type: \"text\",\n label: \"Text\",\n tags: [],\n list: false,\n renderer: { name: \"text-input\", settings: {} },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n },\n {\n id: \"objectMultiple\",\n fieldId: \"objectMultiple\",\n type: \"object\",\n label: \"Object Multiple\",\n tags: [],\n list: true,\n renderer: { name: \"objects-accordion\", settings: {} },\n validation: [],\n listValidation: [],\n predefinedValues: { enabled: false, values: [] },\n settings: {\n fields: [\n {\n id: \"uuid\",\n fieldId: \"uuid\",\n type: \"text\",\n label: \"UUID\",\n tags: [\"uuid\"],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n },\n {\n id: \"name\",\n fieldId: \"name\",\n type: \"text\",\n label: \"Name\",\n tags: [],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n }\n ],\n layout: [[\"uuid\"], [\"name\"]]\n }\n },\n {\n id: \"dynamicZoneList\",\n fieldId: \"dynamicZoneList\",\n type: \"dynamicZone\",\n label: \"DZ List\",\n tags: [],\n list: true,\n renderer: { name: \"dynamicZone\", settings: {} },\n validation: [],\n listValidation: [],\n predefinedValues: { enabled: false, values: [] },\n settings: {\n templates: [\n {\n id: \"textBlock\",\n name: \"Text Block\",\n gqlTypeName: \"TextBlock\",\n fields: [\n {\n id: \"uuid\",\n fieldId: \"uuid\",\n type: \"text\",\n label: \"UUID\",\n tags: [\"uuid\"],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n },\n {\n id: \"title\",\n fieldId: \"title\",\n type: \"text\",\n label: \"Title\",\n tags: [],\n list: false,\n renderer: { name: \"text-input\", settings: null },\n validation: [],\n listValidation: [],\n settings: {},\n predefinedValues: { enabled: false, values: [] }\n }\n ],\n layout: [[\"uuid\"], [\"title\"]],\n validation: []\n }\n ]\n }\n }\n ],\n layout: [[\"textSingle\"], [\"objectMultiple\"], [\"dynamicZoneList\"]]\n} as any;\n\nfunction createCmsForm() {\n const container = new Container();\n IdentityContextFeature.register(container);\n FormModelFeature.register(container);\n CmsFormModelFeature.register(container);\n\n const builder = container.resolve(CmsFormModelBuilder);\n const config = builder.build(model);\n const factory = container.resolve(FormModelFactory);\n return factory.create(config);\n}\n\ndescribe(\"getFieldBuilders with CMS model\", () => {\n it(\"traverse should visit all builders including nested\", () => {\n const form = createCmsForm();\n const visited: Array<{ fieldType: string; tags: string[] }> = [];\n form.traverse(builder => {\n visited.push({ fieldType: builder.getType(), tags: builder.getTags() });\n });\n // top-level: textSingle, objectMultiple, dynamicZoneList = 3\n // objectMultiple children: uuid, name = 2\n // dynamicZoneList template \"textBlock\" children: uuid, title = 2\n // Total = 7\n expect(visited.length).toBe(7);\n });\n\n it(\"traverse should find builders tagged 'uuid'\", () => {\n const form = createCmsForm();\n const uuidBuilders: any[] = [];\n form.traverse(builder => {\n if (builder.getTags().includes(\"uuid\")) {\n uuidBuilders.push(builder);\n }\n });\n // objectMultiple.uuid + dynamicZoneList.textBlock.uuid = 2\n expect(uuidBuilders.length).toBe(2);\n });\n\n it(\"traverse should allow modifying builders with defaultValue and cloneValue\", () => {\n const form = createCmsForm();\n let count = 0;\n form.traverse(builder => {\n if (builder.getTags().includes(\"uuid\")) {\n builder.defaultValue(() => String(Date.now()));\n builder.cloneValue(() => String(Date.now()));\n count++;\n }\n });\n expect(count).toBe(2);\n });\n\n it(\"getName should return the field name for all builders\", () => {\n const form = createCmsForm();\n const names: string[] = [];\n form.traverse(builder => {\n names.push(builder.getName());\n });\n expect(names).toContain(\"textSingle\");\n expect(names).toContain(\"objectMultiple\");\n expect(names).toContain(\"dynamicZoneList\");\n expect(names).toContain(\"uuid\");\n expect(names).toContain(\"name\");\n expect(names).toContain(\"title\");\n });\n\n it(\"getType should return the field type\", () => {\n const form = createCmsForm();\n const types: Record<string, string> = {};\n form.traverse(builder => {\n types[builder.getName()] = builder.getType();\n });\n expect(types[\"textSingle\"]).toBe(\"text\");\n expect(types[\"objectMultiple\"]).toBe(\"object\");\n expect(types[\"uuid\"]).toBe(\"text\");\n });\n\n it(\"should find builders by name using traverse\", () => {\n const form = createCmsForm();\n const matched: string[] = [];\n form.traverse(builder => {\n if (builder.getName() === \"uuid\") {\n matched.push(builder.getName());\n }\n });\n expect(matched.length).toBe(2);\n });\n\n it(\"should find builders by type using traverse\", () => {\n const form = createCmsForm();\n const textBuilders: string[] = [];\n form.traverse(builder => {\n if (builder.getType() === \"text\") {\n textBuilders.push(builder.getName());\n }\n });\n // textSingle + objectMultiple.uuid + objectMultiple.name + dz.textBlock.uuid + dz.textBlock.title = 5\n expect(textBuilders.length).toBe(5);\n });\n\n it(\"should combine getName, getType, and getTags for precise filtering\", () => {\n const form = createCmsForm();\n const matched: string[] = [];\n form.traverse(builder => {\n if (\n builder.getType() === \"text\" &&\n builder.getName() === \"uuid\" &&\n builder.getTags().includes(\"uuid\")\n ) {\n matched.push(builder.getName());\n }\n });\n expect(matched.length).toBe(2);\n });\n});\n"],"names":["model","createCmsForm","container","Container","IdentityContextFeature","FormModelFeature","CmsFormModelFeature","builder","CmsFormModelBuilder","config","factory","FormModelFactory","describe","it","form","visited","expect","uuidBuilders","count","String","Date","names","types","matched","textBuilders"],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ declare class NewContentModelPresenterImpl implements INewContentModelPresenter
|
|
|
16
16
|
private form;
|
|
17
17
|
constructor(formModelFactory: FormModelFactory.Interface, listModelGroupsUseCase: ListModelGroupsUseCase.Interface, createModelUseCase: CreateModelUseCase.Interface, groupsCache: ModelGroupsCache.Interface, modelsCache: ModelsCache.Interface);
|
|
18
18
|
get vm(): INewContentModelPresenterViewModel;
|
|
19
|
+
private get groupOptions();
|
|
19
20
|
init(): Promise<void>;
|
|
20
21
|
save(): Promise<CmsModel | null>;
|
|
21
22
|
reset(): void;
|
|
@@ -26,18 +26,20 @@ class NewContentModelPresenterImpl {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
get vm() {
|
|
29
|
-
const groups = this.groupsCache.getItems().map((g)=>({
|
|
30
|
-
value: g.slug,
|
|
31
|
-
label: g.name
|
|
32
|
-
}));
|
|
33
29
|
return {
|
|
34
30
|
loading: this.loading,
|
|
35
31
|
saving: this.saving,
|
|
36
|
-
groups,
|
|
32
|
+
groups: this.groupOptions,
|
|
37
33
|
models: this.modelsCache.getItems(),
|
|
38
34
|
form: this.form.vm
|
|
39
35
|
};
|
|
40
36
|
}
|
|
37
|
+
get groupOptions() {
|
|
38
|
+
return this.groupsCache.getItems().map((group)=>({
|
|
39
|
+
value: group.slug,
|
|
40
|
+
label: group.name
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
41
43
|
async init() {
|
|
42
44
|
try {
|
|
43
45
|
await this.listModelGroupsUseCase.execute();
|
|
@@ -97,7 +99,7 @@ class NewContentModelPresenterImpl {
|
|
|
97
99
|
singularApiName: fields.text().label("Singular API Name").required("Singular API Name is required."),
|
|
98
100
|
singleEntry: fields.boolean().label("Single entry model").defaultValue(false),
|
|
99
101
|
pluralApiName: fields.text().label("Plural API Name"),
|
|
100
|
-
group: fields.text().label("Content model group").required("Group is required."),
|
|
102
|
+
group: fields.text().label("Content model group").required("Group is required.").options(()=>this.groupOptions),
|
|
101
103
|
icon: fields.text().label("Icon").renderer("cmsIconPicker"),
|
|
102
104
|
description: fields.text().label("Description").renderer("textarea"),
|
|
103
105
|
defaultFields: fields.boolean().label("Create model with default fields").defaultValue(true)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/newContentModel/NewContentModelPresenter.js","sources":["../../../src/presentation/newContentModel/NewContentModelPresenter.ts"],"sourcesContent":["import { makeAutoObservable, runInAction, computed } from \"mobx\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { IFormModel } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModel } from \"~/types.js\";\nimport { ListModelGroupsUseCase } from \"~/features/modelGroup/listModelGroups/abstractions.js\";\nimport { CreateModelUseCase } from \"~/features/model/createModel/abstractions.js\";\nimport { ModelGroupsCache } from \"~/features/modelGroup/abstractions.js\";\nimport { ModelsCache } from \"~/features/model/abstractions.js\";\nconst CMS_MODEL_SINGLETON_TAG = \"singleEntry\";\nimport {\n NewContentModelPresenter as Abstraction,\n type INewContentModelPresenter,\n type INewContentModelPresenterViewModel\n} from \"./abstractions.js\";\n\nclass NewContentModelPresenterImpl implements INewContentModelPresenter {\n private loading = true;\n private saving = false;\n private form: IFormModel;\n\n constructor(\n private formModelFactory: FormModelFactory.Interface,\n private listModelGroupsUseCase: ListModelGroupsUseCase.Interface,\n private createModelUseCase: CreateModelUseCase.Interface,\n private groupsCache: ModelGroupsCache.Interface,\n private modelsCache: ModelsCache.Interface\n ) {\n this.form = this.buildForm();\n makeAutoObservable<\n NewContentModelPresenterImpl,\n | \"formModelFactory\"\n | \"listModelGroupsUseCase\"\n | \"createModelUseCase\"\n | \"groupsCache\"\n | \"modelsCache\"\n >(this, {\n formModelFactory: false,\n listModelGroupsUseCase: false,\n createModelUseCase: false,\n groupsCache: false,\n modelsCache: false,\n vm: computed\n });\n }\n\n get vm(): INewContentModelPresenterViewModel {\n
|
|
1
|
+
{"version":3,"file":"presentation/newContentModel/NewContentModelPresenter.js","sources":["../../../src/presentation/newContentModel/NewContentModelPresenter.ts"],"sourcesContent":["import { makeAutoObservable, runInAction, computed } from \"mobx\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { IFormModel } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { CmsModel } from \"~/types.js\";\nimport { ListModelGroupsUseCase } from \"~/features/modelGroup/listModelGroups/abstractions.js\";\nimport { CreateModelUseCase } from \"~/features/model/createModel/abstractions.js\";\nimport { ModelGroupsCache } from \"~/features/modelGroup/abstractions.js\";\nimport { ModelsCache } from \"~/features/model/abstractions.js\";\nconst CMS_MODEL_SINGLETON_TAG = \"singleEntry\";\nimport {\n NewContentModelPresenter as Abstraction,\n type INewContentModelPresenter,\n type INewContentModelPresenterViewModel\n} from \"./abstractions.js\";\n\nclass NewContentModelPresenterImpl implements INewContentModelPresenter {\n private loading = true;\n private saving = false;\n private form: IFormModel;\n\n constructor(\n private formModelFactory: FormModelFactory.Interface,\n private listModelGroupsUseCase: ListModelGroupsUseCase.Interface,\n private createModelUseCase: CreateModelUseCase.Interface,\n private groupsCache: ModelGroupsCache.Interface,\n private modelsCache: ModelsCache.Interface\n ) {\n this.form = this.buildForm();\n makeAutoObservable<\n NewContentModelPresenterImpl,\n | \"formModelFactory\"\n | \"listModelGroupsUseCase\"\n | \"createModelUseCase\"\n | \"groupsCache\"\n | \"modelsCache\"\n >(this, {\n formModelFactory: false,\n listModelGroupsUseCase: false,\n createModelUseCase: false,\n groupsCache: false,\n modelsCache: false,\n vm: computed\n });\n }\n\n get vm(): INewContentModelPresenterViewModel {\n return {\n loading: this.loading,\n saving: this.saving,\n groups: this.groupOptions,\n models: this.modelsCache.getItems(),\n form: this.form.vm\n };\n }\n\n private get groupOptions() {\n return this.groupsCache.getItems().map(group => ({\n value: group.slug,\n label: group.name\n }));\n }\n\n async init(): Promise<void> {\n try {\n await this.listModelGroupsUseCase.execute();\n } finally {\n runInAction(() => {\n this.loading = false;\n const groups = this.groupsCache.getItems();\n if (groups.length > 0) {\n this.form.setData({ group: groups[0].slug });\n }\n });\n }\n }\n\n async save(): Promise<CmsModel | null> {\n const data = await this.form.submit<Record<string, any>>();\n if (!data) {\n return null;\n }\n\n runInAction(() => {\n this.saving = true;\n });\n\n try {\n const tags: string[] = Array.isArray(data.tags) ? data.tags : [];\n let pluralApiName = data.pluralApiName as string;\n\n if (data.singleEntry) {\n tags.push(CMS_MODEL_SINGLETON_TAG);\n pluralApiName = `${data.singularApiName}Unused`;\n }\n\n const model = await this.createModelUseCase.execute({\n name: data.name as string,\n singularApiName: data.singularApiName as string,\n pluralApiName,\n group: data.group as string,\n icon: data.icon as string | undefined,\n description: data.description as string | undefined,\n defaultFields: data.defaultFields as boolean | undefined,\n tags\n });\n\n return model;\n } catch {\n return null;\n } finally {\n runInAction(() => {\n this.saving = false;\n });\n }\n }\n\n reset(): void {\n this.form = this.buildForm();\n const groups = this.groupsCache.getItems();\n if (groups.length > 0) {\n this.form.setData({ group: groups[0].slug });\n }\n }\n\n private buildForm(): IFormModel {\n return this.formModelFactory.create({\n fields: fields => ({\n name: fields.text().label(\"Name\").required(\"Name is required.\"),\n singularApiName: fields\n .text()\n .label(\"Singular API Name\")\n .required(\"Singular API Name is required.\"),\n singleEntry: fields.boolean().label(\"Single entry model\").defaultValue(false),\n pluralApiName: fields.text().label(\"Plural API Name\"),\n group: fields\n .text()\n .label(\"Content model group\")\n .required(\"Group is required.\")\n /*\n * Options turn the text field into a select. The groups arrive after the form\n * is built, so they have to be read through a callback.\n */\n .options(() => this.groupOptions),\n icon: fields.text().label(\"Icon\").renderer(\"cmsIconPicker\"),\n description: fields.text().label(\"Description\").renderer(\"textarea\"),\n defaultFields: fields\n .boolean()\n .label(\"Create model with default fields\")\n .defaultValue(true)\n }),\n layout: layout => [\n layout.row(\"name\"),\n layout.row(\"singularApiName\"),\n layout.row(\"singleEntry\"),\n layout.row(\"pluralApiName\"),\n layout.row(\"group\"),\n layout.row(\"icon\"),\n layout.row(\"description\"),\n layout.row(\"defaultFields\")\n ]\n });\n }\n}\n\nexport const NewContentModelPresenter = Abstraction.createImplementation({\n implementation: NewContentModelPresenterImpl,\n dependencies: [\n FormModelFactory,\n ListModelGroupsUseCase,\n CreateModelUseCase,\n ModelGroupsCache,\n ModelsCache\n ]\n});\n"],"names":["CMS_MODEL_SINGLETON_TAG","NewContentModelPresenterImpl","formModelFactory","listModelGroupsUseCase","createModelUseCase","groupsCache","modelsCache","makeAutoObservable","computed","group","runInAction","groups","data","tags","Array","pluralApiName","model","fields","layout","NewContentModelPresenter","Abstraction","FormModelFactory","ListModelGroupsUseCase","CreateModelUseCase","ModelGroupsCache","ModelsCache"],"mappings":"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"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { IRuleEvaluator, IRule, IFormModel } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
2
|
-
declare class CmsAccessControlRuleEvaluatorImpl implements IRuleEvaluator {
|
|
3
|
-
canEvaluate(rule: IRule): boolean;
|
|
4
|
-
evaluate(_rule: IRule, _form: IFormModel): boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare const CmsAccessControlRuleEvaluator: typeof CmsAccessControlRuleEvaluatorImpl & {
|
|
7
|
-
__abstraction: import("@webiny/di").Abstraction<IRuleEvaluator>;
|
|
8
|
-
};
|
|
9
|
-
export {};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { RuleEvaluator } from "@webiny/app-admin/features/formModel/abstractions.js";
|
|
2
|
-
class CmsAccessControlRuleEvaluatorImpl {
|
|
3
|
-
canEvaluate(rule) {
|
|
4
|
-
return "accessControl" === rule.type;
|
|
5
|
-
}
|
|
6
|
-
evaluate(_rule, _form) {
|
|
7
|
-
return false;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
const CmsAccessControlRuleEvaluator = RuleEvaluator.createImplementation({
|
|
11
|
-
implementation: CmsAccessControlRuleEvaluatorImpl,
|
|
12
|
-
dependencies: []
|
|
13
|
-
});
|
|
14
|
-
export { CmsAccessControlRuleEvaluator };
|
|
15
|
-
|
|
16
|
-
//# sourceMappingURL=CmsAccessControlRuleEvaluator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"features/formModel/CmsAccessControlRuleEvaluator.js","sources":["../../../src/features/formModel/CmsAccessControlRuleEvaluator.ts"],"sourcesContent":["import type {\n IRuleEvaluator,\n IRule,\n IFormModel\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { RuleEvaluator } from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\nclass CmsAccessControlRuleEvaluatorImpl implements IRuleEvaluator {\n canEvaluate(rule: IRule): boolean {\n return rule.type === \"accessControl\";\n }\n\n evaluate(_rule: IRule, _form: IFormModel): boolean {\n // TODO: implement actual access control check against current identity/permissions\n return false;\n }\n}\n\nexport const CmsAccessControlRuleEvaluator = RuleEvaluator.createImplementation({\n implementation: CmsAccessControlRuleEvaluatorImpl,\n dependencies: []\n});\n"],"names":["CmsAccessControlRuleEvaluatorImpl","rule","_rule","_form","CmsAccessControlRuleEvaluator","RuleEvaluator"],"mappings":";AAOA,MAAMA;IACF,YAAYC,IAAW,EAAW;QAC9B,OAAOA,AAAc,oBAAdA,KAAK,IAAI;IACpB;IAEA,SAASC,KAAY,EAAEC,KAAiB,EAAW;QAE/C,OAAO;IACX;AACJ;AAEO,MAAMC,gCAAgCC,cAAc,oBAAoB,CAAC;IAC5E,gBAAgBL;IAChB,cAAc,EAAE;AACpB"}
|