@truedat/df 4.58.3 → 4.58.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.58.5] 2022-12-23
4
+
5
+ ### Added
6
+
7
+ - [TD-5368] Editable checkbox in template form fields
8
+
3
9
  ## [4.58.3] 2022-12-21
4
10
 
5
11
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/df",
3
- "version": "4.58.3",
3
+ "version": "4.58.5",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -34,7 +34,7 @@
34
34
  "@testing-library/jest-dom": "^5.16.5",
35
35
  "@testing-library/react": "^12.0.0",
36
36
  "@testing-library/user-event": "^13.2.1",
37
- "@truedat/test": "4.58.3",
37
+ "@truedat/test": "4.58.5",
38
38
  "babel-jest": "^28.1.0",
39
39
  "babel-plugin-dynamic-import-node": "^2.3.3",
40
40
  "babel-plugin-lodash": "^3.3.4",
@@ -87,8 +87,8 @@
87
87
  },
88
88
  "dependencies": {
89
89
  "@apollo/client": "^3.7.1",
90
- "@truedat/auth": "4.58.3",
91
- "@truedat/core": "4.58.3",
90
+ "@truedat/auth": "4.58.5",
91
+ "@truedat/core": "4.58.5",
92
92
  "decode-uri-component": "^0.2.2",
93
93
  "path-to-regexp": "^1.7.0",
94
94
  "prop-types": "^15.8.1",
@@ -109,5 +109,5 @@
109
109
  "react-dom": ">= 16.8.6 < 17",
110
110
  "semantic-ui-react": ">= 2.0.3 < 2.2"
111
111
  },
112
- "gitHead": "d6ce0fa41e1d1ca09130b8beab9e21019314726e"
112
+ "gitHead": "4b4fcb2726e4ab83f5b70bf91010ed1aea4fcee7"
113
113
  }
@@ -10,11 +10,12 @@ import FieldGroupSegment from "./FieldGroupSegment";
10
10
  export const DynamicForm = ({
11
11
  applyTemplate,
12
12
  content,
13
- onChange,
14
- template,
15
- loading,
16
13
  fieldsToOmit,
14
+ isModification,
15
+ loading,
16
+ onChange,
17
17
  selectedDomain,
18
+ template,
18
19
  }) => {
19
20
  const { formatMessage } = useIntl();
20
21
  const domainId = selectedDomain?.id;
@@ -59,8 +60,9 @@ export const DynamicForm = ({
59
60
  })
60
61
  : null
61
62
  }
62
- fields={fields}
63
63
  scope={template?.scope}
64
+ fields={fields}
65
+ isModification={isModification}
64
66
  />
65
67
  ));
66
68
  };
@@ -69,10 +71,11 @@ DynamicForm.propTypes = {
69
71
  applyTemplate: PropTypes.func,
70
72
  content: PropTypes.object,
71
73
  fieldsToOmit: PropTypes.array,
72
- onChange: PropTypes.func,
73
- template: PropTypes.object,
74
+ isModification: PropTypes.bool,
74
75
  loading: PropTypes.bool,
76
+ onChange: PropTypes.func,
75
77
  selectedDomain: PropTypes.object,
78
+ template: PropTypes.object,
76
79
  };
77
80
 
