decidim-admin 0.29.1 → 0.30.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (249) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/admin/multi_select_picker/show.erb +10 -0
  3. data/app/cells/decidim/admin/multi_select_picker_cell.rb +38 -0
  4. data/app/commands/decidim/admin/block_user.rb +1 -0
  5. data/app/commands/decidim/admin/bulk_action.rb +92 -0
  6. data/app/commands/decidim/admin/bulk_block_users.rb +75 -0
  7. data/app/commands/decidim/admin/bulk_unblock_users.rb +66 -0
  8. data/app/commands/decidim/admin/bulk_unreport_users.rb +69 -0
  9. data/app/commands/decidim/admin/content_blocks/update_content_block.rb +1 -1
  10. data/app/commands/decidim/admin/create_participatory_space_private_user.rb +3 -1
  11. data/app/commands/decidim/admin/create_share_token.rb +39 -0
  12. data/app/commands/decidim/admin/create_taxonomy.rb +23 -0
  13. data/app/commands/decidim/admin/create_taxonomy_filter.rb +24 -0
  14. data/app/commands/decidim/admin/destroy_share_token.rb +22 -0
  15. data/app/commands/decidim/admin/destroy_taxonomy.rb +18 -0
  16. data/app/commands/decidim/admin/destroy_taxonomy_filter.rb +20 -0
  17. data/app/commands/decidim/admin/hide_menu_component.rb +37 -0
  18. data/app/commands/decidim/admin/hide_resource.rb +4 -2
  19. data/app/commands/decidim/admin/publish_all_participatory_space_private_users.rb +50 -0
  20. data/app/commands/decidim/admin/publish_component.rb +3 -0
  21. data/app/commands/decidim/admin/reorder_components.rb +47 -0
  22. data/app/commands/decidim/admin/reorder_taxonomies.rb +76 -0
  23. data/app/commands/decidim/admin/unhide_resource.rb +11 -3
  24. data/app/commands/decidim/admin/unpublish_all_participatory_space_private_users.rb +50 -0
  25. data/app/commands/decidim/admin/unreport_resource.rb +11 -3
  26. data/app/commands/decidim/admin/update_component_permissions.rb +53 -13
  27. data/app/commands/decidim/admin/update_participatory_space_private_user.rb +11 -0
  28. data/app/commands/decidim/admin/update_share_token.rb +24 -0
  29. data/app/commands/decidim/admin/update_taxonomy.rb +20 -0
  30. data/app/commands/decidim/admin/update_taxonomy_filter.rb +28 -0
  31. data/app/controllers/concerns/decidim/admin/component_taxonomies_helper.rb +19 -0
  32. data/app/controllers/concerns/decidim/admin/filterable.rb +15 -18
  33. data/app/controllers/concerns/decidim/admin/has_trashable_resources.rb +170 -0
  34. data/app/controllers/concerns/decidim/admin/needs_admin_tos_accepted.rb +2 -29
  35. data/app/controllers/concerns/decidim/admin/participatory_space_admin_context.rb +12 -2
  36. data/app/controllers/concerns/decidim/admin/taxonomies/filterable.rb +27 -0
  37. data/app/controllers/decidim/admin/application_controller.rb +1 -2
  38. data/app/controllers/decidim/admin/areas_controller.rb +1 -0
  39. data/app/controllers/decidim/admin/block_user_controller.rb +43 -1
  40. data/app/controllers/decidim/admin/component_permissions_controller.rb +2 -4
  41. data/app/controllers/decidim/admin/components_controller.rb +50 -9
  42. data/app/controllers/decidim/admin/concerns/has_private_users.rb +59 -2
  43. data/app/controllers/decidim/admin/conflicts_controller.rb +1 -1
  44. data/app/controllers/decidim/admin/global_moderations_controller.rb +4 -0
  45. data/app/controllers/decidim/admin/impersonations_controller.rb +1 -0
  46. data/app/controllers/decidim/admin/moderated_users_controller.rb +26 -0
  47. data/app/controllers/decidim/admin/moderations_controller.rb +18 -0
  48. data/app/controllers/decidim/admin/newsletters_controller.rb +50 -6
  49. data/app/controllers/decidim/admin/resource_permissions_controller.rb +1 -1
  50. data/app/controllers/decidim/admin/scopes_controller.rb +1 -0
  51. data/app/controllers/decidim/admin/share_tokens_controller.rb +109 -7
  52. data/app/controllers/decidim/admin/taxonomies_controller.rb +129 -0
  53. data/app/controllers/decidim/admin/taxonomy_filters_controller.rb +112 -0
  54. data/app/controllers/decidim/admin/taxonomy_filters_selector_controller.rb +81 -0
  55. data/app/controllers/decidim/admin/taxonomy_items_controller.rb +91 -0
  56. data/app/forms/concerns/decidim/has_taxonomy_form_attributes.rb +57 -0
  57. data/app/forms/decidim/admin/block_users_form.rb +21 -0
  58. data/app/forms/decidim/admin/help_section_form.rb +1 -1
  59. data/app/forms/decidim/admin/impersonate_user_form.rb +5 -0
  60. data/app/forms/decidim/admin/import_example_form.rb +1 -1
  61. data/app/forms/decidim/admin/newsletter_form.rb +1 -1
  62. data/app/forms/decidim/admin/organization_appearance_form.rb +2 -2
  63. data/app/forms/decidim/admin/organization_form.rb +2 -2
  64. data/app/forms/decidim/admin/participatory_space_private_user_form.rb +5 -0
  65. data/app/forms/decidim/admin/selective_newsletter_form.rb +46 -11
  66. data/app/forms/decidim/admin/share_token_form.rb +55 -0
  67. data/app/forms/decidim/admin/static_page_form.rb +1 -1
  68. data/app/forms/decidim/admin/taxonomy_filter_form.rb +85 -0
  69. data/app/forms/decidim/admin/taxonomy_form.rb +20 -0
  70. data/app/forms/decidim/admin/taxonomy_item_form.rb +54 -0
  71. data/app/forms/decidim/admin/transfer_user_form.rb +15 -0
  72. data/app/helpers/decidim/admin/application_helper.rb +0 -1
  73. data/app/helpers/decidim/admin/bulk_actions_helper.rb +0 -31
  74. data/app/helpers/decidim/admin/moderations/reports_helper.rb +1 -1
  75. data/app/helpers/decidim/admin/moderations_helper.rb +1 -1
  76. data/app/helpers/decidim/admin/newsletters_helper.rb +57 -27
  77. data/app/helpers/decidim/admin/scopes_helper.rb +0 -6
  78. data/app/helpers/decidim/admin/search_form_helper.rb +1 -1
  79. data/app/helpers/decidim/admin/settings_helper.rb +85 -11
  80. data/app/jobs/decidim/admin/newsletter_job.rb +3 -1
  81. data/app/packs/entrypoints/decidim_admin.js +4 -0
  82. data/app/packs/src/decidim/admin/application.js +2 -0
  83. data/app/packs/src/decidim/admin/draggable-table.js +33 -0
  84. data/app/packs/src/decidim/admin/form.js +0 -1
  85. data/app/packs/src/decidim/admin/global_moderations.js +186 -0
  86. data/app/packs/src/decidim/admin/managed_moderated_users.js +186 -0
  87. data/app/packs/src/decidim/admin/newsletters.js +164 -73
  88. data/app/packs/src/decidim/admin/proposal_infinite_edit.js +3 -6
  89. data/app/packs/src/decidim/admin/sortable.js +28 -16
  90. data/app/packs/src/decidim/admin/taxonomy_filters.js +93 -0
  91. data/app/packs/stylesheets/decidim/admin/_component-show.scss +66 -5
  92. data/app/packs/stylesheets/decidim/admin/_legacy_foundation.scss +13 -0
  93. data/app/packs/stylesheets/decidim/admin/_moderations.scss +8 -0
  94. data/app/packs/stylesheets/decidim/admin/_select_picker.scss +20 -0
  95. data/app/packs/stylesheets/decidim/admin/_table-list.scss +22 -0
  96. data/app/packs/stylesheets/decidim/admin/_taxonomies.scss +74 -0
  97. data/app/packs/stylesheets/decidim/admin/application.scss +3 -0
  98. data/app/permissions/decidim/admin/permissions.rb +32 -1
  99. data/app/queries/decidim/admin/newsletter_recipients.rb +59 -19
  100. data/app/views/decidim/admin/areas/index.html.erb +3 -0
  101. data/app/views/decidim/admin/block_user/bulk_new.html.erb +45 -0
  102. data/app/views/decidim/admin/components/_actions.html.erb +50 -33
  103. data/app/views/decidim/admin/components/{_component.html.erb → _component_row.html.erb} +10 -5
  104. data/app/views/decidim/admin/components/_components_table.html.erb +18 -0
  105. data/app/views/decidim/admin/components/_form.html.erb +0 -12
  106. data/app/views/decidim/admin/components/_taxonomy_filters_drawer.html.erb +2 -0
  107. data/app/views/decidim/admin/components/_visibility_label.html.erb +9 -0
  108. data/app/views/decidim/admin/components/index.html.erb +12 -14
  109. data/app/views/decidim/admin/components/manage_trash.html.erb +11 -0
  110. data/app/views/decidim/admin/conflicts/edit.html.erb +21 -11
  111. data/app/views/decidim/admin/moderated_users/_bulk-actions.html.erb +6 -0
  112. data/app/views/decidim/admin/moderated_users/bulk_actions/_block.html.erb +20 -0
  113. data/app/views/decidim/admin/moderated_users/bulk_actions/_dropdown.html.erb +40 -0
  114. data/app/views/decidim/admin/moderated_users/bulk_actions/_unblock.html.erb +20 -0
  115. data/app/views/decidim/admin/moderated_users/bulk_actions/_unreport.html.erb +20 -0
  116. data/app/views/decidim/admin/moderated_users/index.html.erb +15 -7
  117. data/app/views/decidim/admin/moderations/_bulk-actions.html.erb +7 -0
  118. data/app/views/decidim/admin/moderations/_moderation-tr.html.erb +50 -0
  119. data/app/views/decidim/admin/moderations/_moderations-thead.html.erb +18 -0
  120. data/app/views/decidim/admin/moderations/bulk_actions/_dropdown.html.erb +43 -0
  121. data/app/views/decidim/admin/moderations/bulk_actions/_hide.html.erb +20 -0
  122. data/app/views/decidim/admin/moderations/bulk_actions/_unhide.html.erb +20 -0
  123. data/app/views/decidim/admin/moderations/bulk_actions/_unreport.html.erb +20 -0
  124. data/app/views/decidim/admin/moderations/index.html.erb +13 -81
  125. data/app/views/decidim/admin/newsletter_templates/index.html.erb +0 -1
  126. data/app/views/decidim/admin/newsletters/confirm_recipients.html.erb +64 -0
  127. data/app/views/decidim/admin/newsletters/select_recipients_to_deliver.html.erb +44 -20
  128. data/app/views/decidim/admin/participatory_space_private_users/_form.html.erb +6 -0
  129. data/app/views/decidim/admin/participatory_space_private_users/edit.html.erb +19 -0
  130. data/app/views/decidim/admin/participatory_space_private_users/index.html.erb +15 -1
  131. data/app/views/decidim/admin/resource_permissions/_options_form.html.erb +5 -0
  132. data/app/views/decidim/admin/resource_permissions/edit.html.erb +2 -2
  133. data/app/views/decidim/admin/scope_types/index.html.erb +3 -0
  134. data/app/views/decidim/admin/scopes/index.html.erb +3 -0
  135. data/app/views/decidim/admin/share_tokens/_form.html.erb +52 -0
  136. data/app/views/decidim/admin/share_tokens/edit.html.erb +33 -0
  137. data/app/views/decidim/admin/share_tokens/index.html.erb +47 -0
  138. data/app/views/decidim/admin/share_tokens/new.html.erb +69 -0
  139. data/app/views/decidim/admin/shared/landing_page_content_blocks/edit.html.erb +1 -1
  140. data/app/views/decidim/admin/taxonomies/_filters.html.erb +19 -0
  141. data/app/views/decidim/admin/taxonomies/_form.html.erb +5 -0
  142. data/app/views/decidim/admin/taxonomies/_row.html.erb +40 -0
  143. data/app/views/decidim/admin/taxonomies/_row_children.html.erb +8 -0
  144. data/app/views/decidim/admin/taxonomies/_table.html.erb +86 -0
  145. data/app/views/decidim/admin/taxonomies/_taxonomy_actions.html.erb +15 -0
  146. data/app/views/decidim/admin/taxonomies/edit.html.erb +87 -0
  147. data/app/views/decidim/admin/taxonomies/index.html.erb +28 -0
  148. data/app/views/decidim/admin/taxonomies/new.html.erb +16 -0
  149. data/app/views/decidim/admin/taxonomy_filters/_check_boxes.html.erb +10 -0
  150. data/app/views/decidim/admin/taxonomy_filters/_form.html.erb +96 -0
  151. data/app/views/decidim/admin/taxonomy_filters/_table.html.erb +33 -0
  152. data/app/views/decidim/admin/taxonomy_filters/edit.html.erb +22 -0
  153. data/app/views/decidim/admin/taxonomy_filters/index.html.erb +26 -0
  154. data/app/views/decidim/admin/taxonomy_filters/new.html.erb +32 -0
  155. data/app/views/decidim/admin/taxonomy_filters_selector/_check_boxes.html.erb +7 -0
  156. data/app/views/decidim/admin/taxonomy_filters_selector/_component_table.html.erb +25 -0
  157. data/app/views/decidim/admin/taxonomy_filters_selector/_taxonomies_select.html.erb +16 -0
  158. data/app/views/decidim/admin/taxonomy_filters_selector/index.html.erb +1 -0
  159. data/app/views/decidim/admin/taxonomy_filters_selector/new.html.erb +27 -0
  160. data/app/views/decidim/admin/taxonomy_filters_selector/show.html.erb +18 -0
  161. data/app/views/decidim/admin/taxonomy_items/_form.html.erb +8 -0
  162. data/app/views/decidim/admin/taxonomy_items/edit.html.erb +12 -0
  163. data/app/views/decidim/admin/taxonomy_items/new.html.erb +12 -0
  164. data/app/views/layouts/decidim/admin/taxonomy_filters.html.erb +17 -0
  165. data/app/views/layouts/decidim/admin/taxonomy_filters_selector.html.erb +10 -0
  166. data/config/locales/ar.yml +91 -36
  167. data/config/locales/bg.yml +48 -51
  168. data/config/locales/bn-BD.yml +1 -0
  169. data/config/locales/bs-BA.yml +499 -0
  170. data/config/locales/ca.yml +300 -50
  171. data/config/locales/cs.yml +298 -46
  172. data/config/locales/de.yml +300 -50
  173. data/config/locales/el.yml +1 -50
  174. data/config/locales/en.yml +300 -50
  175. data/config/locales/es-MX.yml +298 -48
  176. data/config/locales/es-PY.yml +298 -48
  177. data/config/locales/es.yml +298 -48
  178. data/config/locales/eu.yml +433 -171
  179. data/config/locales/fi-plain.yml +298 -48
  180. data/config/locales/fi.yml +315 -65
  181. data/config/locales/fr-CA.yml +183 -47
  182. data/config/locales/fr.yml +183 -47
  183. data/config/locales/ga-IE.yml +0 -23
  184. data/config/locales/gl.yml +1 -46
  185. data/config/locales/hu.yml +1 -51
  186. data/config/locales/id-ID.yml +0 -20
  187. data/config/locales/is-IS.yml +0 -18
  188. data/config/locales/it.yml +1 -46
  189. data/config/locales/ja.yml +303 -55
  190. data/config/locales/kaa.yml +0 -10
  191. data/config/locales/ko.yml +0 -50
  192. data/config/locales/lb.yml +1 -46
  193. data/config/locales/lt.yml +1 -50
  194. data/config/locales/lv.yml +1 -27
  195. data/config/locales/nl.yml +1 -46
  196. data/config/locales/no.yml +1 -46
  197. data/config/locales/pl.yml +3 -51
  198. data/config/locales/pt-BR.yml +38 -50
  199. data/config/locales/pt.yml +30 -46
  200. data/config/locales/ro-RO.yml +35 -50
  201. data/config/locales/ru.yml +1 -22
  202. data/config/locales/sk.yml +1 -27
  203. data/config/locales/sl.yml +0 -7
  204. data/config/locales/sq-AL.yml +0 -25
  205. data/config/locales/sr-CS.yml +1 -27
  206. data/config/locales/sv.yml +297 -47
  207. data/config/locales/tr-TR.yml +1 -44
  208. data/config/locales/uk.yml +0 -20
  209. data/config/locales/zh-CN.yml +0 -44
  210. data/config/locales/zh-TW.yml +1 -50
  211. data/config/routes.rb +14 -13
  212. data/decidim-admin.gemspec +2 -2
  213. data/lib/decidim/admin/engine.rb +3 -1
  214. data/lib/decidim/admin/import/creator.rb +2 -6
  215. data/lib/decidim/admin/import/readers/json.rb +1 -1
  216. data/lib/decidim/admin/menu.rb +9 -1
  217. data/lib/decidim/admin/search_form_builder.rb +1 -1
  218. data/lib/decidim/admin/test/destroy_admin_examples.rb +2 -2
  219. data/lib/decidim/admin/test/filterable_examples.rb +100 -9
  220. data/lib/decidim/admin/test/forms/attachment_collection_form_examples.rb +1 -1
  221. data/lib/decidim/admin/test/forms/attachment_form_examples.rb +1 -1
  222. data/lib/decidim/admin/test/invite_participatory_space_admins_shared_examples.rb +2 -4
  223. data/lib/decidim/admin/test/manage_component_permissions_examples.rb +5 -5
  224. data/lib/decidim/admin/test/manage_hide_content_examples.rb +0 -1
  225. data/lib/decidim/admin/test/manage_moderations_examples.rb +3 -3
  226. data/lib/decidim/admin/test/manage_resource_soft_deletion_examples.rb +113 -0
  227. data/lib/decidim/admin/test/manage_taxonomy_filters_examples.rb +127 -0
  228. data/lib/decidim/admin/test/taxonomy_filters_examples.rb +32 -0
  229. data/lib/decidim/admin/test.rb +3 -1
  230. data/lib/decidim/admin/version.rb +1 -1
  231. metadata +106 -30
  232. data/app/commands/decidim/admin/create_category.rb +0 -15
  233. data/app/commands/decidim/admin/destroy_category.rb +0 -15
  234. data/app/commands/decidim/admin/destroy_component.rb +0 -19
  235. data/app/commands/decidim/admin/update_category.rb +0 -11
  236. data/app/controllers/decidim/admin/categories_controller.rb +0 -98
  237. data/app/forms/decidim/admin/category_form.rb +0 -32
  238. data/app/helpers/decidim/admin/resource_scope_helper.rb +0 -52
  239. data/app/packs/src/decidim/admin/scope_picker_enabler.component.js +0 -12
  240. data/app/views/decidim/admin/categories/_form.html.erb +0 -18
  241. data/app/views/decidim/admin/categories/edit.html.erb +0 -19
  242. data/app/views/decidim/admin/categories/index.html.erb +0 -65
  243. data/app/views/decidim/admin/categories/new.html.erb +0 -19
  244. data/app/views/decidim/admin/share_tokens/_share_tokens.html.erb +0 -45
  245. data/lib/decidim/admin/test/commands/create_category_examples.rb +0 -74
  246. data/lib/decidim/admin/test/commands/destroy_category_examples.rb +0 -83
  247. data/lib/decidim/admin/test/commands/update_category_examples.rb +0 -76
  248. data/lib/decidim/admin/test/forms/category_form_examples.rb +0 -70
  249. data/lib/decidim/admin/test/manage_categories_examples.rb +0 -128
