@eeacms/volto-clms-theme 1.0.206 → 1.0.208

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,11 +4,19 @@ 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
- ### [1.0.206](https://github.com/eea/volto-clms-theme/compare/1.0.205...1.0.206) - 18 May 2023
7
+ ### [1.0.208](https://github.com/eea/volto-clms-theme/compare/1.0.207...1.0.208) - 19 May 2023
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - feat CLMS-2185 block chooser padding fix [Unai - [`2809c9f`](https://github.com/eea/volto-clms-theme/commit/2809c9ff01e6f9acd35f03c3f5aa903d689b4ed0)]
12
+ ### [1.0.207](https://github.com/eea/volto-clms-theme/compare/1.0.206...1.0.207) - 19 May 2023
8
13
 
9
14
  #### :hammer_and_wrench: Others
10
15
 
11
- - restore icon sizes [Mikel Larreategi - [`40d82cd`](https://github.com/eea/volto-clms-theme/commit/40d82cde432fc43a69f8e8acbfeb630fca88dbe3)]
16
+ - refactor FAQ block view. Small modification done for CclTabs to set active the second tab if the first is a parent tab [ionlizarazu - [`e79f44f`](https://github.com/eea/volto-clms-theme/commit/e79f44f93444fe38ce5209c94cfbc00775e5c124)]
17
+ - CLMS-2024 empty columns and export order for Downloadable File [ionlizarazu - [`4f289f8`](https://github.com/eea/volto-clms-theme/commit/4f289f87d1dd0b91102579ef1b4fcf7796aba801)]
18
+ ### [1.0.206](https://github.com/eea/volto-clms-theme/compare/1.0.205...1.0.206) - 18 May 2023
19
+
12
20
  ### [1.0.205](https://github.com/eea/volto-clms-theme/compare/1.0.204...1.0.205) - 17 May 2023
13
21
 
14
22
  ### [1.0.204](https://github.com/eea/volto-clms-theme/compare/1.0.203...1.0.204) - 17 May 2023
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-clms-theme",
3
- "version": "1.0.206",
3
+ "version": "1.0.208",
4
4
  "description": "volto-clms-theme: Volto theme for CLMS site",
5
5
  "main": "src/index.js",
6
6
  "author": "CodeSyntax for the European Environment Agency",
@@ -1,9 +1,9 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import AnimateHeight from 'react-animate-height';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
4
  import { Accordion, Segment } from 'semantic-ui-react';
5
5
 
6
- import { searchContent } from '@plone/volto/actions';
6
+ import { getContextNavigation } from '@plone/volto/actions';
7
7
  import { Icon, UniversalLink } from '@plone/volto/components';
8
8
  import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
9
9
  import { hasBlocksData } from '@plone/volto/helpers';
@@ -16,8 +16,8 @@ const CclFAQBlockView = (props) => {
16
16
  const { isEditMode } = props;
17
17
  const dispatch = useDispatch();
18
18
  const path = useSelector((state) => state.router.location.pathname);
19
- const search = useSelector((state) => state.search);
20
- const search_key = 'faq-block';
19
+ const contextNavigation = useSelector((state) => state.contextNavigation);
20
+ const cn_key = `${path.replace('/edit', '')}/@contextnavigation`;
21
21
  const handleClick = ({ index }) => {
22
22
  const newIndex =
23
23
  activeIndex.indexOf(index) === -1
@@ -26,181 +26,108 @@ const CclFAQBlockView = (props) => {
26
26
 
27
27
  setActiveIndex(newIndex);
28
28
  };
29
+
30
+ const flattenCN = (cn_items) => {
31
+ return cn_items.reduce((prev, curr) => {
32
+ prev.push(curr);
33
+ if (curr.items.filter((i) => i.type === 'document').length > 0) {
34
+ curr.items
35
+ .filter((i) => i.type === 'document')
36
+ .forEach((i_i) => prev.push({ ...i_i, isSubtab: true }));
37
+ }
38
+ return prev;
39
+ }, []);
40
+ };
41
+ const flatCN = flattenCN(
42
+ contextNavigation?.[cn_key]?.data?.items
43
+ ? contextNavigation?.[cn_key]?.data?.items.filter(
44
+ (i) => i.type === 'document',
45
+ )
46
+ : [],
47
+ );
48
+ const [activeIndex, setActiveIndex] = useState([0]);
29
49
  React.useEffect(() => {
30
- dispatch(
31
- searchContent(
32
- path.replace('/edit', ''),
33
- {
34
- fullobjects: 1,
35
- portal_type: 'FAQ',
36
- b_size: 999,
37
- sort_on: 'getObjPositionInParent',
38
- },
39
- search_key,
40
- ),
41
- );
50
+ dispatch(getContextNavigation(path.replace('/edit', '')));
42
51
  }, [path, dispatch]);
43
- React.useEffect(() => {
44
- if (search?.subrequests?.[search_key]?.loaded) {
45
- const firstOfCategories = categories.map((cat, key, self) => {
46
- const cat_indexes = search?.subrequests?.[search_key]?.items.reduce(
47
- (filtered, item, index) => {
48
- if (filtered.UID) {
49
- filtered = [];
50
- }
51
- if (
52
- item.taxonomy_faqcategories.filter(
53
- (item_cat) =>
54
- item_cat.title && item_cat.title.includes(cat.title),
55
- ).length > 0
56
- ) {
57
- if (index === 1) {
58
- filtered.push(0);
59
- } else {
60
- filtered.push(index);
61
- }
62
- }
63
- return filtered;
64
- },
65
- );
66
- return cat_indexes.length > 0 ? cat_indexes[0] : 0;
67
- });
68
- setActiveIndex(firstOfCategories);
69
- }
70
- // eslint-disable-next-line react-hooks/exhaustive-deps
71
- }, [search?.subrequests]);
72
- let categories =
73
- search?.subrequests &&
74
- search?.subrequests?.[search_key] &&
75
- search?.subrequests?.[search_key]?.loaded &&
76
- search?.subrequests?.[search_key]?.items.length > 0
77
- ? [
78
- ...new Set(
79
- search?.subrequests?.[search_key]?.items
80
- .map((item) => item.taxonomy_faqcategories)
81
- .flat(),
82
- ),
83
- ]
84
- .map((cat) => {
85
- if (cat.title) {
86
- const cat_family = cat.title?.split(' » ');
87
- if (cat_family && cat_family.length > 1) {
88
- cat['subTab'] = true;
89
- }
90
- }
91
- return cat;
92
- })
93
- .filter(
94
- (thing, index, self) =>
95
- index === self.findIndex((t) => t.token === thing.token),
96
- )
97
- .sort((a, b) => {
98
- if (a.title < b.title) {
99
- return -1;
100
- } else if (a.title > b.title) {
101
- return 1;
102
- }
103
- return 0;
104
- })
105
- : [];
106
- categories.forEach((cat, index) => {
107
- if (cat.subTab && !categories[index - 1].subTab) {
108
- categories[index - 1]['parent'] = true;
109
- }
110
- });
52
+
111
53
  const titleIcons = config.blocks?.blocksConfig?.accordion?.titleIcons;
112
54
 
113
- const [activeIndex, setActiveIndex] = React.useState([0]);
114
55
  return (
115
56
  <div id="faq-listing" className="ccl-container tab-container">
116
- {search?.subrequests?.[search_key]?.loaded ? (
117
- search?.subrequests?.[search_key]?.items?.length > 0 &&
118
- categories.length > 0 && (
57
+ {contextNavigation?.[cn_key]?.loaded ? (
58
+ contextNavigation?.[cn_key]?.data?.items?.length > 0 && (
119
59
  <CclTabs routing={true}>
120
- {categories.map((cat, key) => {
121
- let cat_title = '';
122
- let cat_family = [];
123
- if (cat.title) {
124
- cat_family = cat.title.split(' » ');
125
- cat_title =
126
- cat_family.length > 1
127
- ? cat_family[1].split('#')[1]
128
- : cat_family[0].split('#')[1];
129
- }
130
- return (
60
+ {flatCN
61
+ .filter((cn) => cn.type === 'document')
62
+ .map((cn, key) => (
131
63
  <div
132
64
  key={key}
133
- tabTitle={cat_title}
134
- className={cat_family.length > 1 ? 'subcard' : ''}
135
- parent={cat.parent}
65
+ tabTitle={cn.title}
66
+ className={
67
+ cn.isSubtab
68
+ ? 'subcard'
69
+ : cn.items.filter((i) => i.type === 'document').length > 0
70
+ }
71
+ parent={
72
+ cn.items.filter((i) => i.type === 'document').length > 0
73
+ }
136
74
  >
137
75
  <div className="accordion-block">
138
- {search?.subrequests?.[search_key]?.items.map(
139
- (item, item_key) => {
76
+ {cn.items
77
+ .filter((item) => item.type === 'faq')
78
+ .map((item, item_key) => {
140
79
  return (
141
- item.taxonomy_faqcategories.filter(
142
- (faq_cat) =>
143
- faq_cat.title &&
144
- faq_cat.title.includes(cat.title),
145
- ).length > 0 && (
146
- <Accordion fluid styled key={item_key}>
147
- <Accordion.Title
148
- as={'h2'}
149
- onClick={() => handleClick({ index: item_key })}
150
- className={'accordion-title align-arrow-right'}
151
- >
152
- {activeIndex.includes(item_key) ? (
153
- <Icon
154
- name={titleIcons.opened.rightPosition}
155
- />
156
- ) : (
80
+ <Accordion fluid styled key={item_key}>
81
+ <Accordion.Title
82
+ as={'h2'}
83
+ onClick={() => handleClick({ index: item_key })}
84
+ className={'accordion-title align-arrow-right'}
85
+ >
86
+ {activeIndex.includes(item_key) ? (
87
+ <Icon name={titleIcons.opened.rightPosition} />
88
+ ) : (
89
+ <Icon name={titleIcons.closed.rightPosition} />
90
+ )}
91
+ {isEditMode && (
92
+ <UniversalLink
93
+ openLinkInNewTab={true}
94
+ href={`${item['@id']}/edit`}
95
+ >
157
96
  <Icon
158
- name={titleIcons.closed.rightPosition}
97
+ name={penSVG}
98
+ className="circled"
99
+ title={'Edit'}
159
100
  />
160
- )}
161
- {isEditMode && (
162
- <UniversalLink
163
- openLinkInNewTab={true}
164
- href={`${item['@id']}/edit`}
165
- >
166
- <Icon
167
- name={penSVG}
168
- className="circled"
169
- title={'Edit'}
170
- />
171
- </UniversalLink>
172
- )}
173
- <span>{item.title}</span>
174
- </Accordion.Title>
175
- <Accordion.Content
176
- active={activeIndex.includes(item_key)}
101
+ </UniversalLink>
102
+ )}
103
+ <span>{item.title}</span>
104
+ </Accordion.Title>
105
+ <Accordion.Content
106
+ active={activeIndex.includes(item_key)}
107
+ >
108
+ <AnimateHeight
109
+ animateOpacity
110
+ duration={500}
111
+ height={'auto'}
177
112
  >
178
- <AnimateHeight
179
- animateOpacity
180
- duration={500}
181
- height={'auto'}
182
- >
183
- {/* <StringToHTML
113
+ {/* <StringToHTML
184
114
  string={item.text ? item.text.data : ''}
185
115
  /> */}
186
- {hasBlocksData(item) && (
187
- <RenderBlocks content={item} />
188
- )}
189
- </AnimateHeight>
190
- </Accordion.Content>
191
- </Accordion>
192
- )
116
+ {hasBlocksData(item) && (
117
+ <RenderBlocks content={item} />
118
+ )}
119
+ </AnimateHeight>
120
+ </Accordion.Content>
121
+ </Accordion>
193
122
  );
194
- },
195
- )}
123
+ })}
196
124
  </div>
197
125
  </div>
198
- );
199
- })}
126
+ ))}
200
127
  </CclTabs>
201
128
  )
202
129
  ) : (
203
- <Segment loading={search?.subrequests?.[search_key]?.loading}></Segment>
130
+ <Segment loading={contextNavigation?.[cn_key]?.loading}></Segment>
204
131
  )}
205
132
  </div>
206
133
  );
@@ -38,6 +38,16 @@ const CclTabs = (props) => {
38
38
  setActiveTab(slugify(firstTab.props?.tabTitle));
39
39
  } else if (hash) {
40
40
  setActiveTab(hash);
41
+ } else if (
42
+ children.filter((item) => !!item?.props?.tabTitle).length > 1 &&
43
+ firstTab.props?.parent
44
+ ) {
45
+ setActiveTab(
46
+ slugify(
47
+ children.filter((item) => !!item?.props?.tabTitle)[1].props
48
+ ?.tabTitle,
49
+ ),
50
+ );
41
51
  } else {
42
52
  setActiveTab(slugify(firstTab.props?.tabTitle));
43
53
  }
@@ -6,6 +6,41 @@ import CclButton from '../CclButton/CclButton';
6
6
  import { Segment, Loader, Header, Divider } from 'semantic-ui-react';
7
7
  import './DownloadableFilesTableWidget.less';
8
8
 
9
+ const orderKeysBy = (array, data) => {
10
+ if (data) {
11
+ return JSON.stringify(
12
+ array.reduce((obj, key) => {
13
+ obj[key] = data[key] || '';
14
+ return obj;
15
+ }, {}),
16
+ );
17
+ }
18
+ return {};
19
+ };
20
+ const deleteNotExistingColumnsData = (props, schema, uiSchema) => {
21
+ const { id, value } = props;
22
+ const validFields = ['@id', ...Object.keys(schema?.properties)];
23
+ for (let i in value?.items) {
24
+ Object.keys(value?.items[i]).forEach((k) => {
25
+ if (!validFields.includes(k)) {
26
+ delete value?.items[i][k];
27
+ }
28
+ });
29
+ }
30
+ props.onChange(id, {
31
+ items: value.items,
32
+ schema,
33
+ uiSchema,
34
+ });
35
+ };
36
+
37
+ const fixSchema = (schema) => {
38
+ schema.properties = Object.fromEntries(
39
+ Object.entries(schema.properties).filter(([k, v]) => v != null && k),
40
+ );
41
+ schema.fieldsets[0].fields = schema.fieldsets[0].fields.filter((f) => f);
42
+ };
43
+
9
44
  const DownloadableFilesTableWidget = (props) => {
10
45
  const { functions, data } = useSchema(
11
46
  props?.value?.schema,
@@ -15,30 +50,6 @@ const DownloadableFilesTableWidget = (props) => {
15
50
  const { setSchema, setUISchema, setSchemaHandler } = functions;
16
51
  const [edited, setEdited] = React.useState(false);
17
52
 
18
- const fixSchema = (schema) => {
19
- schema.properties = Object.fromEntries(
20
- Object.entries(schema.properties).filter(([k, v]) => v != null && k),
21
- );
22
- schema.fieldsets[0].fields = schema.fieldsets[0].fields.filter((f) => f);
23
- };
24
-
25
- const deleteNotExistingColumnsData = (props, schema) => {
26
- const { id, value } = props;
27
- const validFields = ['@id', ...Object.keys(schema?.properties)];
28
- for (let i in value?.items) {
29
- Object.keys(value?.items[i]).forEach((k) => {
30
- if (!validFields.includes(k)) {
31
- delete value?.items[i][k];
32
- }
33
- });
34
- }
35
- props.onChange(id, {
36
- items: value.items,
37
- ...props?.schema,
38
- ...props?.uiSchema,
39
- });
40
- };
41
-
42
53
  return (
43
54
  <>
44
55
  <div className="ui container">
@@ -93,15 +104,11 @@ const DownloadableFilesTableWidget = (props) => {
93
104
  setSchemaHandler(
94
105
  schema,
95
106
  uiSchema,
96
- (id, schema, uiSchema) =>
97
- props.onChange(id, {
98
- ...props.value,
99
- schema: schema,
100
- uiSchema: uiSchema,
101
- }),
107
+ props.onChange,
102
108
  props.id,
109
+ props.value,
103
110
  );
104
- deleteNotExistingColumnsData(props, schema);
111
+ deleteNotExistingColumnsData(props, schema, uiSchema);
105
112
  }}
106
113
  >
107
114
  APPLY MODIFIED SCHEMA
@@ -121,9 +128,22 @@ const DownloadableFilesTableWidget = (props) => {
121
128
  schema={schema}
122
129
  csvexport={true}
123
130
  csvimport={true}
124
- value={props.value?.items || props.default?.items || []}
131
+ value={
132
+ [
133
+ ...props.value?.items.map((i) =>
134
+ JSON.parse(orderKeysBy(['@id', ...uiSchema['ui:order']], i)),
135
+ ),
136
+ ] ||
137
+ props.default?.items ||
138
+ []
139
+ }
125
140
  onChange={(id, value) =>
126
- props.onChange(id, { ...props.value, items: value })
141
+ props.onChange(id, {
142
+ ...props.value,
143
+ items: value,
144
+ schema: schema,
145
+ uiSchema: uiSchema,
146
+ })
127
147
  }
128
148
  />
129
149
  )}
@@ -1,4 +1,5 @@
1
1
  import { useState } from 'react';
2
+
2
3
  export const useSchema = (baseSchema, baseUISchema) => {
3
4
  const [schema, setSchema] = useState(
4
5
  baseSchema || {
@@ -91,9 +92,8 @@ export const useSchema = (baseSchema, baseUISchema) => {
91
92
  },
92
93
  );
93
94
  const [ready, setReady] = useState(true);
94
- const setSchemaHandler = (schema, uiSchema, onChange, id) => {
95
+ const setSchemaHandler = (schema, uiSchema, onChange, id, value) => {
95
96
  setReady(false);
96
- // console.log('schema', schema);
97
97
  Object.keys(schema.properties).forEach((pr) => {
98
98
  //modify the Dropdown field type to make it compatible with Volto select
99
99
  if (schema.properties[pr].enum) {
@@ -104,8 +104,11 @@ export const useSchema = (baseSchema, baseUISchema) => {
104
104
  }
105
105
  });
106
106
  setSchema(schema);
107
- onChange(id, schema, uiSchema);
108
- // setTimeout(() => onChangeUi(id, uiSchema), 1500);
107
+ onChange(id, {
108
+ ...value,
109
+ schema: schema,
110
+ uiSchema: uiSchema,
111
+ });
109
112
  setTimeout(() => setReady(true), 1500);
110
113
  };
111
114
 
@@ -390,10 +390,8 @@ body:not(.is-authenticated):not(.document_wide_view).stretch {
390
390
  }
391
391
  }
392
392
 
393
- .tabs-block {
394
- .blocks-chooser {
395
- right: 0;
396
- left: auto !important;
397
- margin-top: 50px;
398
- }
393
+ .tabs-block .blocks-chooser {
394
+ right: 0;
395
+ left: auto !important;
396
+ margin-top: 50px;
399
397
  }