@webiny/app-headless-cms-common 6.3.0 → 6.4.0-beta.1
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/Fields/ErrorBoundary.js +29 -34
- package/Fields/ErrorBoundary.js.map +1 -1
- package/Fields/FieldElement.js +38 -61
- package/Fields/FieldElement.js.map +1 -1
- package/Fields/FieldElementError.js +13 -22
- package/Fields/FieldElementError.js.map +1 -1
- package/Fields/FieldRulesProvider.js +11 -17
- package/Fields/FieldRulesProvider.js.map +1 -1
- package/Fields/Fields.js +76 -139
- package/Fields/Fields.js.map +1 -1
- package/Fields/Label.js +7 -7
- package/Fields/Label.js.map +1 -1
- package/Fields/LayoutDescriptorCell.js +33 -40
- package/Fields/LayoutDescriptorCell.js.map +1 -1
- package/Fields/evaluateExpression.js +54 -94
- package/Fields/evaluateExpression.js.map +1 -1
- package/Fields/fieldOptions.js +56 -104
- package/Fields/fieldOptions.js.map +1 -1
- package/Fields/index.js +0 -2
- package/Fields/layoutFieldRenderers/AlertFieldRenderer.js +7 -10
- package/Fields/layoutFieldRenderers/AlertFieldRenderer.js.map +1 -1
- package/Fields/layoutFieldRenderers/SeparatorFieldRenderer.js +12 -15
- package/Fields/layoutFieldRenderers/SeparatorFieldRenderer.js.map +1 -1
- package/Fields/layoutFieldRenderers/TabsFieldRenderer.js +52 -63
- package/Fields/layoutFieldRenderers/TabsFieldRenderer.js.map +1 -1
- package/Fields/operatorOptions.js +115 -87
- package/Fields/operatorOptions.js.map +1 -1
- package/Fields/useBind.js +101 -107
- package/Fields/useBind.js.map +1 -1
- package/Fields/useFieldRules.js +79 -133
- package/Fields/useFieldRules.js.map +1 -1
- package/Fields/useRenderPlugins.js +3 -2
- package/Fields/useRenderPlugins.js.map +1 -1
- package/ModelFieldProvider/CanEditField.js +6 -9
- package/ModelFieldProvider/CanEditField.js.map +1 -1
- package/ModelFieldProvider/ModelFieldContext.js +15 -22
- package/ModelFieldProvider/ModelFieldContext.js.map +1 -1
- package/ModelFieldProvider/index.js +0 -2
- package/ModelFieldProvider/useModelField.js +15 -21
- package/ModelFieldProvider/useModelField.js.map +1 -1
- package/ModelProvider/ModelContext.js +11 -15
- package/ModelProvider/ModelContext.js.map +1 -1
- package/ModelProvider/index.js +0 -2
- package/ModelProvider/useModel.js +7 -11
- package/ModelProvider/useModel.js.map +1 -1
- package/constants.js +2 -1
- package/constants.js.map +1 -1
- package/createFieldsList.js +27 -49
- package/createFieldsList.js.map +1 -1
- package/createValidationContainer.js +13 -20
- package/createValidationContainer.js.map +1 -1
- package/createValidators.js +42 -47
- package/createValidators.js.map +1 -1
- package/entries.graphql.d.ts +11 -0
- package/entries.graphql.js +74 -164
- package/entries.graphql.js.map +1 -1
- package/exports/admin/cms/model.js +0 -2
- package/exports/admin/cms.d.ts +1 -1
- package/exports/admin/cms.js +0 -3
- package/getModelTitleFieldId.js +4 -5
- package/getModelTitleFieldId.js.map +1 -1
- package/index.js +0 -2
- package/normalizeIcon.js +8 -7
- package/normalizeIcon.js.map +1 -1
- package/package.json +11 -13
- package/prepareFormData.js +39 -61
- package/prepareFormData.js.map +1 -1
- package/types/index.d.ts +2 -0
- package/types/index.js +1 -41
- package/types/model.js +4 -27
- package/types/model.js.map +1 -1
- package/types/shared.js +0 -3
- package/types/validation.js +0 -3
- package/Fields/index.js.map +0 -1
- package/ModelFieldProvider/index.js.map +0 -1
- package/ModelProvider/index.js.map +0 -1
- package/exports/admin/cms/model.js.map +0 -1
- package/exports/admin/cms.js.map +0 -1
- package/index.js.map +0 -1
- package/types/index.js.map +0 -1
- package/types/shared.js.map +0 -1
- package/types/validation.js.map +0 -1
package/Fields/useBind.js
CHANGED
|
@@ -1,117 +1,111 @@
|
|
|
1
|
-
import
|
|
1
|
+
import react, { cloneElement, createContext, useContext, useRef } from "react";
|
|
2
2
|
import { useForm } from "@webiny/form";
|
|
3
3
|
import { createValidators } from "../createValidators.js";
|
|
4
4
|
import { useModelField } from "../ModelFieldProvider/index.js";
|
|
5
5
|
import { createValidationContainer } from "../createValidationContainer.js";
|
|
6
|
-
const BindParentNameContext = /*#__PURE__*/createContext("");
|
|
7
|
-
|
|
8
|
-
const createFieldCacheKey = field
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
const BindParentNameContext = /*#__PURE__*/ createContext("");
|
|
7
|
+
const useBindParentName = ()=>useContext(BindParentNameContext);
|
|
8
|
+
const createFieldCacheKey = (field)=>[
|
|
9
|
+
field.id,
|
|
10
|
+
field.fieldId,
|
|
11
|
+
JSON.stringify(field.validation),
|
|
12
|
+
JSON.stringify(field.listValidation)
|
|
13
|
+
].join(";");
|
|
11
14
|
const emptyValidators = [];
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
15
|
+
function useBind({ Bind }) {
|
|
16
|
+
const { field } = useModelField();
|
|
17
|
+
const memoizedBindComponents = useRef({});
|
|
18
|
+
const cacheKey = createFieldCacheKey(field);
|
|
19
|
+
const form = useForm();
|
|
20
|
+
return (index = -1)=>{
|
|
21
|
+
const { parentName } = Bind;
|
|
22
|
+
const name = [
|
|
23
|
+
parentName,
|
|
24
|
+
field.fieldId,
|
|
25
|
+
index >= 0 ? index : void 0
|
|
26
|
+
].filter((v)=>void 0 !== v).join(".");
|
|
27
|
+
const componentId = `${name};${cacheKey}`;
|
|
28
|
+
if (memoizedBindComponents.current[componentId]) return memoizedBindComponents.current[componentId];
|
|
29
|
+
const validators = createValidators(field, field.validation || emptyValidators);
|
|
30
|
+
const listValidators = createValidators(field, field.listValidation || emptyValidators);
|
|
31
|
+
const isMultipleValues = -1 === index && field.list;
|
|
32
|
+
const inputValidators = isMultipleValues ? listValidators : validators;
|
|
33
|
+
const defaultValueFromSettings = isMultipleValues ? null : field.settings?.defaultValue;
|
|
34
|
+
memoizedBindComponents.current[componentId] = function(params) {
|
|
35
|
+
const { name: childName, validators: childValidators, children, defaultValue = defaultValueFromSettings } = params;
|
|
36
|
+
const { field } = useModelField();
|
|
37
|
+
return /*#__PURE__*/ react.createElement(BindParentNameContext.Provider, {
|
|
38
|
+
value: name
|
|
39
|
+
}, /*#__PURE__*/ react.createElement(Bind, {
|
|
40
|
+
name: childName || name,
|
|
41
|
+
validators: childValidators || inputValidators,
|
|
42
|
+
defaultValue: defaultValue ?? null,
|
|
43
|
+
context: {
|
|
44
|
+
field
|
|
45
|
+
}
|
|
46
|
+
}, (bind)=>{
|
|
47
|
+
const props = {
|
|
48
|
+
...bind
|
|
49
|
+
};
|
|
50
|
+
if (field.list && -1 === index) {
|
|
51
|
+
props.appendValue = (newValue, index)=>{
|
|
52
|
+
const currentValue = bind.value || [];
|
|
53
|
+
const newIndex = index ?? currentValue.length;
|
|
54
|
+
bind.onChange([
|
|
55
|
+
...currentValue.slice(0, newIndex),
|
|
56
|
+
newValue,
|
|
57
|
+
...currentValue.slice(newIndex)
|
|
58
|
+
]);
|
|
59
|
+
};
|
|
60
|
+
props.prependValue = (newValue)=>{
|
|
61
|
+
bind.onChange([
|
|
62
|
+
newValue,
|
|
63
|
+
...bind.value || []
|
|
64
|
+
]);
|
|
65
|
+
};
|
|
66
|
+
props.appendValues = (newValues)=>{
|
|
67
|
+
bind.onChange([
|
|
68
|
+
...bind.value || [],
|
|
69
|
+
...newValues
|
|
70
|
+
]);
|
|
71
|
+
};
|
|
72
|
+
props.removeValue = (index)=>{
|
|
73
|
+
if (index < 0) return;
|
|
74
|
+
const value = [
|
|
75
|
+
...bind.value.slice(0, index),
|
|
76
|
+
...bind.value.slice(index + 1)
|
|
77
|
+
];
|
|
78
|
+
bind.onChange(0 === value.length ? null : value);
|
|
79
|
+
form.validateInput(field.fieldId);
|
|
80
|
+
};
|
|
81
|
+
props.moveValueUp = (index)=>{
|
|
82
|
+
if (index <= 0) return;
|
|
83
|
+
const value = [
|
|
84
|
+
...bind.value
|
|
85
|
+
];
|
|
86
|
+
value.splice(index, 1);
|
|
87
|
+
value.splice(index - 1, 0, bind.value[index]);
|
|
88
|
+
bind.onChange(value);
|
|
89
|
+
};
|
|
90
|
+
props.moveValueDown = (index)=>{
|
|
91
|
+
if (index >= bind.value.length) return;
|
|
92
|
+
const value = [
|
|
93
|
+
...bind.value
|
|
94
|
+
];
|
|
95
|
+
value.splice(index, 1);
|
|
96
|
+
value.splice(index + 1, 0, bind.value[index]);
|
|
97
|
+
bind.onChange(value);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return "function" == typeof children ? children(props) : /*#__PURE__*/ cloneElement(children, props);
|
|
101
|
+
}));
|
|
63
102
|
};
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
bind.onChange([...currentValue.slice(0, newIndex), newValue, ...currentValue.slice(newIndex)]);
|
|
69
|
-
};
|
|
70
|
-
props.prependValue = newValue => {
|
|
71
|
-
bind.onChange([newValue, ...(bind.value || [])]);
|
|
72
|
-
};
|
|
73
|
-
props.appendValues = newValues => {
|
|
74
|
-
bind.onChange([...(bind.value || []), ...newValues]);
|
|
75
|
-
};
|
|
76
|
-
props.removeValue = index => {
|
|
77
|
-
if (index < 0) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const value = [...bind.value.slice(0, index), ...bind.value.slice(index + 1)];
|
|
81
|
-
bind.onChange(value.length === 0 ? null : value);
|
|
82
|
-
|
|
83
|
-
// To make sure the field is still valid, we must trigger validation.
|
|
84
|
-
form.validateInput(field.fieldId);
|
|
85
|
-
};
|
|
86
|
-
props.moveValueUp = index => {
|
|
87
|
-
if (index <= 0) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const value = [...bind.value];
|
|
91
|
-
value.splice(index, 1);
|
|
92
|
-
value.splice(index - 1, 0, bind.value[index]);
|
|
93
|
-
bind.onChange(value);
|
|
94
|
-
};
|
|
95
|
-
props.moveValueDown = index => {
|
|
96
|
-
if (index >= bind.value.length) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const value = [...bind.value];
|
|
100
|
-
value.splice(index, 1);
|
|
101
|
-
value.splice(index + 1, 0, bind.value[index]);
|
|
102
|
-
bind.onChange(value);
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
return typeof children === "function" ? children(props) : /*#__PURE__*/cloneElement(children, props);
|
|
106
|
-
}));
|
|
103
|
+
memoizedBindComponents.current[componentId].parentName = name;
|
|
104
|
+
memoizedBindComponents.current[componentId].displayName = `Bind<${name}>`;
|
|
105
|
+
memoizedBindComponents.current[componentId].ValidationContainer = createValidationContainer(name);
|
|
106
|
+
return memoizedBindComponents.current[componentId];
|
|
107
107
|
};
|
|
108
|
-
|
|
109
|
-
// We need to keep track of current field name, to support nested fields.
|
|
110
|
-
memoizedBindComponents.current[componentId].parentName = name;
|
|
111
|
-
memoizedBindComponents.current[componentId].displayName = `Bind<${name}>`;
|
|
112
|
-
memoizedBindComponents.current[componentId].ValidationContainer = createValidationContainer(name);
|
|
113
|
-
return memoizedBindComponents.current[componentId];
|
|
114
|
-
};
|
|
115
108
|
}
|
|
109
|
+
export { useBind, useBindParentName };
|
|
116
110
|
|
|
117
111
|
//# sourceMappingURL=useBind.js.map
|
package/Fields/useBind.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","createContext","useContext","useRef","cloneElement","useForm","createValidators","useModelField","createValidationContainer","BindParentNameContext","useBindParentName","createFieldCacheKey","field","id","fieldId","JSON","stringify","validation","listValidation","join","emptyValidators","useBind","Bind","memoizedBindComponents","cacheKey","form","index","parentName","name","undefined","filter","v","componentId","current","validators","listValidators","isMultipleValues","list","inputValidators","defaultValueFromSettings","settings","defaultValue","UseBind","params","childName","childValidators","children","createElement","Provider","value","context","bind","props","appendValue","newValue","currentValue","newIndex","length","onChange","slice","prependValue","appendValues","newValues","removeValue","validateInput","moveValueUp","splice","moveValueDown","displayName","ValidationContainer"],"sources":["useBind.tsx"],"sourcesContent":["import React, { createContext, useContext, useRef, cloneElement } from \"react\";\nimport type { Validator } from \"@webiny/validation/types.js\";\nimport { useForm } from \"@webiny/form\";\nimport { createValidators } from \"~/createValidators.js\";\nimport type { BindComponent, CmsModelField } from \"~/types/index.js\";\nimport { useModelField } from \"~/ModelFieldProvider/index.js\";\nimport { createValidationContainer } from \"~/createValidationContainer.js\";\n\nconst BindParentNameContext = createContext<string>(\"\");\n\nexport const useBindParentName = (): string => useContext(BindParentNameContext);\n\ninterface UseBindProps {\n Bind: BindComponent;\n}\n\ninterface UseBindParams {\n name?: string;\n validators?: Validator | Validator[];\n children?: any;\n defaultValue?: any;\n}\n\nconst createFieldCacheKey = (field: CmsModelField) => {\n return [\n field.id,\n field.fieldId,\n JSON.stringify(field.validation),\n JSON.stringify(field.listValidation)\n ].join(\";\");\n};\n\nexport interface GetBindCallable {\n (index?: number): BindComponent;\n}\n\nconst emptyValidators: Validator[] = [];\n\nexport function useBind({ Bind }: UseBindProps) {\n const { field } = useModelField();\n const memoizedBindComponents = useRef<Record<string, BindComponent>>({});\n const cacheKey = createFieldCacheKey(field);\n const form = useForm();\n\n return (index = -1) => {\n const { parentName } = Bind;\n\n // If there's a parent name assigned to the given Bind component, we need to include it in the new field \"name\".\n // This allows us to have nested fields (like \"object\" field with nested properties)\n const name = [parentName, field.fieldId, index >= 0 ? index : undefined]\n .filter(v => v !== undefined)\n .join(\".\");\n\n const componentId = `${name};${cacheKey}`;\n\n if (memoizedBindComponents.current[componentId]) {\n return memoizedBindComponents.current[componentId];\n }\n\n const validators = createValidators(field, field.validation || emptyValidators);\n const listValidators = createValidators(field, field.listValidation || emptyValidators);\n const isMultipleValues = index === -1 && field.list;\n const inputValidators = isMultipleValues ? listValidators : validators;\n\n // We only use default values for single-value fields.\n const defaultValueFromSettings = !isMultipleValues ? field.settings?.defaultValue : null;\n\n memoizedBindComponents.current[componentId] = function UseBind(params: UseBindParams) {\n const {\n name: childName,\n validators: childValidators,\n children,\n defaultValue = defaultValueFromSettings\n } = params;\n\n const { field } = useModelField();\n\n return (\n <BindParentNameContext.Provider value={name}>\n <Bind\n name={childName || name}\n validators={childValidators || inputValidators}\n defaultValue={defaultValue ?? null}\n context={{ field }}\n >\n {bind => {\n // Multiple-values functions below.\n const props = { ...bind };\n if (field.list && index === -1) {\n props.appendValue = (newValue: any, index?: number) => {\n const currentValue = bind.value || [];\n const newIndex = index ?? currentValue.length;\n\n bind.onChange([\n ...currentValue.slice(0, newIndex),\n newValue,\n ...currentValue.slice(newIndex)\n ]);\n };\n props.prependValue = (newValue: any) => {\n bind.onChange([newValue, ...(bind.value || [])]);\n };\n props.appendValues = (newValues: any[]) => {\n bind.onChange([...(bind.value || []), ...newValues]);\n };\n\n props.removeValue = (index: number) => {\n if (index < 0) {\n return;\n }\n\n const value = [\n ...bind.value.slice(0, index),\n ...bind.value.slice(index + 1)\n ];\n\n bind.onChange(value.length === 0 ? null : value);\n\n // To make sure the field is still valid, we must trigger validation.\n form.validateInput(field.fieldId);\n };\n\n props.moveValueUp = (index: number) => {\n if (index <= 0) {\n return;\n }\n\n const value = [...bind.value];\n value.splice(index, 1);\n value.splice(index - 1, 0, bind.value[index]);\n\n bind.onChange(value);\n };\n\n props.moveValueDown = (index: number) => {\n if (index >= bind.value.length) {\n return;\n }\n\n const value = [...bind.value];\n value.splice(index, 1);\n value.splice(index + 1, 0, bind.value[index]);\n\n bind.onChange(value);\n };\n }\n\n return typeof children === \"function\"\n ? children(props)\n : cloneElement(children, props);\n }}\n </Bind>\n </BindParentNameContext.Provider>\n );\n } as BindComponent;\n\n // We need to keep track of current field name, to support nested fields.\n memoizedBindComponents.current[componentId].parentName = name;\n memoizedBindComponents.current[componentId].displayName = `Bind<${name}>`;\n memoizedBindComponents.current[componentId].ValidationContainer =\n createValidationContainer(name);\n\n return memoizedBindComponents.current[componentId];\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"Fields/useBind.js","sources":["../../src/Fields/useBind.tsx"],"sourcesContent":["import React, { createContext, useContext, useRef, cloneElement } from \"react\";\nimport type { Validator } from \"@webiny/validation/types.js\";\nimport { useForm } from \"@webiny/form\";\nimport { createValidators } from \"~/createValidators.js\";\nimport type { BindComponent, CmsModelField } from \"~/types/index.js\";\nimport { useModelField } from \"~/ModelFieldProvider/index.js\";\nimport { createValidationContainer } from \"~/createValidationContainer.js\";\n\nconst BindParentNameContext = createContext<string>(\"\");\n\nexport const useBindParentName = (): string => useContext(BindParentNameContext);\n\ninterface UseBindProps {\n Bind: BindComponent;\n}\n\ninterface UseBindParams {\n name?: string;\n validators?: Validator | Validator[];\n children?: any;\n defaultValue?: any;\n}\n\nconst createFieldCacheKey = (field: CmsModelField) => {\n return [\n field.id,\n field.fieldId,\n JSON.stringify(field.validation),\n JSON.stringify(field.listValidation)\n ].join(\";\");\n};\n\nexport interface GetBindCallable {\n (index?: number): BindComponent;\n}\n\nconst emptyValidators: Validator[] = [];\n\nexport function useBind({ Bind }: UseBindProps) {\n const { field } = useModelField();\n const memoizedBindComponents = useRef<Record<string, BindComponent>>({});\n const cacheKey = createFieldCacheKey(field);\n const form = useForm();\n\n return (index = -1) => {\n const { parentName } = Bind;\n\n // If there's a parent name assigned to the given Bind component, we need to include it in the new field \"name\".\n // This allows us to have nested fields (like \"object\" field with nested properties)\n const name = [parentName, field.fieldId, index >= 0 ? index : undefined]\n .filter(v => v !== undefined)\n .join(\".\");\n\n const componentId = `${name};${cacheKey}`;\n\n if (memoizedBindComponents.current[componentId]) {\n return memoizedBindComponents.current[componentId];\n }\n\n const validators = createValidators(field, field.validation || emptyValidators);\n const listValidators = createValidators(field, field.listValidation || emptyValidators);\n const isMultipleValues = index === -1 && field.list;\n const inputValidators = isMultipleValues ? listValidators : validators;\n\n // We only use default values for single-value fields.\n const defaultValueFromSettings = !isMultipleValues ? field.settings?.defaultValue : null;\n\n memoizedBindComponents.current[componentId] = function UseBind(params: UseBindParams) {\n const {\n name: childName,\n validators: childValidators,\n children,\n defaultValue = defaultValueFromSettings\n } = params;\n\n const { field } = useModelField();\n\n return (\n <BindParentNameContext.Provider value={name}>\n <Bind\n name={childName || name}\n validators={childValidators || inputValidators}\n defaultValue={defaultValue ?? null}\n context={{ field }}\n >\n {bind => {\n // Multiple-values functions below.\n const props = { ...bind };\n if (field.list && index === -1) {\n props.appendValue = (newValue: any, index?: number) => {\n const currentValue = bind.value || [];\n const newIndex = index ?? currentValue.length;\n\n bind.onChange([\n ...currentValue.slice(0, newIndex),\n newValue,\n ...currentValue.slice(newIndex)\n ]);\n };\n props.prependValue = (newValue: any) => {\n bind.onChange([newValue, ...(bind.value || [])]);\n };\n props.appendValues = (newValues: any[]) => {\n bind.onChange([...(bind.value || []), ...newValues]);\n };\n\n props.removeValue = (index: number) => {\n if (index < 0) {\n return;\n }\n\n const value = [\n ...bind.value.slice(0, index),\n ...bind.value.slice(index + 1)\n ];\n\n bind.onChange(value.length === 0 ? null : value);\n\n // To make sure the field is still valid, we must trigger validation.\n form.validateInput(field.fieldId);\n };\n\n props.moveValueUp = (index: number) => {\n if (index <= 0) {\n return;\n }\n\n const value = [...bind.value];\n value.splice(index, 1);\n value.splice(index - 1, 0, bind.value[index]);\n\n bind.onChange(value);\n };\n\n props.moveValueDown = (index: number) => {\n if (index >= bind.value.length) {\n return;\n }\n\n const value = [...bind.value];\n value.splice(index, 1);\n value.splice(index + 1, 0, bind.value[index]);\n\n bind.onChange(value);\n };\n }\n\n return typeof children === \"function\"\n ? children(props)\n : cloneElement(children, props);\n }}\n </Bind>\n </BindParentNameContext.Provider>\n );\n } as BindComponent;\n\n // We need to keep track of current field name, to support nested fields.\n memoizedBindComponents.current[componentId].parentName = name;\n memoizedBindComponents.current[componentId].displayName = `Bind<${name}>`;\n memoizedBindComponents.current[componentId].ValidationContainer =\n createValidationContainer(name);\n\n return memoizedBindComponents.current[componentId];\n };\n}\n"],"names":["BindParentNameContext","createContext","useBindParentName","useContext","createFieldCacheKey","field","JSON","emptyValidators","useBind","Bind","useModelField","memoizedBindComponents","useRef","cacheKey","form","useForm","index","parentName","name","undefined","v","componentId","validators","createValidators","listValidators","isMultipleValues","inputValidators","defaultValueFromSettings","params","childName","childValidators","children","defaultValue","bind","props","newValue","currentValue","newIndex","newValues","value","cloneElement","createValidationContainer"],"mappings":"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"}
|
package/Fields/useFieldRules.js
CHANGED
|
@@ -3,151 +3,97 @@ import { useAuthentication } from "@webiny/app-admin";
|
|
|
3
3
|
import { evaluateExpression, resolveFieldPath } from "./evaluateExpression.js";
|
|
4
4
|
import { useParentRules } from "./FieldRulesProvider.js";
|
|
5
5
|
import { useBindParentName } from "./useBind.js";
|
|
6
|
-
/**
|
|
7
|
-
* Evaluate access control rules against an identity.
|
|
8
|
-
* Pure function — no hooks, can be called anywhere.
|
|
9
|
-
*/
|
|
10
6
|
function evaluateAccessControlRulesForIdentity(rules, identity) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
const userTargets = new Set();
|
|
8
|
+
userTargets.add(`admin:${identity.id}`);
|
|
9
|
+
for (const team of identity.teams)userTargets.add(`team:${team.slug}`);
|
|
10
|
+
let canView = true;
|
|
11
|
+
let canEdit = true;
|
|
12
|
+
for (const rule of rules){
|
|
13
|
+
if ("accessControl" === rule.type) {
|
|
14
|
+
if (rule.value && rule.operator) {
|
|
15
|
+
if (userTargets.has(String(rule.value))) {
|
|
16
|
+
if ("hide" === rule.action) canView = false;
|
|
17
|
+
else if ("disable" === rule.action) canEdit = false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
21
|
}
|
|
22
|
-
if (!rule.value || !rule.operator) {
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
if (!userTargets.has(String(rule.value))) {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (rule.action === "hide") {
|
|
29
|
-
canView = false;
|
|
30
|
-
} else if (rule.action === "disable") {
|
|
31
|
-
canEdit = false;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
canView,
|
|
36
|
-
canEdit
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Hook that evaluates access control rules for the current identity.
|
|
42
|
-
* Does not require `bindParentName` — only identity-based permissions.
|
|
43
|
-
*/
|
|
44
|
-
export function useFieldAccessControlRules(item) {
|
|
45
|
-
const {
|
|
46
|
-
identity
|
|
47
|
-
} = useAuthentication();
|
|
48
|
-
const rules = item.rules;
|
|
49
|
-
if (!rules || rules.length === 0) {
|
|
50
22
|
return {
|
|
51
|
-
|
|
52
|
-
|
|
23
|
+
canView,
|
|
24
|
+
canEdit
|
|
53
25
|
};
|
|
54
|
-
}
|
|
55
|
-
return evaluateAccessControlRulesForIdentity(rules, identity);
|
|
56
26
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
27
|
+
function useFieldAccessControlRules(item) {
|
|
28
|
+
const { identity } = useAuthentication();
|
|
29
|
+
const rules = item.rules;
|
|
30
|
+
if (!rules || 0 === rules.length) return {
|
|
31
|
+
canView: true,
|
|
32
|
+
canEdit: true
|
|
33
|
+
};
|
|
34
|
+
return evaluateAccessControlRulesForIdentity(rules, identity);
|
|
35
|
+
}
|
|
36
|
+
function evaluateAccessControlRules(item, identity) {
|
|
37
|
+
const rules = item.rules;
|
|
38
|
+
if (!rules || 0 === rules.length) return {
|
|
39
|
+
canView: true,
|
|
40
|
+
canEdit: true,
|
|
41
|
+
hidden: false,
|
|
42
|
+
disabled: false
|
|
43
|
+
};
|
|
44
|
+
const { canView, canEdit } = evaluateAccessControlRulesForIdentity(rules, identity);
|
|
65
45
|
return {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
46
|
+
canView,
|
|
47
|
+
canEdit,
|
|
48
|
+
hidden: false,
|
|
49
|
+
disabled: false
|
|
70
50
|
};
|
|
71
|
-
}
|
|
72
|
-
const {
|
|
73
|
-
canView,
|
|
74
|
-
canEdit
|
|
75
|
-
} = evaluateAccessControlRulesForIdentity(rules, identity);
|
|
76
|
-
return {
|
|
77
|
-
canView,
|
|
78
|
-
canEdit,
|
|
79
|
-
hidden: false,
|
|
80
|
-
disabled: false
|
|
81
|
-
};
|
|
82
51
|
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Internal hook that evaluates all rules (access control + entry value).
|
|
86
|
-
*/
|
|
87
52
|
function useFieldRules(item) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
canEdit: true,
|
|
98
|
-
hidden: false,
|
|
99
|
-
disabled: false
|
|
53
|
+
const { identity } = useAuthentication();
|
|
54
|
+
const form = useForm();
|
|
55
|
+
const bindParentName = useBindParentName();
|
|
56
|
+
const rules = item.rules;
|
|
57
|
+
if (!rules || 0 === rules.length) return {
|
|
58
|
+
canView: true,
|
|
59
|
+
canEdit: true,
|
|
60
|
+
hidden: false,
|
|
61
|
+
disabled: false
|
|
100
62
|
};
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
target: resolvedPath,
|
|
118
|
-
operator: rule.operator,
|
|
119
|
-
value: rule.value
|
|
120
|
-
}, name => form.getValue(name));
|
|
121
|
-
if (!matches) {
|
|
122
|
-
continue;
|
|
63
|
+
const { canView, canEdit } = evaluateAccessControlRulesForIdentity(rules, identity);
|
|
64
|
+
let hidden = false;
|
|
65
|
+
let disabled = false;
|
|
66
|
+
for (const rule of rules){
|
|
67
|
+
if ("condition" !== rule.type) continue;
|
|
68
|
+
if (!rule.target || !rule.operator) continue;
|
|
69
|
+
const resolvedPath = resolveFieldPath(rule.target, bindParentName);
|
|
70
|
+
const matches = evaluateExpression({
|
|
71
|
+
target: resolvedPath,
|
|
72
|
+
operator: rule.operator,
|
|
73
|
+
value: rule.value
|
|
74
|
+
}, (name)=>form.getValue(name));
|
|
75
|
+
if (matches) {
|
|
76
|
+
if ("hide" === rule.action) hidden = true;
|
|
77
|
+
else if ("disable" === rule.action) disabled = true;
|
|
78
|
+
}
|
|
123
79
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
canView,
|
|
132
|
-
canEdit,
|
|
133
|
-
hidden,
|
|
134
|
-
disabled
|
|
135
|
-
};
|
|
80
|
+
return {
|
|
81
|
+
canView,
|
|
82
|
+
canEdit,
|
|
83
|
+
hidden,
|
|
84
|
+
disabled
|
|
85
|
+
};
|
|
136
86
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
canView: parentRules.canView && itemRules.canView,
|
|
147
|
-
canEdit: parentRules.canEdit && itemRules.canEdit,
|
|
148
|
-
hidden: parentRules.hidden || itemRules.hidden,
|
|
149
|
-
disabled: parentRules.disabled || itemRules.disabled
|
|
150
|
-
};
|
|
87
|
+
function useFieldEffectiveRules(item) {
|
|
88
|
+
const parentRules = useParentRules();
|
|
89
|
+
const itemRules = useFieldRules(item);
|
|
90
|
+
return {
|
|
91
|
+
canView: parentRules.canView && itemRules.canView,
|
|
92
|
+
canEdit: parentRules.canEdit && itemRules.canEdit,
|
|
93
|
+
hidden: parentRules.hidden || itemRules.hidden,
|
|
94
|
+
disabled: parentRules.disabled || itemRules.disabled
|
|
95
|
+
};
|
|
151
96
|
}
|
|
97
|
+
export { evaluateAccessControlRules, useFieldAccessControlRules, useFieldEffectiveRules };
|
|
152
98
|
|
|
153
99
|
//# sourceMappingURL=useFieldRules.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"Fields/useFieldRules.js","sources":["../../src/Fields/useFieldRules.ts"],"sourcesContent":["import { useForm } from \"@webiny/form\";\nimport { useAuthentication } from \"@webiny/app-admin\";\nimport type { FieldRule } from \"~/types/model.js\";\nimport { evaluateExpression, resolveFieldPath } from \"./evaluateExpression.js\";\nimport { useParentRules } from \"./FieldRulesProvider.js\";\nimport { useBindParentName } from \"./useBind.js\";\n\nexport interface EffectiveFieldRules {\n canView: boolean;\n canEdit: boolean;\n hidden: boolean;\n disabled: boolean;\n}\n\ninterface HasRules {\n rules?: FieldRule[];\n}\n\ninterface IdentityLike {\n id: string;\n teams: { slug: string }[];\n}\n\n/**\n * Evaluate access control rules against an identity.\n * Pure function — no hooks, can be called anywhere.\n */\nfunction evaluateAccessControlRulesForIdentity(\n rules: FieldRule[],\n identity: IdentityLike\n): Pick<EffectiveFieldRules, \"canView\" | \"canEdit\"> {\n const userTargets = new Set<string>();\n userTargets.add(`admin:${identity.id}`);\n for (const team of identity.teams) {\n userTargets.add(`team:${team.slug}`);\n }\n\n let canView = true;\n let canEdit = true;\n\n for (const rule of rules) {\n if (rule.type !== \"accessControl\") {\n continue;\n }\n if (!rule.value || !rule.operator) {\n continue;\n }\n if (!userTargets.has(String(rule.value))) {\n continue;\n }\n if (rule.action === \"hide\") {\n canView = false;\n } else if (rule.action === \"disable\") {\n canEdit = false;\n }\n }\n\n return { canView, canEdit };\n}\n\n/**\n * Hook that evaluates access control rules for the current identity.\n * Does not require `bindParentName` — only identity-based permissions.\n */\nexport function useFieldAccessControlRules(\n item: HasRules\n): Pick<EffectiveFieldRules, \"canView\" | \"canEdit\"> {\n const { identity } = useAuthentication();\n\n const rules = item.rules;\n if (!rules || rules.length === 0) {\n return { canView: true, canEdit: true };\n }\n\n return evaluateAccessControlRulesForIdentity(rules, identity);\n}\n\n/**\n * Evaluate access control rules statically (without hooks).\n * Used in RowRenderer for the visibility approximation where hooks can't be called.\n */\nexport function evaluateAccessControlRules(\n item: HasRules,\n identity: IdentityLike\n): EffectiveFieldRules {\n const rules = item.rules;\n if (!rules || rules.length === 0) {\n return { canView: true, canEdit: true, hidden: false, disabled: false };\n }\n\n const { canView, canEdit } = evaluateAccessControlRulesForIdentity(rules, identity);\n return { canView, canEdit, hidden: false, disabled: false };\n}\n\n/**\n * Internal hook that evaluates all rules (access control + entry value).\n */\nfunction useFieldRules(item: HasRules): EffectiveFieldRules {\n const { identity } = useAuthentication();\n const form = useForm();\n const bindParentName = useBindParentName();\n\n const rules = item.rules;\n if (!rules || rules.length === 0) {\n return { canView: true, canEdit: true, hidden: false, disabled: false };\n }\n\n const { canView, canEdit } = evaluateAccessControlRulesForIdentity(rules, identity);\n\n let hidden = false;\n let disabled = false;\n\n for (const rule of rules) {\n if (rule.type !== \"condition\") {\n continue;\n }\n if (!rule.target || !rule.operator) {\n continue;\n }\n const resolvedPath = resolveFieldPath(rule.target, bindParentName);\n const matches = evaluateExpression(\n { target: resolvedPath, operator: rule.operator as any, value: rule.value },\n name => form.getValue(name)\n );\n if (!matches) {\n continue;\n }\n if (rule.action === \"hide\") {\n hidden = true;\n } else if (rule.action === \"disable\") {\n disabled = true;\n }\n }\n\n return { canView, canEdit, hidden, disabled };\n}\n\n/**\n * Composes useParentRules and useFieldRules into a single hook\n * that returns the effective (intersected) rules.\n */\nexport function useFieldEffectiveRules(item: HasRules): EffectiveFieldRules {\n const parentRules = useParentRules();\n const itemRules = useFieldRules(item);\n return {\n canView: parentRules.canView && itemRules.canView,\n canEdit: parentRules.canEdit && itemRules.canEdit,\n hidden: parentRules.hidden || itemRules.hidden,\n disabled: parentRules.disabled || itemRules.disabled\n };\n}\n"],"names":["evaluateAccessControlRulesForIdentity","rules","identity","userTargets","Set","team","canView","canEdit","rule","String","useFieldAccessControlRules","item","useAuthentication","evaluateAccessControlRules","useFieldRules","form","useForm","bindParentName","useBindParentName","hidden","disabled","resolvedPath","resolveFieldPath","matches","evaluateExpression","name","useFieldEffectiveRules","parentRules","useParentRules","itemRules"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { plugins } from "@webiny/plugins";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
function useRenderPlugins() {
|
|
4
|
+
return useMemo(()=>plugins.byType("cms-editor-field-renderer"), []);
|
|
5
5
|
}
|
|
6
|
+
export { useRenderPlugins };
|
|
6
7
|
|
|
7
8
|
//# sourceMappingURL=useRenderPlugins.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"Fields/useRenderPlugins.js","sources":["../../src/Fields/useRenderPlugins.ts"],"sourcesContent":["import { plugins } from \"@webiny/plugins\";\nimport { useMemo } from \"react\";\nimport type { CmsModelFieldRendererPlugin } from \"~/types/index.js\";\n\nexport function useRenderPlugins() {\n return useMemo(\n () => plugins.byType<CmsModelFieldRendererPlugin>(\"cms-editor-field-renderer\"),\n []\n );\n}\n"],"names":["useRenderPlugins","useMemo","plugins"],"mappings":";;AAIO,SAASA;IACZ,OAAOC,QACH,IAAMC,QAAQ,MAAM,CAA8B,8BAClD,EAAE;AAEV"}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import react from "react";
|
|
2
2
|
import { useParentRules } from "../Fields/index.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (!rules.canEdit || rules.disabled) {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, children);
|
|
3
|
+
const CanEditField = ({ children })=>{
|
|
4
|
+
const rules = useParentRules();
|
|
5
|
+
if (!rules.canEdit || rules.disabled) return null;
|
|
6
|
+
return /*#__PURE__*/ react.createElement(react.Fragment, null, children);
|
|
11
7
|
};
|
|
8
|
+
export { CanEditField };
|
|
12
9
|
|
|
13
10
|
//# sourceMappingURL=CanEditField.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"ModelFieldProvider/CanEditField.js","sources":["../../src/ModelFieldProvider/CanEditField.tsx"],"sourcesContent":["import React from \"react\";\nimport { useParentRules } from \"~/Fields/index.js\";\n\nexport interface CanEditFieldProps {\n children: React.ReactNode;\n}\n\nexport const CanEditField = ({ children }: CanEditFieldProps) => {\n const rules = useParentRules();\n\n if (!rules.canEdit || rules.disabled) {\n return null;\n }\n\n return <>{children}</>;\n};\n"],"names":["CanEditField","children","rules","useParentRules"],"mappings":";;AAOO,MAAMA,eAAe,CAAC,EAAEC,QAAQ,EAAqB;IACxD,MAAMC,QAAQC;IAEd,IAAI,CAACD,MAAM,OAAO,IAAIA,MAAM,QAAQ,EAChC,OAAO;IAGX,OAAO,WAAP,GAAO,0CAAGD;AACd"}
|