@plone/volto 17.0.0-alpha.0 → 17.0.0-alpha.10

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.
Files changed (190) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +451 -19
  3. package/CONTRIBUTING.md +1 -1
  4. package/README.md +12 -15
  5. package/addon-registry.js +34 -0
  6. package/create-theme-addons-loader.js +79 -0
  7. package/cypress/support/commands.js +25 -0
  8. package/locales/ca/LC_MESSAGES/volto.po +187 -6
  9. package/locales/ca.json +1 -1
  10. package/locales/de/LC_MESSAGES/volto.po +206 -25
  11. package/locales/de.json +1 -1
  12. package/locales/en/LC_MESSAGES/volto.po +186 -5
  13. package/locales/en.json +1 -1
  14. package/locales/es/LC_MESSAGES/volto.po +187 -6
  15. package/locales/es.json +1 -1
  16. package/locales/eu/LC_MESSAGES/volto.po +187 -6
  17. package/locales/eu.json +1 -1
  18. package/locales/fi/LC_MESSAGES/volto.po +4792 -0
  19. package/locales/fi.json +1 -1
  20. package/locales/fr/LC_MESSAGES/volto.po +187 -6
  21. package/locales/fr.json +1 -1
  22. package/locales/it/LC_MESSAGES/volto.po +187 -6
  23. package/locales/it.json +1 -1
  24. package/locales/ja/LC_MESSAGES/volto.po +187 -6
  25. package/locales/ja.json +1 -1
  26. package/locales/nl/LC_MESSAGES/volto.po +842 -649
  27. package/locales/nl.json +1 -1
  28. package/locales/pt/LC_MESSAGES/volto.po +187 -6
  29. package/locales/pt.json +1 -1
  30. package/locales/pt_BR/LC_MESSAGES/volto.po +195 -14
  31. package/locales/pt_BR.json +1 -1
  32. package/locales/ro/LC_MESSAGES/volto.po +187 -6
  33. package/locales/ro.json +1 -1
  34. package/locales/volto.pot +187 -6
  35. package/locales/zh_CN/LC_MESSAGES/volto.po +187 -6
  36. package/locales/zh_CN.json +1 -1
  37. package/package-why.json +0 -1
  38. package/package.json +9 -8
  39. package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +1 -1
  40. package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +1 -1
  41. package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +1 -1
  42. package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +1 -1
  43. package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +1 -1
  44. package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +1 -1
  45. package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +1 -1
  46. package/packages/volto-slate/build/messages/src/elementEditor/messages.json +1 -1
  47. package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +1 -1
  48. package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +1 -1
  49. package/packages/volto-slate/package.json +1 -1
  50. package/packages/volto-slate/src/blocks/Table/TableBlockView.jsx +4 -4
  51. package/packages/volto-slate/src/blocks/Table/index.js +2 -0
  52. package/packages/volto-slate/src/blocks/Text/SlashMenu.jsx +4 -3
  53. package/packages/volto-slate/src/editor/deserialize.js +0 -1
  54. package/packages/volto-slate/src/editor/plugins/StyleMenu/StyleMenu.jsx +14 -4
  55. package/razzle.config.js +28 -0
  56. package/src/actions/index.js +6 -0
  57. package/src/actions/language/language.js +9 -8
  58. package/src/actions/querystringsearch/querystringsearch.js +20 -14
  59. package/src/actions/relations/rebuild.js +25 -0
  60. package/src/actions/relations/relations.js +86 -0
  61. package/src/actions/relations/relations.test.js +15 -0
  62. package/src/components/index.js +1 -0
  63. package/src/components/manage/Add/Add.jsx +2 -2
  64. package/src/components/manage/BlockChooser/BlockChooser.jsx +14 -5
  65. package/src/components/manage/BlockChooser/BlockChooser.test.jsx +5 -0
  66. package/src/components/manage/BlockChooser/BlockChooserButton.jsx +63 -29
  67. package/src/components/manage/BlockChooser/BlockChooserSearch.jsx +0 -1
  68. package/src/components/manage/Blocks/Listing/Edit.jsx +0 -19
  69. package/src/components/manage/Blocks/Listing/ListingBody.jsx +77 -61
  70. package/src/components/manage/Blocks/Listing/View.jsx +0 -4
  71. package/src/components/manage/Blocks/Listing/getAsyncData.js +10 -2
  72. package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -13
  73. package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +5 -4
  74. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +2 -1
  75. package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
  76. package/src/components/manage/Blocks/Search/components/Facets.jsx +58 -2
  77. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +24 -11
  78. package/src/components/manage/Blocks/Search/layout/LeftColumnFacets.jsx +17 -5
  79. package/src/components/manage/Blocks/Search/layout/RightColumnFacets.jsx +17 -5
  80. package/src/components/manage/Blocks/Search/layout/TopSideFacets.jsx +21 -5
  81. package/src/components/manage/Blocks/Search/schema.js +16 -1
  82. package/src/components/manage/Blocks/ToC/Edit.jsx +1 -0
  83. package/src/components/manage/Contents/Contents.jsx +69 -33
  84. package/src/components/manage/Contents/ContentsItem.jsx +6 -0
  85. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +3 -3
  86. package/src/components/manage/Controlpanels/Controlpanels.jsx +199 -224
  87. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
  88. package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +66 -0
  89. package/src/components/manage/Controlpanels/Relations/Relations.jsx +114 -0
  90. package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +479 -0
  91. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +531 -0
  92. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.jsx +3 -3
  93. package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +51 -82
  94. package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +79 -75
  95. package/src/components/manage/DragDropList/DragDropList.jsx +63 -42
  96. package/src/components/manage/Form/BlocksToolbar.jsx +5 -1
  97. package/src/components/manage/Form/Form.jsx +11 -5
  98. package/src/components/manage/Form/InlineForm.jsx +39 -9
  99. package/src/components/manage/Form/InlineFormState.js +8 -0
  100. package/src/components/manage/History/History.jsx +35 -18
  101. package/src/components/manage/Multilingual/CreateTranslation.jsx +2 -2
  102. package/src/components/manage/Multilingual/TranslationObject.jsx +4 -3
  103. package/src/components/manage/Preferences/ChangePassword.jsx +2 -2
  104. package/src/components/manage/Preferences/PersonalPreferences.jsx +2 -2
  105. package/src/components/manage/Toast/Toast.jsx +1 -1
  106. package/src/components/manage/Toolbar/Types.jsx +2 -2
  107. package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
  108. package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
  109. package/src/components/manage/Widgets/RecurrenceWidget/ByDayField.jsx +2 -1
  110. package/src/components/manage/Widgets/RecurrenceWidget/MonthOfTheYearField.jsx +2 -1
  111. package/src/components/manage/Widgets/RecurrenceWidget/Occurences.jsx +2 -1
  112. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +7 -2
  113. package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthField.jsx +2 -1
  114. package/src/components/manage/Widgets/SelectUtils.js +1 -1
  115. package/src/components/manage/Widgets/SelectWidget.jsx +1 -1
  116. package/src/components/theme/Footer/Footer.jsx +2 -13
  117. package/src/components/theme/Header/Header.jsx +37 -63
  118. package/src/components/theme/Header/Header.test.jsx +18 -0
  119. package/src/components/theme/Icon/Icon.jsx +2 -2
  120. package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
  121. package/src/components/theme/Login/Login.jsx +1 -0
  122. package/src/components/theme/Logo/Logo.jsx +2 -1
  123. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +2 -2
  124. package/src/components/theme/Navigation/NavItem.jsx +4 -2
  125. package/src/components/theme/NotFound/NotFound.jsx +55 -41
  126. package/src/components/theme/PasswordReset/PasswordReset.jsx +7 -4
  127. package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +1 -1
  128. package/src/components/theme/Sitemap/Sitemap.jsx +5 -3
  129. package/src/components/theme/View/DefaultView.jsx +1 -1
  130. package/src/components/theme/View/EventDatesInfo.jsx +2 -1
  131. package/src/components/theme/View/EventView.jsx +1 -1
  132. package/src/components/theme/View/NewsItemView.jsx +1 -1
  133. package/src/components/theme/View/RenderBlocks.jsx +7 -1
  134. package/src/components/theme/Widgets/DateWidget.jsx +2 -1
  135. package/src/components/theme/Widgets/DatetimeWidget.jsx +2 -1
  136. package/src/components/theme/Widgets/RelationsWidget.jsx +13 -11
  137. package/src/config/ControlPanels.js +2 -0
  138. package/src/config/Widgets.jsx +1 -0
  139. package/src/config/index.js +3 -0
  140. package/src/config/server.js +19 -0
  141. package/src/constants/ActionTypes.js +4 -0
  142. package/src/constants/Languages.js +8 -4
  143. package/src/express-middleware/devproxy.js +4 -2
  144. package/src/express-middleware/sitemap.js +36 -4
  145. package/src/express-middleware/static.js +32 -0
  146. package/src/helpers/Api/Api.js +1 -1
  147. package/src/helpers/FormValidation/FormValidation.js +11 -2
  148. package/src/helpers/FormValidation/FormValidation.test.js +73 -0
  149. package/src/helpers/Html/Html.jsx +3 -1
  150. package/src/helpers/Html/Html.test.jsx +5 -0
  151. package/src/helpers/MessageLabels/MessageLabels.js +72 -0
  152. package/src/helpers/Robots/Robots.js +24 -6
  153. package/src/helpers/Sitemap/Sitemap.js +44 -2
  154. package/src/helpers/Url/Url.js +27 -6
  155. package/src/helpers/Url/Url.test.js +26 -0
  156. package/src/helpers/Utils/Utils.js +38 -13
  157. package/src/helpers/Utils/Utils.test.js +4 -4
  158. package/src/helpers/index.js +7 -2
  159. package/src/hooks/userSession/useToken.js +5 -0
  160. package/src/middleware/Api.test.js +54 -0
  161. package/src/middleware/api.js +8 -4
  162. package/src/reducers/actions/actions.js +1 -1
  163. package/src/reducers/breadcrumbs/breadcrumbs.js +1 -1
  164. package/src/reducers/index.js +2 -0
  165. package/src/reducers/navigation/navigation.js +1 -1
  166. package/src/reducers/relations/relations.js +173 -0
  167. package/src/reducers/types/types.js +1 -1
  168. package/src/routes.js +5 -0
  169. package/src/server.jsx +29 -30
  170. package/src/start-server.js +4 -2
  171. package/test-setup-config.js +1 -0
  172. package/theme/themes/pastanaga/extras/blocks.less +0 -9
  173. package/theme/themes/pastanaga/extras/contents.less +1 -0
  174. package/theme/themes/pastanaga/extras/main.less +80 -1
  175. package/theme/themes/pastanaga/extras/search.less +6 -0
  176. package/theme/themes/pastanaga/extras/sidebar.less +4 -0
  177. package/theme/themes/pastanaga/extras/userscontrolpanel.less +99 -76
  178. package/.changelog.draft +0 -22
  179. package/.editorconfig +0 -36
  180. package/.storybook/main.js +0 -127
  181. package/.storybook/manager.js +0 -15
  182. package/.storybook/preview.js +0 -21
  183. package/.storybook/static/previewImage.svg +0 -48
  184. package/.yarnrc.yml +0 -5
  185. package/jsdoc.json +0 -16
  186. package/netlify.toml +0 -5
  187. package/pyvenv.cfg +0 -3
  188. package/share/man/man1/ttx.1 +0 -225
  189. package/src/components/theme/Header/Header.md +0 -27
  190. package/towncrier.toml +0 -33