@@ -0,0 +1,186 @@
1
+ /* eslint-disable no-invalid-this */
2
+ /* eslint no-unused-vars: 0 */
3
+ /* eslint id-length: ["error", { "exceptions": ["e"] }] */
4
+
5
+ document.addEventListener("DOMContentLoaded", () => {
6
+ const selectedModeratedUsersCount = () => {
7
+ return document.querySelectorAll(".table-list .js-check-all-moderated_users:checked").length;
8
+ };
9
+
10
+ const selectedModeratedUsersCountUpdate = () => {
11
+ const selectedModeratedUsers = selectedModeratedUsersCount();
12
+
13
+ const countElement = document.getElementById("js-selected-moderated_users-count");
14
+ const blockActions = document.getElementById("js-block-moderated_users-actions");
15
+ const unblockActions = document.getElementById("js-unblock-moderated_users-actions");
16
+ const unreportActions = document.getElementById("js-unreport-moderated_users-actions");
17
+
18
+ if (selectedModeratedUsers === 0) {
19
+ countElement.textContent = "";
20
+ blockActions.classList.add("hide");
21
+ unblockActions.classList.add("hide");
22
+ unreportActions.classList.add("hide");
23
+ } else {
24
+ countElement.textContent = selectedModeratedUsers;
25
+ }
26
+ };
27
+
28
+ const showBulkActionsButton = () => {
29
+ if (selectedModeratedUsersCount() > 0) {
30
+ document.getElementById("js-bulk-actions-button").classList.remove("hide");
31
+ }
32
+ };
33
+
34
+ const hideBulkActionsButton = (force = false) => {
35
+ const bulkActionsButton = document.getElementById("js-bulk-actions-button");
36
+ const bulkActionsDropdown = document.getElementById("js-bulk-actions-dropdown");
37
+
38
+ if (selectedModeratedUsersCount() === 0 || force) {
39
+ bulkActionsButton.classList.add("hide");
40
+ bulkActionsDropdown.classList.remove("is-open");
41
+ }
42
+ };
43
+
44
+ const showOtherActionsButtons = () => {
45
+ document.getElementById("js-other-actions-wrapper").classList.remove("hide");
46
+ };
47
+
48
+ const hideOtherActionsButtons = () => {
49
+ document.getElementById("js-other-actions-wrapper").classList.add("hide");
50
+ };
51
+
52
+ const hideBulkActionForms = () => {
53
+ document.querySelectorAll(".js-bulk-action-form").forEach((form) => {
54
+ form.classList.add("hide");
55
+ });
56
+ };
57
+
58
+ // Expose functions to make them available in .js.erb templates
59
+ window.selectedModeratedUsersCountUpdate = selectedModeratedUsersCountUpdate;
60
+ window.showBulkActionsButton = showBulkActionsButton;
61
+ window.hideBulkActionsButton = hideBulkActionsButton;
62
+ window.showOtherActionsButtons = showOtherActionsButtons;
63
+ window.hideOtherActionsButtons = hideOtherActionsButtons;
64
+ window.hideBulkActionForms = hideBulkActionForms;
65
+
66
+ const bulkActionsButton = document.getElementById("js-bulk-actions-button");
67
+
68
+ if (document.querySelectorAll(".js-bulk-action-form").length) {
69
+ hideBulkActionForms();
70
+ bulkActionsButton.classList.add("hide");
71
+
72
+ document.querySelectorAll("#js-bulk-actions-dropdown ul li button").forEach((button) => {
73
+ button.addEventListener("click", (event) => {
74
+ const bulkActionsDropdown = document.getElementById("js-bulk-actions-dropdown");
75
+ bulkActionsDropdown.classList.remove("is-open");
76
+ hideBulkActionForms();
77
+
78
+ const action = event.target.dataset.action;
79
+ const panelActions = [
80
+ "block-moderated_users",
81
+ "unreport-moderated_users",
82
+ "unblock-moderated_users"
83
+ ];
84
+
85
+ if (!action) {
86
+ return;
87
+ }
88
+
89
+ const form = document.getElementById(`js-form-${action}`);
90
+ const actionElement = document.getElementById(`js-${action}-actions`);
91
+
92
+ if (panelActions.includes(action)) {
93
+ form.addEventListener("submit", () => {
94
+ document.querySelector(".layout-content > div[data-callout-wrapper]").innerHTML = "";
95
+ });
96
+
97
+ actionElement.classList.remove("hide");
98
+ } else {
99
+ form.addEventListener("submit", () => {
100
+ document.querySelector(".layout-content > div[data-callout-wrapper]").innerHTML = "";
101
+ });
102
+
103
+ actionElement.classList.remove("hide");
104
+ hideBulkActionsButton(true);
105
+ hideOtherActionsButtons();
106
+ }
107
+ });
108
+ });
109
+
110
+ // Select all checkboxes
111
+ document.querySelector(".js-check-all").addEventListener("change", function () {
112
+ const isChecked = this.checked;
113
+ const checkboxes = document.querySelectorAll(".js-check-all-moderated_users");
114
+
115
+ checkboxes.forEach((checkbox) => {
116
+ checkbox.checked = isChecked;
117
+ const row = checkbox.closest("tr");
118
+ if (row) {
119
+ row.classList.toggle("selected", isChecked);
120
+ }
121
+ });
122
+
123
+ if (isChecked) {
124
+ showBulkActionsButton();
125
+ } else {
126
+ hideBulkActionsButton();
127
+ }
128
+
129
+ selectedModeratedUsersCountUpdate();
130
+ });
131
+
132
+ // moderated users checkbox change
133
+ document.querySelector(".table-list").addEventListener("change", (event) => {
134
+ if (!event.target.matches(".js-check-all-moderated_users")) {
135
+ return;
136
+ }
137
+
138
+ const checkbox = event.target;
139
+ const moderationId = checkbox.value;
140
+ const checked = checkbox.checked;
141
+
142
+ // Uncheck "select all" if one of the checkboxes is unchecked
143
+ const selectAllCheckbox = document.querySelector(".js-check-all");
144
+ if (!checked) {
145
+ selectAllCheckbox.checked = false;
146
+ }
147
+
148
+ // If all individual checkboxes are checked, check the "select all" checkbox
149
+ const allCheckboxes = Array.from(document.querySelectorAll(".js-check-all-moderated_users")).filter((checkboxItem) => checkboxItem.offsetParent !== null);
150
+ const checkedCheckboxes = Array.from(document.querySelectorAll(".js-check-all-moderated_users:checked")).filter((checkboxItem) => checkboxItem.offsetParent !== null);
151
+
152
+ if (allCheckboxes.length === checkedCheckboxes.length) {
153
+ selectAllCheckbox.checked = true;
154
+ showBulkActionsButton();
155
+ }
156
+
157
+ const row = checkbox.closest("tr");
158
+ if (row) {
159
+ row.classList.toggle("selected", checked);
160
+ }
161
+
162
+ if (checked) {
163
+ showBulkActionsButton();
164
+ } else {
165
+ hideBulkActionsButton();
166
+ }
167
+
168
+ if (checkedCheckboxes.length === 0) {
169
+ hideBulkActionsButton();
170
+ }
171
+
172
+ document.querySelectorAll(`.js-moderated_user-id-${moderationId}`).forEach((input) => {
173
+ input.checked = checked;
174
+ });
175
+ selectedModeratedUsersCountUpdate();
176
+ });
177
+
178
+ document.querySelectorAll(".js-cancel-bulk-action").forEach((button) => {
179
+ button.addEventListener("click", () => {
180
+ hideBulkActionForms();
181
+ showBulkActionsButton();
182
+ showOtherActionsButtons();
183
+ });
184
+ });
185
+ }
186
+ });
@@ -1,82 +1,173 @@
1
- $(() => {
2
- const $form = $(".form.newsletter_deliver");
3
-
4
- if ($form.length > 0) {
5
- const $sendNewsletterToAllUsers = $form.find("#send_newsletter_to_all_users");
6
- const $sendNewsletterToFollowers = $form.find("#send_newsletter_to_followers");
7
- const $sendNewsletterToParticipants = $form.find("#send_newsletter_to_participants");
8
- const $participatorySpacesForSelect = $form.find("#participatory_spaces_for_select");
9
-
10
- const checkSelectiveNewsletterFollowers = $sendNewsletterToFollowers.find("input[type='checkbox']").prop("checked");
11
- const checkSelectiveNewsletterParticipants = $sendNewsletterToParticipants.find("input[type='checkbox']").prop("checked");
12
-
13
- $sendNewsletterToAllUsers.on("change", (event) => {
14
- const checked = event.target.checked;
15
- if (checked) {
16
- $sendNewsletterToFollowers.find("input[type='checkbox']").prop("checked", !checked);
17
- $sendNewsletterToParticipants.find("input[type='checkbox']").prop("checked", !checked);
18
- $participatorySpacesForSelect.hide();
1
+ import TomSelect from "tom-select/dist/cjs/tom-select.popular";
2
+
3
+ document.addEventListener("DOMContentLoaded", () => {
4
+ const isOnSelectRecipientsPage = window.location.pathname.includes("/select_recipients_to_deliver");
5
+
6
+ const selectors = {
7
+ form: document.querySelector(".form.newsletter_deliver"),
8
+ sendToAllUsers: document.querySelector("#newsletter_send_to_all_users"),
9
+ sendToVerifiedUsers: document.querySelector("#newsletter_send_to_verified_users"),
10
+ sendToParticipants: document.querySelector("#newsletter_send_to_participants"),
11
+ sendToFollowers: document.querySelector("#newsletter_send_to_followers"),
12
+ sendToPrivateMembers: document.querySelector("#newsletter_send_to_private_members"),
13
+ verificationTypesSelect: document.querySelector("#verification_types_for_select"),
14
+ participatorySpacesForSelect: document.querySelector("#participatory_spaces_for_select"),
15
+ deliverButton: document.querySelector("#deliver-button"),
16
+ confirmRecipientsLink: document.querySelector("#confirm-recipients-link"),
17
+ recipientsCount: document.querySelector("#recipients_count"),
18
+ recipientsCountSpinner: document.querySelector("#recipients_count_spinner"),
19
+ csrfToken: document.querySelector('meta[name="csrf-token"]')
20
+ };
21
+
22
+ const inputs = {
23
+ radioButtons: [selectors.sendToAllUsers, selectors.sendToVerifiedUsers].filter(Boolean),
24
+ checkboxes: [
25
+ selectors.sendToParticipants,
26
+ selectors.sendToFollowers,
27
+ selectors.sendToPrivateMembers
28
+ ].filter(Boolean)
29
+ };
30
+
31
+ const toggleVisibility = (element, condition) => element?.classList.toggle("hidden", !condition);
32
+
33
+ const updateDeliverButtonVisibility = () => {
34
+ const sendToAllUsersChecked = selectors.form?.elements["newsletter[send_to_all_users]"]?.value === "1";
35
+
36
+ toggleVisibility(selectors.deliverButton, sendToAllUsersChecked);
37
+ toggleVisibility(selectors.confirmRecipientsLink, !sendToAllUsersChecked);
38
+ };
39
+
40
+ const updateHiddenField = (input) => {
41
+ const hiddenInput = selectors.form?.elements[input.name];
42
+ if (hiddenInput) {
43
+ hiddenInput.value = input.checked
44
+ ? "1"
45
+ : "0";}
46
+ };
47
+
48
+ const ensureAtLeastOneOptionSelected = () => {
49
+ if (![...inputs.radioButtons, ...inputs.checkboxes].some((input) => input?.checked)) {
50
+ selectors.sendToAllUsers.checked = true;
51
+ updateHiddenField(selectors.sendToAllUsers);
52
+ }
53
+ };
54
+
55
+ const updateConfirmRecipientsLink = () => {
56
+ if (!selectors.confirmRecipientsLink) {
57
+ return;
58
+ }
59
+ const params = new URLSearchParams(new FormData(selectors.form));
60
+ selectors.confirmRecipientsLink.setAttribute(
61
+ "href",
62
+ `${selectors.confirmRecipientsLink.dataset.baseUrl}?${params.toString()}`
63
+ );
64
+ };
65
+
66
+ const updateRecipientsCount = async () => {
67
+ const url = selectors.form?.dataset?.recipientsCountNewsletterPath;
68
+ if (!url) {
69
+ return;
70
+ }
71
+
72
+ selectors.recipientsCountSpinner?.classList.remove("hide");
73
+ try {
74
+ const response = await fetch(url, {
75
+ method: "POST",
76
+ headers: { "X-CSRF-Token": selectors.csrfToken?.content },
77
+ body: new FormData(selectors.form)
78
+ });
79
+ selectors.recipientsCount.textContent = await response.text();
80
+ } catch (error) {
81
+ console.error("Error fetching recipients count:", error);
82
+ } finally {
83
+ selectors.recipientsCountSpinner?.classList.add("hide");
84
+ }
85
+ };
86
+
87
+ const resetIdsForParticipatorySpaces = () => {
88
+ document.querySelectorAll('.form.newsletter_deliver select[name$="[ids][]"]').forEach((select) => {
89
+ if (select.tomselect) {
90
+ select.tomselect.clear();
19
91
  } else {
20
- $sendNewsletterToFollowers.find("input[type='checkbox']").prop("checked", !checked);
21
- $sendNewsletterToParticipants.find("input[type='checkbox']").prop("checked", !checked);
22
- $participatorySpacesForSelect.show();
23
- }
24
- })
25
-
26
- $sendNewsletterToFollowers.on("change", (event) => {
27
- const checked = event.target.checked;
28
- const selectiveNewsletterParticipants = $sendNewsletterToParticipants.find("input[type='checkbox']").prop("checked");
29
-
30
- if (checked) {
31
- $sendNewsletterToAllUsers.find("input[type='checkbox']").prop("checked", !checked);
32
- $participatorySpacesForSelect.show();
33
- } else if (!selectiveNewsletterParticipants) {
34
- $sendNewsletterToAllUsers.find("input[type='checkbox']").prop("checked", true);
35
- $participatorySpacesForSelect.hide();
92
+ select.value = [];
36
93
  }
37
- })
38
-
39
- $sendNewsletterToParticipants.on("change", (event) => {
40
- const checked = event.target.checked;
41
- const selectiveNewsletterFollowers = $sendNewsletterToFollowers.find("input[type='checkbox']").prop("checked");
42
- if (checked) {
43
- $sendNewsletterToAllUsers.find("input[type='checkbox']").prop("checked", !checked);
44
- $participatorySpacesForSelect.show();
45
- } else if (!selectiveNewsletterFollowers) {
46
- $sendNewsletterToAllUsers.find("input[type='checkbox']").prop("checked", true);
47
- $participatorySpacesForSelect.hide();
48
- }
49
- })
94
+ });
95
+ };
50
96
 
51
- if (checkSelectiveNewsletterFollowers || checkSelectiveNewsletterParticipants) {
52
- $participatorySpacesForSelect.show();
53
- } else {
54
- $participatorySpacesForSelect.hide();
97
+ const resetVerificationTypes = () => {
98
+ const select = document.querySelector("#verification-types-select");
99
+ select?.tomselect?.clear();
100
+ const hiddenInput = selectors.form?.elements["newsletter[verification_types]"];
101
+ if (hiddenInput) {
102
+ hiddenInput.value = "";
55
103
  }
104
+ };
56
105
 
57
- $(".form .spaces-block-tag").each(function(_i, blockTag) {
58
- const selectTag = $(blockTag).find(".chosen-select")
59
- selectTag.change(function() {
60
- let optionSelected = selectTag.find("option:selected").val()
61
- if (optionSelected === "all") {
62
- selectTag.find("option").not(":first").prop("selected", true);
63
- selectTag.find("option[value='all']").prop("selected", false);
64
- } else if (optionSelected === "") {
65
- selectTag.find("option").not(":first").prop("selected", false);
66
- }
106
+ const updateFormState = () => {
107
+ [...inputs.radioButtons, ...inputs.checkboxes].forEach(updateHiddenField);
108
+ const isAllUsersChecked = selectors.sendToAllUsers?.checked;
109
+ const isAnyChecked = [...inputs.radioButtons, ...inputs.checkboxes].some((input) => input?.checked);
110
+
111
+ toggleVisibility(selectors.deliverButton, isAllUsersChecked);
112
+ toggleVisibility(selectors.confirmRecipientsLink, !isAllUsersChecked && isAnyChecked);
113
+ toggleVisibility(
114
+ selectors.participatorySpacesForSelect,
115
+ inputs.checkboxes.some((input) => input.checked) && !selectors.sendToVerifiedUsers?.checked
116
+ );
117
+ toggleVisibility(selectors.verificationTypesSelect, selectors.sendToVerifiedUsers?.checked);
118
+ ensureAtLeastOneOptionSelected();
119
+ updateConfirmRecipientsLink();
120
+ updateRecipientsCount();
121
+ };
122
+
123
+ const handleRadioChange = (radio) => {
124
+ inputs.radioButtons.forEach((rb) => (rb.checked = rb === radio));
125
+ inputs.checkboxes.forEach((checkbox) => (checkbox.checked = false));
126
+ resetVerificationTypes();
127
+ resetIdsForParticipatorySpaces();
128
+ updateFormState();
129
+ };
130
+
131
+ const handleCheckboxChange = () => {
132
+ inputs.radioButtons.forEach((radio) => (radio.checked = false));
133
+ resetVerificationTypes();
134
+ resetIdsForParticipatorySpaces();
135
+ updateFormState();
136
+ };
137
+
138
+ const attachEventListeners = () => {
139
+ inputs.radioButtons.forEach((radio) =>
140
+ radio.addEventListener("change", () => handleRadioChange(radio))
141
+ );
142
+
143
+ inputs.checkboxes.forEach((checkbox) =>
144
+ checkbox.addEventListener("change", handleCheckboxChange)
145
+ );
146
+
147
+ selectors.form?.addEventListener("change", updateFormState);
148
+ };
149
+
150
+ const initializeTomSelect = () => {
151
+ document.querySelectorAll("[data-multiselect='true']").forEach((select) => {
152
+ const tomSelect = new TomSelect(select, {
153
+ plugins: ["remove_button", "dropdown_input"],
154
+ allowEmptyOption: true
67
155
  });
68
- })
69
-
70
- $form.on("change", function() {
71
- let $data = $form.serializeJSON().newsletter;
72
- let $url = $form.data("recipients-count-newsletter-path");
73
- const $modal = $("#recipients_count_spinner");
74
- $modal.removeClass("hide");
75
- $.get($url, {data: $data}, function(recipientsCount) {
76
- $("#recipients_count").text(recipientsCount);
77
- }).always(function() {
78
- $modal.addClass("hide");
156
+
157
+ tomSelect.on("change", () => {
158
+ const selectedOptions = tomSelect.getValue();
159
+
160
+ if (selectedOptions.includes("all") && selectedOptions.length > 1) {
161
+ tomSelect.setValue(["all"]);
162
+ }
79
163
  });
80
- })
164
+ });
165
+ };
166
+
167
+ if (isOnSelectRecipientsPage) {
168
+ attachEventListeners();
169
+ initializeTomSelect();
170
+ updateFormState();
171
+ updateDeliverButtonVisibility();
81
172
  }
82
173
  });
@@ -1,10 +1,7 @@
1
1
  $(() => {
2
- const $limitedTimeLabel = $("label[for='component_settings_proposal_edit_time_limited']")
3
- const $limitedTimeRadioButton = $("#component_settings_proposal_edit_time_limited")
4
- const $infiniteTimeRadioButton = $("#component_settings_proposal_edit_time_infinite")
5
- const $editTimeContainer = $(".proposal_edit_before_minutes_container")
6
-
7
- $editTimeContainer.detach().appendTo($limitedTimeLabel)
2
+ const $limitedTimeRadioButton = $("#component_settings_proposal_edit_time_limited");
3
+ const $infiniteTimeRadioButton = $("#component_settings_proposal_edit_time_infinite");
4
+ const $editTimeContainer = $(".edit_time_container");
8
5
 
9
6
  if ($infiniteTimeRadioButton.is(":checked")) {
10
7
  $editTimeContainer.hide();
@@ -1,19 +1,31 @@
1
- import createSortList from "src/decidim/admin/sort_list.component"
1
+ import sortable from "html5sortable/dist/html5sortable.es";
2
2
 
3
- // Once in DOM
4
- $(() => {
5
- const selector = ".js-sortable"
6
- const $sortable = $(selector)
3
+ /*
4
+ Initializes any element with the class js-sortable as a sortable list
5
+ User html5Sortable, with options available as data-draggable-options (see https://github.com/lukasoppermann/html5sortable)
7
6
 
8
- $sortable.each((index, elem) => {
9
- const item = (elem.id)
10
- ? `#${elem.id}`
11
- : selector
7
+ Event are dispatched on the element with the class js-sortable, so you can simply do:
12
8
 
13
- createSortList(item, {
14
- handle: "li",
15
- forcePlaceholderSize: true,
16
- placeholderClass: "sort-placeholder"
17
- })
18
- })
19
- })
9
+ document.querySelector('.js-sortable').addEventListener('sortupdate', (event) => {
10
+ console.log('The new order is:', event.target.children);
11
+ });
12
+ */
13
+ window.addEventListener("DOMContentLoaded", () => {
14
+ const draggables = document.querySelectorAll(".js-sortable");
15
+
16
+ if (draggables) {
17
+ draggables.forEach((draggable) => {
18
+ let options = {
19
+ "forcePlaceholderSize": true
20
+ };
21
+ ["items", "acceptFrom", "handle", "placeholderClass", "placeholder", "hoverClass"].forEach((option) => {
22
+ let dataOption = `draggable${option.charAt(0).toUpperCase() + option.slice(1)}`;
23
+ if (draggable.dataset[dataOption]) {
24
+ options[option] = draggable.dataset[dataOption];
25
+ }
26
+ });
27
+ // console.log("initialize sortable with options", options);
28
+ sortable(draggable, options);
29
+ });
30
+ }
31
+ });
@@ -0,0 +1,93 @@
1
+ /* eslint-disable no-use-before-define */
2
+ document.addEventListener("decidim:loaded", () => {
3
+ document.querySelectorAll(".js-taxonomy-filters-container").forEach((settingsContainer) => {
4
+ const drawer = window.Decidim.currentDialogs[settingsContainer.dataset.drawer];
5
+ const container = drawer.dialog.querySelector(".js-taxonomy-filters-drawer-container");
6
+ const addButton = settingsContainer.querySelector(".js-add-taxonomy-filter");
7
+
8
+ // Handles the click on edit button for each taxonomy filter in the component settings table
9
+ const activateSettingsActions = () => {
10
+ const edits = settingsContainer.querySelectorAll(".js-edit-taxonomy-filter");
11
+ edits.forEach((edit) => {
12
+ edit.addEventListener("click", (event) => {
13
+ event.preventDefault();
14
+ drawer.open();
15
+ fetchUrl(edit.href);
16
+ });
17
+ });
18
+ };
19
+
20
+ // Handles the change on the taxonomy and filter selects in the drawer
21
+ const activateDrawerActions = () => {
22
+ const taxonomySelector = container.querySelector(".js-drawer-taxonomy-select select");
23
+ const filterSelector = container.querySelector(".js-drawer-filter-select select");
24
+ const selectForm = drawer.dialog.querySelector("#select-taxonomy-filter-form");
25
+ const saveForm = drawer.dialog.querySelector("#save-taxonomy-filter-form");
26
+ const save = drawer.dialog.querySelector("#save-taxonomy-filter");
27
+ const remove = drawer.dialog.querySelector("#remove-taxonomy-filter");
28
+ const currentFilters = settingsContainer.querySelector(".js-current-filters");
29
+
30
+ if (selectForm) {
31
+ selectForm.addEventListener("ajax:success", (event) => {
32
+ container.innerHTML = event.detail[2].responseText;
33
+ activateDrawerActions();
34
+ });
35
+ }
36
+
37
+ if (remove) {
38
+ remove.addEventListener("ajax:success", (event) => {
39
+ currentFilters.innerHTML = event.detail[2].responseText;
40
+ activateSettingsActions();
41
+ drawer.close();
42
+ });
43
+ }
44
+
45
+ if (taxonomySelector) {
46
+ taxonomySelector.addEventListener("change", () => {
47
+ Rails.fire(selectForm, "submit");
48
+ });
49
+ }
50
+
51
+ if (filterSelector) {
52
+ filterSelector.addEventListener("change", () => {
53
+ Rails.fire(selectForm, "submit");
54
+ });
55
+ }
56
+
57
+ if (saveForm) {
58
+ saveForm.addEventListener("ajax:success", (event) => {
59
+ currentFilters.innerHTML = event.detail[2].responseText;
60
+ activateSettingsActions();
61
+ drawer.close();
62
+ });
63
+
64
+ if (save) {
65
+ save.addEventListener("click", (event) => {
66
+ event.preventDefault();
67
+ Rails.fire(saveForm, "submit");
68
+ });
69
+ }
70
+ }
71
+ };
72
+
73
+ const fetchUrl = (url) => {
74
+ container.classList.add("spinner-container");
75
+ fetch(url).then((response) => response.text()).then((html) => {
76
+ container.innerHTML = html;
77
+ container.classList.remove("spinner-container");
78
+ activateDrawerActions();
79
+ });
80
+ };
81
+
82
+ // Activate the rendered edit buttons
83
+ activateSettingsActions();
84
+
85
+ // Opens the drawer with the form to add a new taxonomy filter
86
+ addButton.addEventListener("click", (event) => {
87
+ event.preventDefault();
88
+ const url = addButton.dataset.url;
89
+ fetchUrl(url);
90
+ drawer.open();
91
+ });
92
+ });
93
+ });
@@ -62,13 +62,74 @@
62
62
  }
63
63
 
64
64
  &_notes {
65
- &-grid {
66
- @apply grid grid-cols-2 gap-4 my-4;
65
+ .comment,
66
+ .comment-reply {
67
+ @apply mt-4 p-4 rounded w-full border border-gray-3 space-y-2;
67
68
 
68
- .comment {
69
- @apply p-4 rounded;
69
+ background-color: rgba(255, 252, 238, 1);
70
+ }
71
+
72
+ .comment-reply {
73
+ @apply bg-white;
74
+ }
75
+
76
+ .comment__content {
77
+ @apply space-y-4;
78
+
79
+ a {
80
+ @apply text-secondary;
81
+ }
82
+ }
83
+
84
+ .comment-actions {
85
+ @apply flex items-center gap-4;
86
+
87
+ .button[aria-expanded="false"] {
88
+ svg:first-of-type {
89
+ @apply block;
90
+ }
91
+
92
+ svg:last-of-type {
93
+ @apply hidden;
94
+ }
95
+
96
+ span:first-of-type {
97
+ @apply block;
98
+ }
99
+
100
+ span:last-of-type {
101
+ @apply hidden;
102
+ }
103
+ }
104
+
105
+ .button[aria-expanded="true"] {
106
+ svg:first-of-type {
107
+ @apply hidden;
108
+ }
109
+
110
+ svg:last-of-type {
111
+ @apply block;
112
+ }
113
+
114
+ span:first-of-type {
115
+ @apply hidden;
116
+ }
117
+
118
+ span:last-of-type {
119
+ @apply block;
120
+ }
121
+ }
122
+ }
123
+
124
+ .form__wrapper {
125
+ @apply pb-4;
126
+
127
+ label {
128
+ @apply text-gray-2 text-sm;
129
+ }
70
130
 
71
- background-color: rgba(255, 252, 238, 1);
131
+ textarea {
132
+ @apply mt-2;
72
133
  }
73
134
  }
74
135
  }