@eeacms/volto-editing-progress 0.3.0 → 0.4.0

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
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [0.4.0](https://github.com/eea/volto-editing-progress/compare/0.3.0...0.4.0) - 19 February 2024
8
+
9
+ #### :rocket: New Features
10
+
11
+ - feat: Improve editing progress, add propery option, remove property, change states - refs #262289 [dobri1408 - [`82c1ceb`](https://github.com/eea/volto-editing-progress/commit/82c1ceb2920b12e8eaf7225de944baad20382989)]
12
+
13
+ #### :house: Internal changes
14
+
15
+
16
+ #### :hammer_and_wrench: Others
17
+
18
+ - Release 0.4.0 [alin - [`13fc3ef`](https://github.com/eea/volto-editing-progress/commit/13fc3ef5bbeaeaa5f8086a9003e42b05bc06c30a)]
7
19
  ### [0.3.0](https://github.com/eea/volto-editing-progress/compare/0.2.3...0.3.0) - 18 October 2023
8
20
 
9
21
  #### :rocket: New Features
@@ -40,7 +52,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
40
52
  - test: Update failing snapshots [Alin Voinea - [`c1b022f`](https://github.com/eea/volto-editing-progress/commit/c1b022f39c9ff8ee1f6a9732eb2ba7f58b7e8492)]
41
53
  - test: remade interface in accordion style and accommodated tests [Chirilov Narcis - [`2cc87f5`](https://github.com/eea/volto-editing-progress/commit/2cc87f5456cf9610be6c883877b4ec87e5613ede)]
42
54
  - test: EN locales, pre-commit fix, feature PRs checks Refs #257193 [valentinab25 - [`59236c9`](https://github.com/eea/volto-editing-progress/commit/59236c9381b5d1f2059086d1f61823a1ec2309b0)]
43
- - Release 0.3.0 [Alin Voinea - [`21d325a`](https://github.com/eea/volto-editing-progress/commit/21d325a8f265c21fb3bf78a5ad2fe037aa86040e)]
44
55
  - new feature [Narcis2005 - [`d981603`](https://github.com/eea/volto-editing-progress/commit/d981603df4204eab8a650df92521201a299ea75e)]
45
56
  - more refactoring [Narcis2005 - [`28cfc60`](https://github.com/eea/volto-editing-progress/commit/28cfc6021b4ee328cecbef285b9ed2296891c7e9)]
46
57
  - refactoring [Narcis2005 - [`8dc569c`](https://github.com/eea/volto-editing-progress/commit/8dc569cf2b21a7528a77ee55881b56c11a4ad3c6)]
package/cypress.config.js CHANGED
@@ -5,9 +5,9 @@ module.exports = defineConfig({
5
5
  defaultCommandTimeout: 8888,
6
6
  chromeWebSecurity: false,
7
7
  reporter: 'junit',
8
- video: true,
8
+ video: false,
9
9
  retries: {
10
- runMode: 1,
10
+ runMode: 2,
11
11
  openMode: 0,
12
12
  },
13
13
  reporterOptions: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-editing-progress",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "@eeacms/volto-editing-progress: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -86,7 +86,7 @@ const EditingProgress = (props) => {
86
86
  className={'sidenav-ol sidenav-ol--ep is-hidden'}
87
87
  ref={sideMenuRef}
88
88
  >
89
- {remaining_steps.map((step, index) => {
89
+ {remaining_steps.map((step) => {
90
90
  return (
91
91
  <li className={'ep-sidenav-li'} key={step['link_label']}>
92
92
  <a
@@ -1,6 +1,8 @@
1
1
  import React, { useState, useEffect } from 'react';
2
2
  import { ModalForm } from '@plone/volto/components';
3
3
  import { JSONSchema } from './schema';
4
+ import { Dropdown } from 'semantic-ui-react';
5
+
4
6
  import {
5
7
  Button,
6
8
  Container,
@@ -42,6 +44,8 @@ function addNewStateToAlreadyExistingField(
42
44
  currentField,
43
45
  statesToAdd,
44
46
  message,
47
+ condition,
48
+ link,
45
49
  ) {
46
50
  for (
47
51
  let localRuleIndex = 0;
@@ -55,7 +59,9 @@ function addNewStateToAlreadyExistingField(
55
59
  // to currentContentTypeData dinamically in order to create the posibillity
56
60
  // for multiple fields
57
61
 
58
- if (message) currentContentTypeData[localRuleIndex].message = message;
62
+ if (message) currentContentTypeData[localRuleIndex].linkLabel = message;
63
+ if (condition) currentContentTypeData[localRuleIndex].condition = condition;
64
+ if (link) currentContentTypeData[localRuleIndex].link = link;
59
65
  if (statesToAdd !== undefined) {
60
66
  currentContentTypeData[localRuleIndex].states = statesToAdd;
61
67
  } else if (!message) currentContentTypeData.splice(localRuleIndex, 1);
@@ -74,20 +80,13 @@ function createFieldRule(currentField, statesToAdd) {
74
80
  prefix: currentField,
75
81
  states: statesToAdd,
76
82
  condition: 'python:value',
77
- hideReady: 'False',
78
- iconEmpty: 'eea-icon eea-icon-edit',
79
- iconReady: 'eea-icon eea-icon-check',
80
- labelEmpty: 'Please set the {label} of this {context.portal_type}',
81
- labelReady: 'You added the {label}',
82
- link: 'edit#fieldset-supporting information-field-label-data_description',
83
+ link: 'edit#fieldset-metadata-field-label-' + currentField,
83
84
  linkLabel: 'Add {label}',
84
- message: '',
85
85
  };
86
86
  }
87
87
 
88
88
  const VisualJSONWidget = (props) => {
89
89
  const { id, value = {}, onChange } = props;
90
- // console.log(value);
91
90
  const [isJSONEditorOpen, setIsJSONEditorOpen] = useState(false);
92
91
  const [currentContentType, setCurrentContentType] = useState();
93
92
 
@@ -99,7 +98,10 @@ const VisualJSONWidget = (props) => {
99
98
  const request = useSelector((state) => state.rawdata?.[path]);
100
99
  const content = request?.data;
101
100
  const types = useSelector((state) => state.types);
102
-
101
+ const fields =
102
+ request?.data?.fieldsets.reduce((acc, cur) => {
103
+ return [...acc, ...(cur.fields || [])];
104
+ }, []) || [];
103
105
  useEffect(() => {
104
106
  if (path && !request?.loading && !request?.loaded && !content)
105
107
  dispatch(getRawContent(path));
@@ -120,7 +122,9 @@ const VisualJSONWidget = (props) => {
120
122
  e.preventDefault();
121
123
  setIsJSONEditorOpen(true);
122
124
  };
123
-
125
+ const makeFirstLetterCapital = (string) => {
126
+ return string.charAt(0).toUpperCase() + string.slice(1);
127
+ };
124
128
  const onJSONSubmit = (e) => {
125
129
  setIsJSONEditorOpen(false);
126
130
  if (typeof e.json === 'string' && isValidJson(e.json)) {
@@ -134,8 +138,15 @@ const VisualJSONWidget = (props) => {
134
138
  setCurrentContentType(type);
135
139
  };
136
140
 
137
- const handleOnDropdownChange = (e, data, currentField, message) => {
138
- const states = data?.value?.length > 0 ? data?.value : undefined;
141
+ const handleOnDropdownChange = (
142
+ e,
143
+ data,
144
+ currentField,
145
+ message,
146
+ condition,
147
+ link,
148
+ ) => {
149
+ const states = data.value;
139
150
  const statesToAdd = states?.map((state) => state.toLowerCase());
140
151
  const localCopyOfValue = _.cloneDeep(value);
141
152
  const currentContentTypeData = localCopyOfValue[currentContentType.id];
@@ -159,6 +170,8 @@ const VisualJSONWidget = (props) => {
159
170
  currentField,
160
171
  statesToAdd,
161
172
  message,
173
+ condition,
174
+ link,
162
175
  );
163
176
  }
164
177
  //The variable currentContentTypeData cannot be used here because of eslint and delete keyword
@@ -167,6 +180,19 @@ const VisualJSONWidget = (props) => {
167
180
  }
168
181
  onChange(id, localCopyOfValue);
169
182
  };
183
+ const getDropdownValues = (currentField) => {
184
+ if (
185
+ !request.loading &&
186
+ request.loaded &&
187
+ currentContentType &&
188
+ value[currentContentType.id]
189
+ )
190
+ return value[currentContentType.id]
191
+ .find((rule) => rule?.prefix === currentField)
192
+ ?.states.map((state) => makeFirstLetterCapital(state));
193
+
194
+ return undefined;
195
+ };
170
196
 
171
197
  return (
172
198
  <>
@@ -186,6 +212,26 @@ const VisualJSONWidget = (props) => {
186
212
  <Button onClick={handleEditJSON} color="grey" id="json_button">
187
213
  <FormattedMessage id="Edit JSON" defaultMessage="Edit JSON" />
188
214
  </Button>
215
+
216
+ {fields && (
217
+ <Dropdown
218
+ className="ui grey button dropdown-button"
219
+ text="Add Property"
220
+ options={fields
221
+ .filter((field) => {
222
+ return (
223
+ getDropdownValues(field) === undefined &&
224
+ !request.data.required.includes(field)
225
+ );
226
+ })
227
+ .map((field) => {
228
+ return { key: field, text: field, value: field };
229
+ })}
230
+ onChange={(e, t) => {
231
+ handleOnDropdownChange(e, { value: ['all'] }, t.value);
232
+ }}
233
+ />
234
+ )}
189
235
  </Container>
190
236
  <Divider />
191
237
  </div>
@@ -202,6 +248,8 @@ const VisualJSONWidget = (props) => {
202
248
  handleOnDropdownChange={handleOnDropdownChange}
203
249
  currentContentType={currentContentType}
204
250
  value={value}
251
+ fields={fields}
252
+ getDropdownValues={getDropdownValues}
205
253
  />
206
254
  </Sidebar.Pusher>
207
255
  </Sidebar.Pushable>
@@ -5,6 +5,8 @@ import { useSelector, useDispatch } from 'react-redux';
5
5
  import { getRawContent } from './actions';
6
6
  import { COMPONENT_HEIGHT } from './VisualJSONWidget';
7
7
 
8
+ import './less/editor.less';
9
+
8
10
  export function makeFirstLetterCapital(string) {
9
11
  return string.charAt(0).toUpperCase() + string.slice(1);
10
12
  }
@@ -14,6 +16,8 @@ const EditDataComponent = ({
14
16
  handleOnDropdownChange,
15
17
  currentContentType,
16
18
  value,
19
+ fields,
20
+ getDropdownValues,
17
21
  }) => {
18
22
  const path = flattenToAppURL(
19
23
  '/@vocabularies/plone.app.vocabularies.WorkflowStates',
@@ -43,41 +47,28 @@ const EditDataComponent = ({
43
47
  ]);
44
48
 
45
49
  //Returns the saved values for dropdown with the first letter in uppercase
46
- const getDropdownValues = (currentField) => {
47
- if (
48
- !request.loading &&
49
- request.loaded &&
50
- currentContentType &&
51
- value[currentContentType.id]
52
- )
53
- return value[currentContentType.id]
54
- .find((rule) => rule?.prefix === currentField)
55
- ?.states.map((state) => makeFirstLetterCapital(state));
56
50
 
57
- return undefined;
58
- };
59
- const getMessage = (currentField) => {
51
+ const getValues = (currentField) => {
60
52
  if (
61
53
  !request.loading &&
62
54
  request.loaded &&
63
55
  currentContentType &&
64
56
  value[currentContentType.id]
65
57
  )
66
- return (
67
- value[currentContentType.id].find(
68
- (rule) => rule?.prefix === currentField,
69
- )?.message || ''
58
+ return value[currentContentType.id].find(
59
+ (rule) => rule?.prefix === currentField,
70
60
  );
71
61
 
72
- return '';
62
+ return undefined;
73
63
  };
64
+
74
65
  const renderLabel = (label) => ({
75
66
  color: 'blue',
76
67
  content: `${label.text}`,
77
68
  });
78
69
 
79
70
  const createStateOption = (stateOptions) => {
80
- return stateOptions.map((state) => ({
71
+ return ['all', ...(stateOptions || [])].map((state) => ({
81
72
  key: makeFirstLetterCapital(state),
82
73
  text: makeFirstLetterCapital(state),
83
74
  value: makeFirstLetterCapital(state),
@@ -86,17 +77,46 @@ const EditDataComponent = ({
86
77
  const [activeIndex, setActiveIndex] = useState(0);
87
78
  // const inputRef = useRef();
88
79
  const [inputValue, setInputValue] = useState('');
89
-
80
+ const [conditionValue, setConditionValue] = useState('');
81
+ const [linkValue, setLinkValue] = useState();
90
82
  const handleClick = (e, titleProps, currentField) => {
91
83
  const { index } = titleProps;
92
84
  const newIndex = activeIndex === index ? -1 : index;
93
85
 
94
86
  setActiveIndex(newIndex);
95
- setInputValue(getMessage(currentField));
87
+ setInputValue(getValues(currentField)?.linkLabel || '');
88
+ setConditionValue(getValues(currentField)?.condition || '');
89
+ setLinkValue(getValues(currentField)?.link || '');
96
90
  };
97
91
  const handleInputChange = (e, currentField) => {
98
92
  setInputValue(e.target.value);
99
- handleOnDropdownChange(null, null, currentField, e.target.value);
93
+ handleOnDropdownChange(
94
+ null,
95
+ { value: getValues(currentField).states || [] },
96
+ currentField,
97
+ e.target.value,
98
+ );
99
+ };
100
+ const handleInputLinkChange = (e, currentField) => {
101
+ setLinkValue(e.target.value);
102
+ handleOnDropdownChange(
103
+ null,
104
+ { value: getValues(currentField).states || [] },
105
+ currentField,
106
+ undefined,
107
+ undefined,
108
+ e.target.value,
109
+ );
110
+ };
111
+ const handleInputConditionChange = (e, currentField) => {
112
+ setConditionValue(e.target.value);
113
+ handleOnDropdownChange(
114
+ null,
115
+ { value: getValues(currentField).states || [] },
116
+ currentField,
117
+ undefined,
118
+ e.target.value,
119
+ );
100
120
  };
101
121
  return (
102
122
  <Segment
@@ -104,8 +124,8 @@ const EditDataComponent = ({
104
124
  width: '100%',
105
125
  paddingBottom:
106
126
  request?.data?.fieldsets[0]?.fields.length > 9 ? '120px' : '',
107
- maxHeight: COMPONENT_HEIGHT,
108
- overflow: request?.data?.fieldsets[0]?.fields.length > 9 ? 'auto' : '',
127
+ height: COMPONENT_HEIGHT,
128
+ overflow: 'auto',
109
129
  }}
110
130
  >
111
131
  <Accordion styled fluid>
@@ -114,8 +134,12 @@ const EditDataComponent = ({
114
134
  requestStateOptions?.loaded &&
115
135
  !requestStateOptions?.loading &&
116
136
  requestStateOptions?.data &&
117
- request?.data?.fieldsets[0]?.fields?.map((currentField, index) => {
118
- if (request.data.required.includes(currentField)) return null;
137
+ fields.map((currentField, index) => {
138
+ if (
139
+ request.data.required.includes(currentField) ||
140
+ getDropdownValues(currentField) === undefined
141
+ )
142
+ return null;
119
143
  return (
120
144
  <React.Fragment key={`${currentField}${index}`}>
121
145
  <Accordion.Title
@@ -126,31 +150,80 @@ const EditDataComponent = ({
126
150
  }
127
151
  id={`property_${currentField}`}
128
152
  >
129
- <Icon name="dropdown" />
130
- {currentField}
153
+ <div className="title-editing-progress">
154
+ <Icon name="dropdown" size="tiny" />
155
+ &nbsp;
156
+ {currentField}
157
+ </div>
158
+ <div className="title-editing-progress">
159
+ <Icon
160
+ name="cancel"
161
+ size="mini"
162
+ onClick={(e) => {
163
+ e.preventDefault();
164
+ handleOnDropdownChange(
165
+ e,
166
+ { value: undefined },
167
+ currentField,
168
+ );
169
+ }}
170
+ />
171
+ </div>
131
172
  </Accordion.Title>
132
173
  <Accordion.Content
133
174
  active={activeIndex === index}
134
175
  id={`property_content_${currentField}`}
135
176
  >
136
- <>
137
- <label
138
- htmlFor="message"
139
- style={{ display: 'block', padding: '10px' }}
140
- >
141
- Message
142
- </label>
143
- <input
144
- className="message-input"
145
- value={inputValue}
146
- onChange={(e) => handleInputChange(e, currentField)}
147
- // ref={inputRef}
148
- name="message"
149
- style={{ padding: '10px' }}
150
- disabled={getDropdownValues(currentField) == null}
151
- placeholder="Write a dfferent message after you set at lest one state"
152
- />
153
- </>
177
+ <label
178
+ htmlFor="message"
179
+ style={{ display: 'block', padding: '10px' }}
180
+ >
181
+ Message
182
+ </label>
183
+ <input
184
+ className="message-input"
185
+ value={inputValue}
186
+ onChange={(e) => handleInputChange(e, currentField)}
187
+ // ref={inputRef}
188
+ name="message"
189
+ style={{ padding: '10px' }}
190
+ disabled={getDropdownValues(currentField) == null}
191
+ placeholder="Write a dfferent message after you set at lest one state"
192
+ />
193
+ <label
194
+ htmlFor="message"
195
+ style={{ display: 'block', padding: '10px' }}
196
+ >
197
+ Link
198
+ </label>
199
+ <input
200
+ className="link-input"
201
+ value={linkValue}
202
+ onChange={(e) => handleInputLinkChange(e, currentField)}
203
+ // ref={inputRef}
204
+ name="link"
205
+ style={{ padding: '10px' }}
206
+ disabled={getDropdownValues(currentField) == null}
207
+ placeholder="Write a dfferent href link"
208
+ />
209
+ <label
210
+ htmlFor="condition"
211
+ style={{ display: 'block', padding: '10px' }}
212
+ >
213
+ Condition
214
+ </label>
215
+ <input
216
+ className="condition-input"
217
+ value={conditionValue}
218
+ onChange={(e) =>
219
+ handleInputConditionChange(e, currentField)
220
+ }
221
+ // ref={inputRef}
222
+ name="condition"
223
+ style={{ padding: '10px' }}
224
+ disabled={getDropdownValues(currentField) == null}
225
+ placeholder="Write a dfferent condition"
226
+ />
154
227
  <label
155
228
  htmlFor="dropdown"
156
229
  style={{ display: 'block', padding: '10px' }}
@@ -165,11 +238,13 @@ const EditDataComponent = ({
165
238
  search
166
239
  name="dropdown"
167
240
  defaultValue={getDropdownValues(currentField)}
168
- options={createStateOption(
169
- requestStateOptions.data.items.map(
170
- (option) => option.token,
241
+ options={[
242
+ ...createStateOption(
243
+ requestStateOptions.data.items.map(
244
+ (option) => option.token,
245
+ ),
171
246
  ),
172
- )}
247
+ ]}
173
248
  onChange={(e, data) =>
174
249
  handleOnDropdownChange(e, data, currentField)
175
250
  }
@@ -8,6 +8,15 @@
8
8
  }
9
9
  }
10
10
 
11
+ .dropdown-button {
12
+ background: grey;
13
+ color: #ffffff !important;
14
+
15
+ .divider.text {
16
+ color: #ffffff !important;
17
+ }
18
+ }
19
+
11
20
  .soft-required .wrapper {
12
21
  > label[for]::after,
13
22
  .ui.label::after {
@@ -27,6 +36,19 @@
27
36
  -webkit-animation: flash linear 1s 1s 1.5;
28
37
  animation: flash linear 1s 1s 1.5;
29
38
  }
39
+
40
+ .title-editing-progress {
41
+ display: inline-block;
42
+ font-size: 1.5rem !important;
43
+
44
+ .dropdown {
45
+ font-size: 1.5rem !important;
46
+ }
47
+
48
+ .cancel {
49
+ font-size: 1.5rem !important;
50
+ }
51
+ }
30
52
  @-webkit-keyframes flash {
31
53
  0% {
32
54
  opacity: 1;