@@ -9,8 +9,6 @@ import { listGroups } from '@plone/volto/actions';
9
9
  import { Icon, Toast } from '@plone/volto/components';
10
10
  import { updateGroup, listUsers } from '@plone/volto/actions';
11
11
 
12
- import add from '@plone/volto/icons/add.svg';
13
- import remove from '@plone/volto/icons/remove.svg';
14
12
  import down_key from '@plone/volto/icons/down-key.svg';
15
13
 
16
14
  const ListingTemplate = ({
@@ -116,7 +114,7 @@ const ListingTemplate = ({
116
114
  }
117
115
  }, [dispatch, query_group, show_matrix_options, groups_filter]);
118
116
 
119
- const onSelectOptionHandler = (item, selectedvalue, checked, singleClick) => {
117
+ const onSelectOptionHandler = (selectedvalue, checked, singleClick) => {
120
118
  singleClick = singleClick ?? false;
121
119
  let group = selectedvalue.y;
122
120
  let username = selectedvalue.x;
@@ -150,17 +148,14 @@ const ListingTemplate = ({
150
148
  });
151
149
  };
152
150
 
153
- const onSelectAllHandler = (mtxoption, checked) => {
154
- let elements = document.querySelectorAll(`div.checkbox_${mtxoption} input`);
155
- let identifier;
151
+ const onSelectAllHandler = (group, items_ids, checked) => {
156
152
  let usersgroupmapping = {};
157
- elements.forEach((element) => {
158
- identifier = element.name.split('_-_');
159
- usersgroupmapping[identifier[1]] = checked ? true : false;
153
+ items_ids.forEach((el) => {
154
+ usersgroupmapping[el] = checked ? true : false;
160
155
  });
161
156
 
162
157
  dispatch(
163
- updateGroup(identifier[2], {
158
+ updateGroup(group, {
164
159
  users: usersgroupmapping,
165
160
  }),
166
161
  )
@@ -188,93 +183,68 @@ const ListingTemplate = ({
188
183
  <div className="administration_matrix">
189
184
  {matrix_options && matrix_options?.length > 0 && (
190
185
  <div className="label-options">
191
- {matrix_options?.map((matrix_option) => (
192
- <div
193
- className="label-options-label inclined"
194
- key={matrix_option.value}
195
- >
196
- <div>
197
- <span className="label">{matrix_option.label}</span>
186
+ <div className="target-labels">
187
+ <div>
188
+ <h3>{items.length} users</h3>
189
+ </div>
190
+ <div>
191
+ {matrix_options?.map((matrix_option) => (
192
+ <div
193
+ className="label-options-label inclined"
194
+ key={matrix_option.value}
195
+ >
196
+ <div>
197
+ <span className="label">{matrix_option.label}</span>
198
+ </div>
199
+ </div>
200
+ ))}
201
+ </div>
202
+ </div>
203
+ <div className="listing-row selectall" key="selectall">
204
+ <div className="listing-item">
205
+ <div />
206
+ <div className="matrix_options">
207
+ {matrix_options?.map((matrix_option) => (
208
+ <div key={matrix_option.value}>
209
+ <Checkbox
210
+ className="toggle-target"
211
+ defaultChecked={false}
212
+ onChange={(event, { checked }) =>
213
+ onSelectAllHandler(
214
+ matrix_option.value,
215
+ items.map((el) => el.id),
216
+ checked,
217
+ )
218
+ }
219
+ />
220
+ </div>
221
+ ))}
198
222
  </div>
199
223
  </div>
200
- ))}
224
+ </div>
201
225
  </div>
202
226
  )}
203
227
 
204
228
  <div className="items">
205
229
  {items.length > 0 ? (
206
230
  <>
207
- <div className="listing-row selectall" key="selectall">
208
- <div className="listing-item">
209
- <div />
210
- <div className="matrix_options">
211
- {matrix_options?.map((matrix_option) => (
212
- <div key={matrix_option.value}>
213
- <Button
214
- icon
215
- basic
216
- onClick={() =>
217
- onSelectAllHandler(matrix_option.value, true)
218
- }
219
- className="add-button"
220
- aria-label={
221
- intl.formatMessage(messages.addUsersToGroup) +
222
- ` ${matrix_option.label}`
223
- }
224
- title={
225
- intl.formatMessage(messages.addUsersToGroup) +
226
- ` ${matrix_option.label}`
227
- }
228
- >
229
- <Icon
230
- name={add}
231
- size="10px"
232
- className="circled"
233
- color="unset"
234
- />
235
- </Button>
236
- <Button
237
- icon
238
- basic
239
- onClick={() =>
240
- onSelectAllHandler(matrix_option.value, false)
241
- }
242
- className="remove-button"
243
- aria-label={
244
- intl.formatMessage(messages.removeUsersFromGroup) +
245
- ` ${matrix_option.label}`
246
- }
247
- title={
248
- intl.formatMessage(messages.removeUsersFromGroup) +
249
- ` ${matrix_option.label}`
250
- }
251
- >
252
- <Icon
253
- name={remove}
254
- size="10px"
255
- className="circled"
256
- color="unset"
257
- />
258
- </Button>
259
- </div>
260
- ))}
261
- </div>
262
- </div>
263
- </div>
264
-
265
- <h3>{items.length} users </h3>
266
231
  {items.map((item) => (
267
- <div className="listing-row" key={item.id}>
232
+ <div
233
+ className="listing-row"
234
+ key={item.id}
235
+ id={`source-row-${item.id}`}
236
+ >
268
237
  <div className="listing-item" key={item['@id']}>
269
238
  <div>
270
- <h4>
271
- {item.fullname} ({item.id})
239
+ <h4 title={`${item.fullname} ${item.id}`}>
240
+ {item.fullname?.length > 25
241
+ ? item.fullname.slice(0, 22) + '...'
242
+ : item.fullname || item.id}
272
243
  </h4>
273
244
  </div>
274
245
  <div className="matrix_options">
275
246
  {matrix_options?.map((matrix_option) => (
276
247
  <Checkbox
277
- name={`member_-_${item.id}_-_${matrix_option.value}`}
278
248
  className={`checkbox_${matrix_option.value}`}
279
249
  key={matrix_option.value}
280
250
  title={matrix_option.title}
@@ -283,7 +253,6 @@ const ListingTemplate = ({
283
253
  .includes(matrix_option.value)}
284
254
  onChange={(event, { checked }) => {
285
255
  onSelectOptionHandler(
286
- item,
287
256
  { y: matrix_option.value, x: item.id },
288
257
  checked,
289
258
  true,
@@ -122,83 +122,87 @@ const UserGroupMembershipMatrix = ({ many_users, many_groups }) => {
122
122
 
123
123
  return (
124
124
  <div className="controlpanel_matrix">
125
- <div className="controlpanel_search_y">
126
- <Form className="search_users" onSubmit={onReset}>
127
- <Form.Field>
128
- <Input
129
- name="SearchUser"
130
- action={{ icon: 'delete' }}
131
- placeholder={intl.formatMessage(messages.searchUsers)}
132
- onChange={onChangeSearchUsers}
133
- onKeyDown={onChangeSearchUsers}
134
- id="user-search-input"
135
- />
136
- </Form.Field>
137
- </Form>
125
+ <div className="controlpanel_search_wrapper">
126
+ <div className="controlpanel_search_y">
127
+ <Form className="search_users" onSubmit={onReset}>
128
+ <Form.Field>
129
+ <Input
130
+ name="SearchUser"
131
+ action={{ icon: 'delete' }}
132
+ placeholder={intl.formatMessage(messages.searchUsers)}
133
+ onChange={onChangeSearchUsers}
134
+ onKeyDown={onChangeSearchUsers}
135
+ id="user-search-input"
136
+ />
137
+ </Form.Field>
138
+ </Form>
139
+ </div>
140
+ <div className="controlpanel_search_x">
141
+ <Form className="search_groups" onSubmit={onReset}>
142
+ <Form.Field>
143
+ <Input
144
+ name="SearchGroup"
145
+ action={{ icon: 'delete' }}
146
+ placeholder={intl.formatMessage(messages.searchGroups)}
147
+ onChange={onChangeSearchGroups}
148
+ onKeyDown={onChangeSearchGroups}
149
+ id="group-search-input"
150
+ />
151
+ </Form.Field>
152
+ <Form.Field>
153
+ <Checkbox
154
+ name="addJoinedGroups"
155
+ label={intl.formatMessage(messages.addJoinedGroups)}
156
+ title={intl.formatMessage(messages.addJoinedGroups)}
157
+ defaultChecked={false}
158
+ onChange={(event, { checked }) => {
159
+ onToggleJoinedGroups(checked);
160
+ }}
161
+ />
162
+ </Form.Field>
163
+ </Form>
164
+ </div>
138
165
  </div>
139
- <div className="controlpanel_search_x">
140
- <Form className="search_groups" onSubmit={onReset}>
141
- <Form.Field>
142
- <Input
143
- name="SearchGroup"
144
- action={{ icon: 'delete' }}
145
- placeholder={intl.formatMessage(messages.searchGroups)}
146
- onChange={onChangeSearchGroups}
147
- onKeyDown={onChangeSearchGroups}
148
- id="group-search-input"
149
- />
150
- </Form.Field>
151
- <Form.Field>
152
- <Checkbox
153
- name="addJoinedGroups"
154
- label={intl.formatMessage(messages.addJoinedGroups)}
155
- title={intl.formatMessage(messages.addJoinedGroups)}
156
- defaultChecked={false}
157
- onChange={(event, { checked }) => {
158
- onToggleJoinedGroups(checked);
159
- }}
160
- />
161
- </Form.Field>
162
- </Form>
166
+ <div className="controlpanel_listing_wrapper">
167
+ <div className="controlpanel_filter">
168
+ <h3>{intl.formatMessage(messages.filterByGroups)}</h3>
169
+ <Form className="search_filter_groups" onSubmit={onReset}>
170
+ <Form.Field>
171
+ <Input
172
+ name="SearchGroupFilter"
173
+ action={{ icon: 'delete' }}
174
+ placeholder={intl.formatMessage(messages.searchGroups)}
175
+ onChange={onChangeSearchGroupsFilter}
176
+ onKeyDown={onChangeSearchGroupsFilter}
177
+ id="groupfilter-search-input"
178
+ />
179
+ </Form.Field>
180
+ </Form>
181
+ {(!many_groups || query_group_filter.length > 1) &&
182
+ filter_options?.map((filter_option) => (
183
+ <Form.Field>
184
+ <Checkbox
185
+ name={`filter_option_${filter_option.value}`}
186
+ key={filter_option.value}
187
+ title={filter_option.label}
188
+ label={filter_option.label}
189
+ defaultChecked={false}
190
+ onChange={(event, { checked }) => {
191
+ onSelectOptionHandler(filter_option, checked);
192
+ }}
193
+ />
194
+ </Form.Field>
195
+ ))}
196
+ </div>
197
+ <UserGroupMembershipListing
198
+ query_user={query_user}
199
+ query_group={query_group}
200
+ groups_filter={groups_filter}
201
+ add_joined_groups={add_joined_groups}
202
+ many_users={many_users}
203
+ many_groups={many_groups}
204
+ />
163
205
  </div>
164
- <div className="controlpanel_filter">
165
- <h3>{intl.formatMessage(messages.filterByGroups)}</h3>
166
-
167
- <Form className="search_filter_groups" onSubmit={onReset}>
168
- <Form.Field>
169
- <Input
170
- name="SearchGroupFilter"
171
- action={{ icon: 'delete' }}
172
- placeholder={intl.formatMessage(messages.searchGroups)}
173
- onChange={onChangeSearchGroupsFilter}
174
- onKeyDown={onChangeSearchGroupsFilter}
175
- id="groupfilter-search-input"
176
- />
177
- </Form.Field>
178
- </Form>
179
-
180
- {(!many_groups || query_group_filter.length > 1) &&
181
- filter_options?.map((filter_option) => (
182
- <Checkbox
183
- name={`filter_option_${filter_option.value}`}
184
- key={filter_option.value}
185
- title={filter_option.label}
186
- label={filter_option.label}
187
- defaultChecked={false}
188
- onChange={(event, { checked }) => {
189
- onSelectOptionHandler(filter_option, checked);
190
- }}
191
- />
192
- ))}
193
- </div>
194
- <UserGroupMembershipListing
195
- query_user={query_user}
196
- query_group={query_group}
197
- groups_filter={groups_filter}
198
- add_joined_groups={add_joined_groups}
199
- many_users={many_users}
200
- many_groups={many_groups}
201
- />
202
206
  </div>
203
207
  );
204
208
  };
@@ -3,7 +3,7 @@ import { isEmpty } from 'lodash';
3
3
  import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
4
4
  import { v4 as uuid } from 'uuid';
5
5
 
6
- const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => {
6
+ const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex, uid) => {
7
7
  // Because of the margin rendering rules, there is no easy
8
8
  // way to calculate the offset of the placeholder.
9
9
  //
@@ -13,12 +13,16 @@ const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => {
13
13
  //
14
14
  // To get a placeholder that looks good in all cases, we
15
15
  // fill up the space between the previous and the next element.
16
- const childrenArray = [...draggedDOM.parentNode.children];
16
+ const queryAttr = 'data-rbd-droppable-id';
17
+ const domQuery = `[${queryAttr}='${uid}']`;
18
+ const parentDOM = document.querySelector(domQuery);
19
+
20
+ const childrenArray = [...parentDOM.children];
17
21
  // Remove the source element
18
22
  childrenArray.splice(sourceIndex, 1);
19
23
  // Also remove the placeholder that the library always inserts at the end
20
24
  childrenArray.splice(-1, 1);
21
- const parentRect = draggedDOM.parentNode.getBoundingClientRect();
25
+ const parentRect = parentDOM.getBoundingClientRect();
22
26
  const prevNode = childrenArray[destinationIndex - 1];
23
27
  const nextNode = childrenArray[destinationIndex];
24
28
  let top, bottom;
@@ -40,9 +44,7 @@ const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => {
40
44
  return {
41
45
  clientY: top,
42
46
  clientHeight: bottom - top,
43
- clientX: parseFloat(
44
- window.getComputedStyle(draggedDOM.parentNode).paddingLeft,
45
- ),
47
+ clientX: parseFloat(window.getComputedStyle(parentDOM).paddingLeft),
46
48
  clientWidth: draggedDOM.clientWidth,
47
49
  };
48
50
  };
@@ -63,17 +65,22 @@ const DragDropList = (props) => {
63
65
  // queueing timed action
64
66
  const timer = useRef(null);
65
67
 
66
- const onDragStart = React.useCallback((event) => {
67
- clearTimeout(timer.current);
68
- const queryAttr = 'data-rbd-draggable-id';
69
- const domQuery = `[${queryAttr}='${event.draggableId}']`;
70
- const draggedDOM = document.querySelector(domQuery);
71
- if (!draggedDOM) {
72
- return;
73
- }
74
- const sourceIndex = event.source.index;
75
- setPlaceholderProps(getPlaceholder(draggedDOM, sourceIndex, sourceIndex));
76
- }, []);
68
+ const onDragStart = React.useCallback(
69
+ (event) => {
70
+ clearTimeout(timer.current);
71
+ const queryAttr = 'data-rbd-draggable-id';
72
+ const domQuery = `[${queryAttr}='${event.draggableId}']`;
73
+ const draggedDOM = document.querySelector(domQuery);
74
+ if (!draggedDOM) {
75
+ return;
76
+ }
77
+ const sourceIndex = event.source.index;
78
+ setPlaceholderProps(
79
+ getPlaceholder(draggedDOM, sourceIndex, sourceIndex, uid),
80
+ );
81
+ },
82
+ [uid],
83
+ );
77
84
 
78
85
  const onDragEnd = React.useCallback(
79
86
  (result) => {
@@ -84,30 +91,33 @@ const DragDropList = (props) => {
84
91
  [onMoveItem],
85
92
  );
86
93
 
87
- const onDragUpdate = React.useCallback((update) => {
88
- clearTimeout(timer.current);
89
- setPlaceholderProps({});
90
- if (!update.destination) {
91
- return;
92
- }
93
- const draggableId = update.draggableId;
94
- const queryAttr = 'data-rbd-draggable-id';
95
- const domQuery = `[${queryAttr}='${draggableId}']`;
96
- const draggedDOM = document.querySelector(domQuery);
97
- if (!draggedDOM) {
98
- return;
99
- }
100
- const sourceIndex = update.source.index;
101
- const destinationIndex = update.destination.index;
102
- // Wait until the animations have finished, to make it look good.
103
- timer.current = setTimeout(
104
- () =>
105
- setPlaceholderProps(
106
- getPlaceholder(draggedDOM, sourceIndex, destinationIndex),
107
- ),
108
- 250,
109
- );
110
- }, []);
94
+ const onDragUpdate = React.useCallback(
95
+ (update) => {
96
+ clearTimeout(timer.current);
97
+ setPlaceholderProps({});
98
+ if (!update.destination) {
99
+ return;
100
+ }
101
+ const draggableId = update.draggableId;
102
+ const queryAttr = 'data-rbd-draggable-id';
103
+ const domQuery = `[${queryAttr}='${draggableId}']`;
104
+ const draggedDOM = document.querySelector(domQuery);
105
+ if (!draggedDOM) {
106
+ return;
107
+ }
108
+ const sourceIndex = update.source.index;
109
+ const destinationIndex = update.destination.index;
110
+ // Wait until the animations have finished, to make it look good.
111
+ timer.current = setTimeout(
112
+ () =>
113
+ setPlaceholderProps(
114
+ getPlaceholder(draggedDOM, sourceIndex, destinationIndex, uid),
115
+ ),
116
+ 250,
117
+ );
118
+ },
119
+ [uid],
120
+ );
111
121
 
112
122
  const AsDomComponent = as;
113
123
  return (
@@ -116,7 +126,18 @@ const DragDropList = (props) => {
116
126
  onDragUpdate={onDragUpdate}
117
127
  onDragEnd={onDragEnd}
118
128
  >
119
- <Droppable droppableId={uid}>
129
+ <Droppable
130
+ droppableId={uid}
131
+ renderClone={(provided, snapshot, rubric) => {
132
+ const index = rubric.source.index;
133
+ return children({
134
+ child: childList[index][1],
135
+ childId: childList[index][0],
136
+ index,
137
+ draginfo: provided,
138
+ });
139
+ }}
140
+ >
120
141
  {(provided, snapshot) => (
121
142
  <AsDomComponent
122
143
  ref={provided.innerRef}
@@ -177,7 +177,11 @@ export class BlocksToolbarComponent extends React.Component {
177
177
  ''
178
178
  )}
179
179
  {selectedBlock && (blocksClipboard?.cut || blocksClipboard?.copy) && (
180
- <Plug pluggable="main.toolbar.bottom" id="block-paste-btn">
180
+ <Plug
181
+ pluggable="main.toolbar.bottom"
182
+ id="block-paste-btn"
183
+ dependencies={[selectedBlock]}
184
+ >
181
185
  <button
182
186
  aria-label={intl.formatMessage(messages.pasteBlocks)}
183
187
  onClick={this.pasteBlocks}
@@ -31,7 +31,7 @@ import { Portal } from 'react-portal';
31
31
  import { connect } from 'react-redux';
32
32
  import {
33
33
  Button,
34
- Container,
34
+ Container as SemanticContainer,
35
35
  Form as UiForm,
36
36
  Message,
37
37
  Segment,
@@ -258,7 +258,11 @@ class Form extends Component {
258
258
  * Tab selection is done only by setting activeIndex in state
259
259
  */
260
260
  onTabChange(e, { activeIndex }) {
261
- this.setState({ activeIndex });
261
+ const defaultFocus = this.props.schema.fieldsets[activeIndex].fields[0];
262
+ this.setState({
263
+ activeIndex,
264
+ ...(defaultFocus ? { inFocus: { [defaultFocus]: true } } : {}),
265
+ });
262
266
  }
263
267
 
264
268
  /**
@@ -541,12 +545,14 @@ class Form extends Component {
541
545
  const { schema: originalSchema, onCancel, onSubmit } = this.props;
542
546
  const { formData } = this.state;
543
547
  const schema = this.removeBlocksLayoutFields(originalSchema);
548
+ const Container =
549
+ config.getComponent({ name: 'Container' }).component || SemanticContainer;
544
550
 
545
551
  return this.props.visual ? (
546
552
  // Removing this from SSR is important, since react-beautiful-dnd supports SSR,
547
553
  // but draftJS don't like it much and the hydration gets messed up
548
554
  this.state.isClient && (
549
- <div className="ui container">
555
+ <Container>
550
556
  <BlocksToolbar
551
557
  formData={this.state.formData}
552
558
  selectedBlock={this.state.selected}
@@ -635,7 +641,7 @@ class Form extends Component {
635
641
  </UiForm>
636
642
  </Portal>
637
643
  )}
638
- </div>
644
+ </Container>
639
645
  )
640
646
  ) : (
641
647
  <Container>
@@ -686,7 +692,7 @@ class Form extends Component {
686
692
  id={field}
687
693
  formData={this.state.formData}
688
694
  fieldSet={item.title.toLowerCase()}
689
- focus={index === 0}
695
+ focus={this.state.inFocus[field]}
690
696
  value={this.state.formData?.[field]}
691
697
  required={schema.required.indexOf(field) !== -1}
692
698
  onChange={this.onChangeField}
@@ -4,13 +4,21 @@ import { Accordion, Segment, Message } from 'semantic-ui-react';
4
4
  import { defineMessages, injectIntl } from 'react-intl';
5
5
  import AnimateHeight from 'react-animate-height';
6
6
  import { keys, map, isEqual } from 'lodash';
7
-
7
+ import { useAtom } from 'jotai';
8
+ import { inlineFormFieldsetsState } from './InlineFormState';
9
+ import {
10
+ insertInArray,
11
+ removeFromArray,
12
+ arrayRange,
13
+ } from '@plone/volto/helpers/Utils/Utils';
8
14
  import { Field, Icon } from '@plone/volto/components';
9
15
  import { applySchemaDefaults } from '@plone/volto/helpers';
10
16
 
11
17
  import upSVG from '@plone/volto/icons/up-key.svg';
12
18
  import downSVG from '@plone/volto/icons/down-key.svg';
13
19
 
20
+ import config from '@plone/volto/registry';
21
+
14
22
  const messages = defineMessages({
15
23
  editValues: {
16
24
  id: 'Edit values',
@@ -70,12 +78,34 @@ const InlineForm = (props) => {
70
78
  // eslint-disable-next-line react-hooks/exhaustive-deps
71
79
  }, []);
72
80
 
73
- const [currentActiveFieldset, setCurrentActiveFieldset] = React.useState(0);
81
+ const [currentActiveFieldset, setCurrentActiveFieldset] = useAtom(
82
+ inlineFormFieldsetsState({
83
+ name: block,
84
+ fielsetList: other,
85
+ initialState: config.settings.blockSettingsTabFieldsetsInitialStateOpen
86
+ ? arrayRange(0, other.length - 1, 1)
87
+ : [],
88
+ }),
89
+ );
90
+
74
91
  function handleCurrentActiveFieldset(e, blockProps) {
75
92
  const { index } = blockProps;
76
- const newIndex = currentActiveFieldset === index ? -1 : index;
77
-
78
- setCurrentActiveFieldset(newIndex);
93
+ if (currentActiveFieldset.includes(index)) {
94
+ setCurrentActiveFieldset(
95
+ removeFromArray(
96
+ currentActiveFieldset,
97
+ currentActiveFieldset.indexOf(index),
98
+ ),
99
+ );
100
+ } else {
101
+ setCurrentActiveFieldset(
102
+ insertInArray(
103
+ currentActiveFieldset,
104
+ index,
105
+ currentActiveFieldset.length + 1,
106
+ ),
107
+ );
108
+ }
79
109
  }
80
110
 
81
111
  return (
@@ -136,22 +166,22 @@ const InlineForm = (props) => {
136
166
  <Accordion fluid styled className="form" key={fieldset.id}>
137
167
  <div key={fieldset.id} id={`blockform-fieldset-${fieldset.id}`}>
138
168
  <Accordion.Title
139
- active={currentActiveFieldset === index}
169
+ active={currentActiveFieldset.includes(index)}
140
170
  index={index}
141
171
  onClick={handleCurrentActiveFieldset}
142
172
  >
143
173
  {fieldset.title && <>{fieldset.title}</>}
144
- {currentActiveFieldset === index ? (
174
+ {currentActiveFieldset.includes(index) ? (
145
175
  <Icon name={upSVG} size="20px" />
146
176
  ) : (
147
177
  <Icon name={downSVG} size="20px" />
148
178
  )}
149
179
  </Accordion.Title>
150
- <Accordion.Content active={currentActiveFieldset === index}>
180
+ <Accordion.Content active={currentActiveFieldset.includes(index)}>
151
181
  <AnimateHeight
152
182
  animateOpacity
153
183
  duration={500}
154
- height={currentActiveFieldset === index ? 'auto' : 0}
184
+ height={currentActiveFieldset.includes(index) ? 'auto' : 0}
155
185
  >
156
186
  <Segment className="attached">
157
187
  {map(fieldset.fields, (field) => (
@@ -0,0 +1,8 @@
1
+ import { atom } from 'jotai';
2
+ import { atomFamily } from 'jotai/utils';
3
+ import { isEqual } from 'lodash';
4
+
5
+ export const inlineFormFieldsetsState = atomFamily(
6
+ ({ name, initialState }) => atom(initialState),
7
+ (a, b) => a.name === b.name && isEqual(a.fielsetList, b.fielsetList),
8
+ );