78
81
  const makeMapStateToProps = () => {
@@ -4,7 +4,13 @@ import { Segment, Header } from "semantic-ui-react";
4
4
  import DynamicField from "./widgets/DynamicField";
5
5
  import FieldGroupSubSegment from "./FieldGroupSubSegment/FieldGroupSubSegment";
6
6
 
7
- export const FieldGroupSegment = ({ onFieldChange, name, fields, scope }) => (
7
+ export const FieldGroupSegment = ({
8
+ scope,
9
+ fields,
10
+ isModification,
11
+ name,
12
+ onFieldChange,
13
+ }) => (
8
14
  <Segment>
9
15
  {name && name !== "undefined" ? <Header as="h4" content={name} /> : null}
10
16
  {fields &&
@@ -19,11 +25,12 @@ export const FieldGroupSegment = ({ onFieldChange, name, fields, scope }) => (
19
25
  />
20
26
  ) : (
21
27
  <DynamicField
22
- key={i}
23
- onChange={onFieldChange}
28
+ scope={scope}
24
29
  field={field}
25
30
  fields={fields}
26
- scope={scope}
31
+ isModification={isModification}
32
+ key={i}
33
+ onChange={onFieldChange}
27
34
  />
28
35
  )
29
36
  )}
@@ -31,9 +38,10 @@ export const FieldGroupSegment = ({ onFieldChange, name, fields, scope }) => (
31
38
  );
32
39
 
33
40
  FieldGroupSegment.propTypes = {
34
- onFieldChange: PropTypes.func,
35
- name: PropTypes.string,
36
41
  fields: PropTypes.array,
42
+ isModification: PropTypes.bool,
43
+ name: PropTypes.string,
44
+ onFieldChange: PropTypes.func,
37
45
  scope: PropTypes.string,
38
46
  };
39
47
 
@@ -6,16 +6,17 @@ import { applyTemplate, validateContent } from "@truedat/df/utils";
6
6
  import DynamicForm from "./DynamicForm";
7
7
 
8
8
  export default function SelectableDynamicForm({
9
- domainIds,
10
- scope,
11
- required,
12
9
  content,
10
+ domainIds,
13
11
  header,
12
+ hideLabel,
13
+ isModification,
14
14
  name,
15
15
  onChange,
16
16
  onNameChange,
17
17
  placeholder,
18
- hideLabel,
18
+ required,
19
+ scope,
19
20
  }) {
20
21
  const [template, setTemplate] = useState();
21
22
  const domain = _.size(domainIds) > 0 ? { id: _.head(domainIds) } : null;
@@ -54,21 +55,22 @@ export default function SelectableDynamicForm({
54
55
  <TemplateSelector
55
56
  scope={scope}
56
57
  domainIds={domainIds}
57
- required={required}
58
- selectedValue={template?.id}
58
+ hideLabel={hideLabel}
59
59
  onChange={handleSelected}
60
60
  onLoad={handleLoad}
61
61
  placeholder={placeholder}
62
- hideLabel={hideLabel}
62
+ required={required}
63
+ selectedValue={template?.id}
63
64
  />
64
65
  {template ? (
65
66
  <>
66
67
  {header}
67
68
  <DynamicForm
68
- onChange={handleChange}
69
69
  content={content}
70
- template={template}
70
+ isModification={isModification}
71
+ onChange={handleChange}
71
72
  selectedDomain={domain}
73
+ template={template}
72
74
  />
73
75
  </>
74
76
  ) : null}
@@ -77,14 +79,15 @@ export default function SelectableDynamicForm({
77
79
  }
78
80
 
79
81
  SelectableDynamicForm.propTypes = {
80
- domainIds: PropTypes.array,
81
- scope: PropTypes.string,
82
- required: PropTypes.bool,
83
82
  content: PropTypes.object,
83
+ domainIds: PropTypes.array,
84
84
  header: PropTypes.node,
85
+ hideLabel: PropTypes.bool,
86
+ isModification: PropTypes.bool,
85
87
  name: PropTypes.string,
86
88
  onChange: PropTypes.func,
87
89
  onNameChange: PropTypes.func,
88
90
  placeholder: PropTypes.string,
89
- hideLabel: PropTypes.bool,
91
+ required: PropTypes.bool,
92
+ scope: PropTypes.string,
90
93
  };
@@ -19,6 +19,7 @@ Object {
19
19
  >
20
20
  <div
21
21
  class="field"
22
+ data-testid="form-field"
22
23
  >
23
24
  <label>
24
25
  label
@@ -70,6 +71,7 @@ Object {
70
71
  >
71
72
  <div
72
73
  class="field"
74
+ data-testid="form-field"
73
75
  >
74
76
  <label>
75
77
  label
@@ -12,6 +12,7 @@ exports[`<SelectableDynamicForm /> with a single template matches the latest sna
12
12
  </h4>
13
13
  <div
14
14
  class="field"
15
+ data-testid="form-field"
15
16
  >
16
17
  <label>
17
18
  field1
@@ -68,11 +68,19 @@ FieldByWidget.propTypes = {
68
68
  };
69
69
 
70
70
  export const DynamicField = ({
71
- field: { label, cardinality, description, value, ...fieldProps },
71
+ field: {
72
+ label,
73
+ cardinality,
74
+ description,
75
+ value,
76
+ editable = true,
77
+ ...fieldProps
78
+ },
79
+ isModification,
72
80
  onChange,
73
81
  scope,
74
82
  }) => (
75
- <Form.Field>
83
+ <Form.Field disabled={!editable && isModification} data-testid="form-field">
76
84
  <label>
77
85
  {label ? (
78
86
  <FormattedMessage id={`fields.${label}`} defaultMessage={label} />
@@ -109,6 +117,7 @@ export const DynamicField = ({
109
117
  </Label>
110
118
  ) : null}
111
119
  </label>
120
+
112
121
  <FieldByWidget
113
122
  field={{ ...fieldProps, value, cardinality }}
114
123
  onChange={onChange}
@@ -119,8 +128,9 @@ export const DynamicField = ({
119
128
  );
120
129
 
121
130
  DynamicField.propTypes = {
122
- onChange: PropTypes.func.isRequired,
123
131
  field: PropTypes.object.isRequired,
132
+ isModification: PropTypes.bool,
133
+ onChange: PropTypes.func.isRequired,
124
134
  scope: PropTypes.string,
125
135
  };
126
136
 
@@ -1,73 +1,130 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
2
+ import { render } from "@truedat/test/render";
3
+ import { within } from "@testing-library/react";
3
4
  import { DynamicField } from "../DynamicField";
4
5
 
5
6
  const onChange = jest.fn();
6
7
 
7
8
  describe("<DynamicField />", () => {
8
9
  it("matches the latest snapshot (radio widget)", () => {
9
- const props = { field: { widget: "radio" }, onChange };
10
- const wrapper = shallow(<DynamicField {...props} />);
11
- expect(wrapper).toMatchSnapshot();
10
+ const parsedValues = [
11
+ {
12
+ value: "a",
13
+ text: "a",
14
+ },
15
+ {
16
+ value: "b",
17
+ text: "b",
18
+ },
19
+ {
20
+ value: "c",
21
+ text: "c",
22
+ },
23
+ ];
24
+ const props = { field: { widget: "radio", parsedValues }, onChange };
25
+ const { container } = render(<DynamicField {...props} />);
26
+ expect(container).toMatchSnapshot();
12
27
  });
13
28
 
14
- it("matches the latest snapshot (cehckbox widget)", () => {
29
+ it("matches the latest snapshot (checkbox widget)", () => {
15
30
  const props = { field: { widget: "checkbox" }, onChange };
16
- const wrapper = shallow(<DynamicField {...props} />);
17
- expect(wrapper).toMatchSnapshot();
31
+ const { container } = render(<DynamicField {...props} />);
32
+ expect(container).toMatchSnapshot();
18
33
  });
19
34
 
20
35
  it("matches the latest snapshot (dropdown widget)", () => {
21
36
  const props = { field: { widget: "dropdown" }, onChange };
22
- const wrapper = shallow(<DynamicField {...props} />);
23
- expect(wrapper).toMatchSnapshot();
37
+ const { container } = render(<DynamicField {...props} />);
38
+ expect(container).toMatchSnapshot();
24
39
  });
25
40
 
26
41
  it("matches the latest snapshot (textarea widget)", () => {
27
42
  const props = { field: { widget: "textarea" }, onChange };
28
- const wrapper = shallow(<DynamicField {...props} />);
29
- expect(wrapper).toMatchSnapshot();
43
+ const { container } = render(<DynamicField {...props} />);
44
+ expect(container).toMatchSnapshot();
30
45
  });
31
46
 
32
47
  it("matches the latest snapshot (color_picker widget)", () => {
33
48
  const props = { field: { widget: "color_picker" }, onChange };
34
- const wrapper = shallow(<DynamicField {...props} />);
35
- expect(wrapper).toMatchSnapshot();
49
+ const { container } = render(<DynamicField {...props} />);
50
+ expect(container).toMatchSnapshot();
36
51
  });
37
52
 
38
53
  it("matches the latest snapshot (pair_list widget)", () => {
39
54
  const props = { field: { widget: "pair_list" }, onChange };
40
- const wrapper = shallow(<DynamicField {...props} />);
41
- expect(wrapper).toMatchSnapshot();
55
+ const { container } = render(<DynamicField {...props} />);
56
+ expect(container).toMatchSnapshot();
42
57
  });
43
58
 
44
59
  it("matches the latest snapshot (image widget)", () => {
45
60
  const props = { field: { widget: "image" }, onChange };
46
- const wrapper = shallow(<DynamicField {...props} />);
47
- expect(wrapper).toMatchSnapshot();
61
+ const { container } = render(<DynamicField {...props} />);
62
+ expect(container).toMatchSnapshot();
48
63
  });
49
64
 
50
65
  it("matches the latest snapshot (number widget)", () => {
51
66
  const props = { field: { widget: "number" }, onChange };
52
- const wrapper = shallow(<DynamicField {...props} />);
53
- expect(wrapper).toMatchSnapshot();
67
+ const { container } = render(<DynamicField {...props} />);
68
+ expect(container).toMatchSnapshot();
54
69
  });
55
70
 
56
71
  it("matches the latest snapshot (date widget)", () => {
57
72
  const props = { field: { widget: "date" }, onChange };
58
- const wrapper = shallow(<DynamicField {...props} />);
59
- expect(wrapper).toMatchSnapshot();
73
+ const { container } = render(<DynamicField {...props} />);
74
+ expect(container).toMatchSnapshot();
60
75
  });
61
76
 
62
77
  it("matches the latest snapshot (datetime widget)", () => {
63
78
  const props = { field: { widget: "datetime" }, onChange };
64
- const wrapper = shallow(<DynamicField {...props} />);
65
- expect(wrapper).toMatchSnapshot();
79
+ const { container } = render(<DynamicField {...props} />);
80
+ expect(container).toMatchSnapshot();
66
81
  });
67
82
 
68
83
  it("matches the latest snapshot (default widget)", () => {
69
84
  const props = { field: { widget: "foo" }, onChange };
70
- const wrapper = shallow(<DynamicField {...props} />);
71
- expect(wrapper).toMatchSnapshot();
85
+ const { container } = render(<DynamicField {...props} />);
86
+ expect(container).toMatchSnapshot();
87
+ });
88
+
89
+ it("editable: false enable the form field if is not modification", () => {
90
+ const props = {
91
+ field: { widget: "string", value: "input_placeholder", editable: false },
92
+ onChange,
93
+ isModification: false,
94
+ };
95
+
96
+ const { getByTestId } = render(<DynamicField {...props} />);
97
+ const formField = getByTestId("form-field");
98
+ expect(formField).not.toHaveClass("disabled");
99
+ const input = within(formField).getByDisplayValue("input_placeholder");
100
+ expect(input).toBeInTheDocument();
101
+ });
102
+
103
+ it("editable: false disables the form field if is a modification", () => {
104
+ const props = {
105
+ field: { widget: "string", value: "input_placeholder", editable: false },
106
+ onChange,
107
+ isModification: true,
108
+ };
109
+
110
+ const { getByTestId } = render(<DynamicField {...props} />);
111
+ const formField = getByTestId("form-field");
112
+ expect(formField).toHaveClass("disabled");
113
+ const input = within(formField).getByDisplayValue("input_placeholder");
114
+ expect(input).toBeInTheDocument();
115
+ });
116
+
117
+ it("editable: true enables the form field if not a modification", () => {
118
+ const props = {
119
+ field: { widget: "string", value: "input_placeholder", editable: true },
120
+ onChange,
121
+ isModification: false,
122
+ };
123
+
124
+ const { getByTestId } = render(<DynamicField {...props} />);
125
+ const formField = getByTestId("form-field");
126
+ expect(formField).not.toHaveClass("disabled");
127
+ const input = within(formField).getByDisplayValue("input_placeholder");
128
+ expect(input).toBeInTheDocument();
72
129
  });
73
130
  });
@@ -1,188 +1,555 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`<DynamicField /> matches the latest snapshot (cehckbox widget) 1`] = `
4
- <FormField>
5
- <label />
6
- <FieldByWidget
7
- field={
8
- Object {
9
- "cardinality": undefined,
10
- "value": undefined,
11
- "widget": "checkbox",
12
- }
13
- }
14
- onChange={[MockFunction]}
15
- widget="checkbox"
16
- />
17
- </FormField>
3
+ exports[`<DynamicField /> matches the latest snapshot (checkbox widget) 1`] = `
4
+ <div>
5
+ <div
6
+ class="field"
7
+ data-testid="form-field"
8
+ >
9
+ <label />
10
+ <div
11
+ class="field"
12
+ >
13
+ <div
14
+ class="ui fitted checkbox"
15
+ >
16
+ <input
17
+ class="hidden"
18
+ readonly=""
19
+ tabindex="0"
20
+ type="checkbox"
21
+ value=""
22
+ />
23
+ <label />
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
18
28
  `;
19
29
 
20
30
  exports[`<DynamicField /> matches the latest snapshot (color_picker widget) 1`] = `
21
- <FormField>
22
- <label />
23
- <FieldByWidget
24
- field={
25
- Object {
26
- "cardinality": undefined,
27
- "value": undefined,
28
- "widget": "color_picker",
29
- }
30
- }
31
- onChange={[MockFunction]}
32
- widget="color_picker"
33
- />
34
- </FormField>
31
+ <div>
32
+ <div
33
+ class="field"
34
+ data-testid="form-field"
35
+ >
36
+ <label />
37
+ <div
38
+ class="github-picker "
39
+ style="width: 200px; background: rgb(255, 255, 255); border: 1px solid rgba(0,0,0,0.2); box-shadow: 0 3px 12px rgba(0,0,0,0.15); border-radius: 4px; position: relative; padding: 5px; display: flex; flex-wrap: wrap;"
40
+ >
41
+ <div
42
+ style="position: absolute; border: 8px solid transparent; border-bottom-color: rgba(0,0,0,0.15); top: -16px; left: 9px;"
43
+ />
44
+ <div
45
+ style="position: absolute; border: 7px solid transparent; border-bottom-color: #fff; top: -14px; left: 10px;"
46
+ />
47
+ <span>
48
+ <div
49
+ style="width: 25px; height: 25px; font-size: 0px;"
50
+ >
51
+ <span>
52
+ <div
53
+ style="background: rgb(184, 0, 0); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
54
+ tabindex="0"
55
+ title="#B80000"
56
+ />
57
+ </span>
58
+ </div>
59
+ </span>
60
+ <span>
61
+ <div
62
+ style="width: 25px; height: 25px; font-size: 0px;"
63
+ >
64
+ <span>
65
+ <div
66
+ style="background: rgb(219, 62, 0); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
67
+ tabindex="0"
68
+ title="#DB3E00"
69
+ />
70
+ </span>
71
+ </div>
72
+ </span>
73
+ <span>
74
+ <div
75
+ style="width: 25px; height: 25px; font-size: 0px;"
76
+ >
77
+ <span>
78
+ <div
79
+ style="background: rgb(252, 203, 0); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
80
+ tabindex="0"
81
+ title="#FCCB00"
82
+ />
83
+ </span>
84
+ </div>
85
+ </span>
86
+ <span>
87
+ <div
88
+ style="width: 25px; height: 25px; font-size: 0px;"
89
+ >
90
+ <span>
91
+ <div
92
+ style="background: rgb(0, 139, 2); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
93
+ tabindex="0"
94
+ title="#008B02"
95
+ />
96
+ </span>
97
+ </div>
98
+ </span>
99
+ <span>
100
+ <div
101
+ style="width: 25px; height: 25px; font-size: 0px;"
102
+ >
103
+ <span>
104
+ <div
105
+ style="background: rgb(0, 107, 118); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
106
+ tabindex="0"
107
+ title="#006B76"
108
+ />
109
+ </span>
110
+ </div>
111
+ </span>
112
+ <span>
113
+ <div
114
+ style="width: 25px; height: 25px; font-size: 0px;"
115
+ >
116
+ <span>
117
+ <div
118
+ style="background: rgb(18, 115, 222); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
119
+ tabindex="0"
120
+ title="#1273DE"
121
+ />
122
+ </span>
123
+ </div>
124
+ </span>
125
+ <span>
126
+ <div
127
+ style="width: 25px; height: 25px; font-size: 0px;"
128
+ >
129
+ <span>
130
+ <div
131
+ style="background: rgb(0, 77, 207); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
132
+ tabindex="0"
133
+ title="#004DCF"
134
+ />
135
+ </span>
136
+ </div>
137
+ </span>
138
+ <span>
139
+ <div
140
+ style="width: 25px; height: 25px; font-size: 0px;"
141
+ >
142
+ <span>
143
+ <div
144
+ style="background: rgb(83, 0, 235); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
145
+ tabindex="0"
146
+ title="#5300EB"
147
+ />
148
+ </span>
149
+ </div>
150
+ </span>
151
+ <span>
152
+ <div
153
+ style="width: 25px; height: 25px; font-size: 0px;"
154
+ >
155
+ <span>
156
+ <div
157
+ style="background: rgb(235, 150, 148); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
158
+ tabindex="0"
159
+ title="#EB9694"
160
+ />
161
+ </span>
162
+ </div>
163
+ </span>
164
+ <span>
165
+ <div
166
+ style="width: 25px; height: 25px; font-size: 0px;"
167
+ >
168
+ <span>
169
+ <div
170
+ style="background: rgb(250, 208, 195); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
171
+ tabindex="0"
172
+ title="#FAD0C3"
173
+ />
174
+ </span>
175
+ </div>
176
+ </span>
177
+ <span>
178
+ <div
179
+ style="width: 25px; height: 25px; font-size: 0px;"
180
+ >
181
+ <span>
182
+ <div
183
+ style="background: rgb(254, 243, 189); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
184
+ tabindex="0"
185
+ title="#FEF3BD"
186
+ />
187
+ </span>
188
+ </div>
189
+ </span>
190
+ <span>
191
+ <div
192
+ style="width: 25px; height: 25px; font-size: 0px;"
193
+ >
194
+ <span>
195
+ <div
196
+ style="background: rgb(193, 225, 197); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
197
+ tabindex="0"
198
+ title="#C1E1C5"
199
+ />
200
+ </span>
201
+ </div>
202
+ </span>
203
+ <span>
204
+ <div
205
+ style="width: 25px; height: 25px; font-size: 0px;"
206
+ >
207
+ <span>
208
+ <div
209
+ style="background: rgb(190, 218, 220); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
210
+ tabindex="0"
211
+ title="#BEDADC"
212
+ />
213
+ </span>
214
+ </div>
215
+ </span>
216
+ <span>
217
+ <div
218
+ style="width: 25px; height: 25px; font-size: 0px;"
219
+ >
220
+ <span>
221
+ <div
222
+ style="background: rgb(196, 222, 246); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
223
+ tabindex="0"
224
+ title="#C4DEF6"
225
+ />
226
+ </span>
227
+ </div>
228
+ </span>
229
+ <span>
230
+ <div
231
+ style="width: 25px; height: 25px; font-size: 0px;"
232
+ >
233
+ <span>
234
+ <div
235
+ style="background: rgb(190, 211, 243); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
236
+ tabindex="0"
237
+ title="#BED3F3"
238
+ />
239
+ </span>
240
+ </div>
241
+ </span>
242
+ <span>
243
+ <div
244
+ style="width: 25px; height: 25px; font-size: 0px;"
245
+ >
246
+ <span>
247
+ <div
248
+ style="background: rgb(212, 196, 251); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none;"
249
+ tabindex="0"
250
+ title="#D4C4FB"
251
+ />
252
+ </span>
253
+ </div>
254
+ </span>
255
+ </div>
256
+ </div>
257
+ </div>
35
258
  `;
36
259
 
37
260
  exports[`<DynamicField /> matches the latest snapshot (date widget) 1`] = `
38
- <FormField>
39
- <label />
40
- <FieldByWidget
41
- field={
42
- Object {
43
- "cardinality": undefined,
44
- "value": undefined,
45
- "widget": "date",
46
- }
47
- }
48
- onChange={[MockFunction]}
49
- widget="date"
50
- />
51
- </FormField>
261
+ <div>
262
+ <div
263
+ class="field"
264
+ data-testid="form-field"
265
+ >
266
+ <label />
267
+ <div
268
+ class="field"
269
+ >
270
+ <div
271
+ class="ui left icon input"
272
+ >
273
+ <i
274
+ aria-hidden="true"
275
+ class="calendar icon"
276
+ />
277
+ <input
278
+ placeholder="Date"
279
+ tabindex="0"
280
+ type="text"
281
+ value=""
282
+ />
283
+ </div>
284
+ </div>
285
+ </div>
286
+ </div>
52
287
  `;
53
288
 
54
289
  exports[`<DynamicField /> matches the latest snapshot (datetime widget) 1`] = `
55
- <FormField>
56
- <label />
57
- <FieldByWidget
58
- field={
59
- Object {
60
- "cardinality": undefined,
61
- "value": undefined,
62
- "widget": "datetime",
63
- }
64
- }
65
- onChange={[MockFunction]}
66
- widget="datetime"
67
- />
68
- </FormField>
290
+ <div>
291
+ <div
292
+ class="field"
293
+ data-testid="form-field"
294
+ >
295
+ <label />
296
+ <div
297
+ class="field"
298
+ >
299
+ <div
300
+ class="ui left icon input"
301
+ >
302
+ <i
303
+ aria-hidden="true"
304
+ class="calendar icon"
305
+ />
306
+ <input
307
+ placeholder="Date Time"
308
+ tabindex="0"
309
+ type="text"
310
+ value=""
311
+ />
312
+ </div>
313
+ </div>
314
+ </div>
315
+ </div>
69
316
  `;
70
317
 
71
318
  exports[`<DynamicField /> matches the latest snapshot (default widget) 1`] = `
72
- <FormField>
73
- <label />
74
- <FieldByWidget
75
- field={
76
- Object {
77
- "cardinality": undefined,
78
- "value": undefined,
79
- "widget": "foo",
80
- }
81
- }
82
- onChange={[MockFunction]}
83
- widget="foo"
84
- />
85
- </FormField>
319
+ <div>
320
+ <div
321
+ class="field"
322
+ data-testid="form-field"
323
+ >
324
+ <label />
325
+ <div
326
+ class="field"
327
+ >
328
+ <div
329
+ class="ui input"
330
+ >
331
+ <input
332
+ type="text"
333
+ value=""
334
+ />
335
+ </div>
336
+ </div>
337
+ </div>
338
+ </div>
86
339
  `;
87
340
 
88
341
  exports[`<DynamicField /> matches the latest snapshot (dropdown widget) 1`] = `
89
- <FormField>
90
- <label />
91
- <FieldByWidget
92
- field={
93
- Object {
94
- "cardinality": undefined,
95
- "value": undefined,
96
- "widget": "dropdown",
97
- }
98
- }
99
- onChange={[MockFunction]}
100
- widget="dropdown"
101
- />
102
- </FormField>
342
+ <div>
343
+ <div
344
+ class="field"
345
+ data-testid="form-field"
346
+ >
347
+ <label />
348
+ <div
349
+ class="dimmable"
350
+ >
351
+ <div
352
+ class="field"
353
+ >
354
+ <div
355
+ aria-expanded="false"
356
+ class="ui fluid search selection dropdown"
357
+ role="combobox"
358
+ >
359
+ <input
360
+ aria-autocomplete="list"
361
+ autocomplete="off"
362
+ class="search"
363
+ tabindex="0"
364
+ type="text"
365
+ value=""
366
+ />
367
+ <div
368
+ aria-atomic="true"
369
+ aria-live="polite"
370
+ class="divider default text"
371
+ role="alert"
372
+ >
373
+ Select one...
374
+ </div>
375
+ <i
376
+ aria-hidden="true"
377
+ class="dropdown icon"
378
+ />
379
+ <div
380
+ aria-multiselectable="false"
381
+ class="menu transition"
382
+ role="listbox"
383
+ >
384
+ <div
385
+ aria-checked="false"
386
+ aria-selected="true"
387
+ class="selected item"
388
+ role="option"
389
+ style="pointer-events: all;"
390
+ >
391
+ <span
392
+ class="text"
393
+ >
394
+ No selection
395
+ </span>
396
+ </div>
397
+ </div>
398
+ </div>
399
+ </div>
400
+ <div
401
+ class="ui inverted dimmer"
402
+ >
403
+ <div
404
+ class="content"
405
+ >
406
+ <div
407
+ class="ui loader"
408
+ />
409
+ </div>
410
+ </div>
411
+ </div>
412
+ </div>
413
+ </div>
103
414
  `;
104
415
 
105
416
  exports[`<DynamicField /> matches the latest snapshot (image widget) 1`] = `
106
- <FormField>
107
- <label />
108
- <FieldByWidget
109
- field={
110
- Object {
111
- "cardinality": undefined,
112
- "value": undefined,
113
- "widget": "image",
114
- }
115
- }
116
- onChange={[MockFunction]}
117
- widget="image"
118
- />
119
- </FormField>
417
+ <div>
418
+ <div
419
+ class="field"
420
+ data-testid="form-field"
421
+ >
422
+ <label />
423
+ <input
424
+ accept="image/*"
425
+ type="file"
426
+ value=""
427
+ />
428
+ </div>
429
+ </div>
120
430
  `;
121
431
 
122
432
  exports[`<DynamicField /> matches the latest snapshot (number widget) 1`] = `
123
- <FormField>
124
- <label />
125
- <FieldByWidget
126
- field={
127
- Object {
128
- "cardinality": undefined,
129
- "value": undefined,
130
- "widget": "number",
131
- }
132
- }
133
- onChange={[MockFunction]}
134
- widget="number"
135
- />
136
- </FormField>
433
+ <div>
434
+ <div
435
+ class="field"
436
+ data-testid="form-field"
437
+ >
438
+ <label />
439
+ <div
440
+ class="field"
441
+ >
442
+ <input
443
+ type="number"
444
+ value=""
445
+ />
446
+ </div>
447
+ </div>
448
+ </div>
137
449
  `;
138
450
 
139
451
  exports[`<DynamicField /> matches the latest snapshot (pair_list widget) 1`] = `
140
- <FormField>
141
- <label />
142
- <FieldByWidget
143
- field={
144
- Object {
145
- "cardinality": undefined,
146
- "value": undefined,
147
- "widget": "pair_list",
148
- }
149
- }
150
- onChange={[MockFunction]}
151
- widget="pair_list"
152
- />
153
- </FormField>
452
+ <div>
453
+ <div
454
+ class="field"
455
+ data-testid="form-field"
456
+ >
457
+ <label />
458
+ <div
459
+ class="field"
460
+ >
461
+ <button
462
+ class="ui compact icon button"
463
+ >
464
+ <i
465
+ aria-hidden="true"
466
+ class="green add icon"
467
+ />
468
+ </button>
469
+ </div>
470
+ </div>
471
+ </div>
154
472
  `;
155
473
 
156
474
  exports[`<DynamicField /> matches the latest snapshot (radio widget) 1`] = `
157
- <FormField>
158
- <label />
159
- <FieldByWidget
160
- field={
161
- Object {
162
- "cardinality": undefined,
163
- "value": undefined,
164
- "widget": "radio",
165
- }
166
- }
167
- onChange={[MockFunction]}
168
- widget="radio"
169
- />
170
- </FormField>
475
+ <div>
476
+ <div
477
+ class="field"
478
+ data-testid="form-field"
479
+ >
480
+ <label />
481
+ <div
482
+ class="field"
483
+ >
484
+ <div
485
+ class="ui radio checkbox"
486
+ >
487
+ <input
488
+ class="hidden"
489
+ readonly=""
490
+ tabindex="0"
491
+ type="radio"
492
+ value="a"
493
+ />
494
+ <label>
495
+ a
496
+ </label>
497
+ </div>
498
+ </div>
499
+ <div
500
+ class="field"
501
+ >
502
+ <div
503
+ class="ui radio checkbox"
504
+ >
505
+ <input
506
+ class="hidden"
507
+ readonly=""
508
+ tabindex="0"
509
+ type="radio"
510
+ value="b"
511
+ />
512
+ <label>
513
+ b
514
+ </label>
515
+ </div>
516
+ </div>
517
+ <div
518
+ class="field"
519
+ >
520
+ <div
521
+ class="ui radio checkbox"
522
+ >
523
+ <input
524
+ class="hidden"
525
+ readonly=""
526
+ tabindex="0"
527
+ type="radio"
528
+ value="c"
529
+ />
530
+ <label>
531
+ c
532
+ </label>
533
+ </div>
534
+ </div>
535
+ </div>
536
+ </div>
171
537
  `;
172
538
 
173
539
  exports[`<DynamicField /> matches the latest snapshot (textarea widget) 1`] = `
174
- <FormField>
175
- <label />
176
- <FieldByWidget
177
- field={
178
- Object {
179
- "cardinality": undefined,
180
- "value": undefined,
181
- "widget": "textarea",
182
- }
183
- }
184
- onChange={[MockFunction]}
185
- widget="textarea"
186
- />
187
- </FormField>
540
+ <div>
541
+ <div
542
+ class="field"
543
+ data-testid="form-field"
544
+ >
545
+ <label />
546
+ <div
547
+ class="field"
548
+ >
549
+ <textarea
550
+ rows="3"
551
+ />
552
+ </div>
553
+ </div>
554
+ </div>
188
555
  `;
@@ -22,6 +22,7 @@ export default {
22
22
  "template.field.depends.on": "Source Field",
23
23
  "template.field.depends.to_be": "Source Value",
24
24
  "template.field.description": "Description",
25
+ "template.field.editable": "Editable",
25
26
  "template.field.hidden_secret": "<Hidden secret value>",
26
27
  "template.field.label": "Label",
27
28
  "template.field.mandatory.depends": "Mandatory depending on",
@@ -22,6 +22,7 @@ export default {
22
22
  "template.field.depends.on": "Campo origen",
23
23
  "template.field.depends.to_be": "Valor origen",
24
24
  "template.field.description": "Descripción",
25
+ "template.field.editable": "Editable",
25
26
  "template.field.hidden_secret": "<Campo secreto oculto>",
26
27
  "template.field.mandatory.depends": "Obligatorio dependiente de",
27
28
  "template.field.mandatory.depends.on": "Depende de",
@@ -2,7 +2,7 @@ import _ from "lodash/fp";
2
2
  import React, { useEffect } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { useIntl } from "react-intl";
5
- import { Form, Button, Divider, Segment } from "semantic-ui-react";
5
+ import { Form, Button, Divider, Segment, Checkbox } from "semantic-ui-react";
6
6
  import ValuesField from "./ValuesField";
7
7
  import ConditionalFieldForm from "./ConditionalFieldForm";
8
8
  import MandatoryConditional from "./MandatoryConditional";
@@ -42,8 +42,9 @@ export const FieldForm = ({
42
42
  cardinality,
43
43
  type,
44
44
  widget,
45
- disabled,
45
+ disabledName,
46
46
  errors,
47
+ editable = true,
47
48
  } = field;
48
49
  const fieldNamePrefix = `${groupNamePrefix}.fields[${fieldIndex}]`;
49
50
  const valueName = `${fieldNamePrefix}.values`;
@@ -167,7 +168,7 @@ export const FieldForm = ({
167
168
  value={name || ""}
168
169
  required
169
170
  onChange={onChange}
170
- disabled={disabled || hasDependencies}
171
+ disabled={disabledName || hasDependencies}
171
172
  error={
172
173
  errors &&
173
174
  errors.nameDuplicated && {
@@ -217,6 +218,14 @@ export const FieldForm = ({
217
218
  required
218
219
  options={getCardinalityOptions(formatMessage)(widget)}
219
220
  />
221
+ <Form.Checkbox
222
+ name={`${fieldNamePrefix}.editable`}
223
+ label={formatMessage({ id: "template.field.editable" })}
224
+ checked={editable}
225
+ onChange={(e, { name, checked: value }) =>
226
+ onChange(null, { name, value })
227
+ }
228
+ ></Form.Checkbox>
220
229
  </Form.Group>
221
230
  <ValuesField
222
231
  defaultField={defaultField}
@@ -29,7 +29,9 @@ export const TemplateForm = ({ loading, template, onSubmit, onDelete }) => {
29
29
  useEffect(() => {
30
30
  if (template && !_.isNil(template.id)) {
31
31
  const content = _.map((g) => {
32
- const fields = _.map((f) => ({ ...f, disabled: true }))(g.fields);
32
+ const fields = _.map((f) => {
33
+ return { ...f, disabledName: true };
34
+ })(g.fields);
33
35
  return { ...g, fields };
34
36
  })(template.content);
35
37
  setEditedTemplate({ ...editedTemplate, content });
@@ -65,6 +67,7 @@ export const TemplateForm = ({ loading, template, onSubmit, onDelete }) => {
65
67
  "default",
66
68
  "subscribable",
67
69
  "mandatory",
70
+ "editable",
68
71
  ];
69
72
 
70
73
  const dependsProperty = _.isEmpty(_.path("depends.on")(field))
@@ -41,7 +41,7 @@ describe("<FieldForm />", () => {
41
41
  label: "Field 1",
42
42
  description: "A field for testing",
43
43
  meta: { role: "Data Owner" },
44
- disabled: true,
44
+ disabledName: true,
45
45
  widget: "string",
46
46
  };
47
47
  const fieldIndex = 0;
@@ -208,6 +208,14 @@ exports[`<FieldForm /> manages handleCardinalityChange 1`] = `
208
208
  selection={true}
209
209
  value="?"
210
210
  />
211
+ <FormCheckbox
212
+ as={[Function]}
213
+ checked={true}
214
+ control={[Function]}
215
+ label="template.field.editable"
216
+ name="Group.fields[0].editable"
217
+ onChange={[Function]}
218
+ />
211
219
  </FormGroup>
212
220
  <ValuesField
213
221
  defaultField="Group.fields[0].default"
@@ -587,6 +595,14 @@ exports[`<FieldForm /> matches the latest snapshot 1`] = `
587
595
  required={true}
588
596
  selection={true}
589
597
  />
598
+ <FormCheckbox
599
+ as={[Function]}
600
+ checked={true}
601
+ control={[Function]}
602
+ label="template.field.editable"
603
+ name="undefined.fields[0].editable"
604
+ onChange={[Function]}
605
+ />
590
606
  </FormGroup>
591
607
  <ValuesField
592
608
  defaultField="undefined.fields[0].default"
@@ -847,6 +863,14 @@ exports[`<FieldForm /> renders MandatoryConditional 1`] = `
847
863
  selection={true}
848
864
  value="?"
849
865
  />
866
+ <FormCheckbox
867
+ as={[Function]}
868
+ checked={true}
869
+ control={[Function]}
870
+ label="template.field.editable"
871
+ name="Group.fields[0].editable"
872
+ onChange={[Function]}
873
+ />
850
874
  </FormGroup>
851
875
  <ValuesField
852
876
  defaultField="Group.fields[0].default"
@@ -1246,6 +1270,14 @@ exports[`<FieldForm /> renders ValuesField and manages onChange 1`] = `
1246
1270
  required={true}
1247
1271
  selection={true}
1248
1272
  />
1273
+ <FormCheckbox
1274
+ as={[Function]}
1275
+ checked={true}
1276
+ control={[Function]}
1277
+ label="template.field.editable"
1278
+ name="Group.fields[0].editable"
1279
+ onChange={[Function]}
1280
+ />
1249
1281
  </FormGroup>
1250
1282
  <ValuesField
1251
1283
  defaultField="Group.fields[0].default"