decidim-proposals 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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/proposals/highlighted_proposals_for_component/show.erb +12 -12
  3. data/app/cells/decidim/proposals/highlighted_proposals_for_component_cell.rb +1 -1
  4. data/app/cells/decidim/proposals/participatory_text_proposal_cell.rb +1 -1
  5. data/app/cells/decidim/proposals/proposal_g/show.erb +13 -0
  6. data/app/cells/decidim/proposals/proposal_g_cell.rb +34 -0
  7. data/app/cells/decidim/proposals/proposal_history_cell.rb +107 -0
  8. data/app/cells/decidim/proposals/proposal_l/show.erb +37 -0
  9. data/app/cells/decidim/proposals/proposal_l_cell.rb +26 -18
  10. data/app/cells/decidim/proposals/proposal_metadata_cell.rb +2 -2
  11. data/app/cells/decidim/proposals/proposal_vote/show.erb +75 -0
  12. data/app/cells/decidim/proposals/proposal_vote_cell.rb +43 -0
  13. data/app/commands/decidim/proposals/accept_coauthorship.rb +62 -0
  14. data/app/commands/decidim/proposals/admin/assign_proposals_to_valuator.rb +14 -0
  15. data/app/commands/decidim/proposals/admin/create_proposal.rb +6 -14
  16. data/app/commands/decidim/proposals/admin/create_proposal_note.rb +20 -11
  17. data/app/commands/decidim/proposals/admin/import_proposals.rb +0 -5
  18. data/app/commands/decidim/proposals/admin/merge_proposals.rb +2 -2
  19. data/app/commands/decidim/proposals/admin/proposal_notes_methods.rb +48 -0
  20. data/app/commands/decidim/proposals/admin/reply_proposal_note.rb +92 -0
  21. data/app/commands/decidim/proposals/admin/split_proposals.rb +2 -2
  22. data/app/commands/decidim/proposals/admin/update_proposal.rb +10 -16
  23. data/app/commands/decidim/proposals/admin/update_proposal_taxonomies.rb +34 -0
  24. data/app/commands/decidim/proposals/cancel_coauthorship.rb +32 -0
  25. data/app/commands/decidim/proposals/create_collaborative_draft.rb +1 -2
  26. data/app/commands/decidim/proposals/create_proposal.rb +1 -2
  27. data/app/commands/decidim/proposals/invite_coauthor.rb +45 -0
  28. data/app/commands/decidim/proposals/publish_collaborative_draft.rb +1 -2
  29. data/app/commands/decidim/proposals/reject_coauthorship.rb +54 -0
  30. data/app/commands/decidim/proposals/update_collaborative_draft.rb +1 -2
  31. data/app/commands/decidim/proposals/update_proposal.rb +1 -2
  32. data/app/controllers/concerns/decidim/proposals/admin/filterable.rb +6 -2
  33. data/app/controllers/concerns/decidim/proposals/admin/needs_interpolations.rb +40 -0
  34. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +50 -2
  35. data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +18 -0
  36. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +41 -85
  37. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +2 -4
  38. data/app/controllers/decidim/proposals/invite_coauthors_controller.rb +87 -0
  39. data/app/controllers/decidim/proposals/proposals_controller.rb +11 -40
  40. data/app/events/decidim/proposals/accepted_coauthorship_event.rb +8 -0
  41. data/app/events/decidim/proposals/admin/proposal_assigned_to_valuator_event.rb +27 -0
  42. data/app/events/decidim/proposals/admin/proposal_note_created_event.rb +5 -0
  43. data/app/events/decidim/proposals/coauthor_accepted_invite_event.rb +49 -0
  44. data/app/events/decidim/proposals/coauthor_invited_event.rb +45 -0
  45. data/app/events/decidim/proposals/coauthor_rejected_invite_event.rb +8 -0
  46. data/app/events/decidim/proposals/rejected_coauthorship_event.rb +8 -0
  47. data/app/events/decidim/proposals/update_proposal_taxonomies_event.rb +9 -0
  48. data/app/forms/decidim/proposals/admin/proposal_answer_form.rb +4 -3
  49. data/app/forms/decidim/proposals/admin/proposal_base_form.rb +3 -31
  50. data/app/forms/decidim/proposals/admin/proposal_form.rb +12 -7
  51. data/app/forms/decidim/proposals/admin/proposals_import_form.rb +6 -14
  52. data/app/forms/decidim/proposals/admin/valuation_assignment_form.rb +4 -1
  53. data/app/forms/decidim/proposals/collaborative_draft_form.rb +0 -8
  54. data/app/forms/decidim/proposals/proposal_form.rb +5 -32
  55. data/app/helpers/decidim/proposals/admin/proposal_bulk_actions_helper.rb +26 -1
  56. data/app/helpers/decidim/proposals/admin/proposals_helper.rb +0 -1
  57. data/app/helpers/decidim/proposals/application_helper.rb +23 -14
  58. data/app/helpers/decidim/proposals/collaborative_draft_helper.rb +7 -7
  59. data/app/helpers/decidim/proposals/map_helper.rb +0 -18
  60. data/app/helpers/decidim/proposals/proposal_votes_helper.rb +15 -2
  61. data/app/jobs/decidim/proposals/admin/proposal_answer_job.rb +20 -0
  62. data/app/models/decidim/proposals/collaborative_draft.rb +10 -1
  63. data/app/models/decidim/proposals/proposal.rb +67 -10
  64. data/app/models/decidim/proposals/proposal_note.rb +11 -0
  65. data/app/models/decidim/proposals/proposal_state.rb +1 -1
  66. data/app/packs/entrypoints/decidim_proposals.js +1 -0
  67. data/app/packs/entrypoints/decidim_proposals_geocoding.js +2 -0
  68. data/app/packs/src/decidim/proposals/admin/proposals.js +16 -1
  69. data/app/packs/src/decidim/proposals/exit_handler.js +73 -0
  70. data/app/packs/stylesheets/decidim/proposals/proposals.scss +246 -5
  71. data/app/permissions/decidim/proposals/admin/permissions.rb +2 -5
  72. data/app/permissions/decidim/proposals/permissions.rb +46 -3
  73. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +1 -1
  74. data/app/presenters/decidim/proposals/proposal_presenter.rb +1 -1
  75. data/app/queries/decidim/proposals/filtered_proposals.rb +2 -2
  76. data/app/queries/decidim/proposals/metrics/accepted_proposals_metric_manage.rb +2 -2
  77. data/app/queries/decidim/proposals/metrics/endorsements_metric_manage.rb +10 -10
  78. data/app/queries/decidim/proposals/metrics/proposal_followers_metric_measure.rb +4 -4
  79. data/app/queries/decidim/proposals/metrics/proposal_participants_metric_measure.rb +6 -6
  80. data/app/queries/decidim/proposals/metrics/proposals_metric_manage.rb +6 -6
  81. data/app/queries/decidim/proposals/metrics/votes_metric_manage.rb +6 -6
  82. data/app/services/decidim/proposals/collaborative_draft_diff_renderer.rb +22 -0
  83. data/app/services/decidim/proposals/diff_renderer.rb +2 -0
  84. data/app/services/decidim/proposals/proposal_builder.rb +2 -2
  85. data/app/views/decidim/proposals/admin/proposal_notes/_form.html.erb +3 -3
  86. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_note.html.erb +28 -0
  87. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_note_reply.html.erb +9 -0
  88. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes.html.erb +4 -28
  89. data/app/views/decidim/proposals/admin/proposal_states/_form.html.erb +1 -1
  90. data/app/views/decidim/proposals/admin/proposals/_actions.html.erb +21 -0
  91. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +3 -2
  92. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +16 -23
  93. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +12 -28
  94. data/app/views/decidim/proposals/admin/proposals/_proposals-thead.html.erb +45 -0
  95. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_apply_answer_template.html.erb +22 -0
  96. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +15 -11
  97. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_taxonomy_change.html.erb +23 -0
  98. data/app/views/decidim/proposals/admin/proposals/index.html.erb +17 -48
  99. data/app/views/decidim/proposals/admin/proposals/manage_trash.html.erb +18 -0
  100. data/app/views/decidim/proposals/admin/proposals/publish_answers.js.erb +1 -1
  101. data/app/views/decidim/proposals/admin/proposals/show.html.erb +10 -22
  102. data/app/views/decidim/proposals/admin/proposals/update_attribute.js.erb +1 -1
  103. data/app/views/decidim/proposals/admin/proposals_imports/new.html.erb +2 -5
  104. data/app/views/decidim/proposals/collaborative_drafts/_collaborative_actions.html.erb +9 -0
  105. data/app/views/decidim/proposals/collaborative_drafts/_collaborative_draft_aside.html.erb +0 -15
  106. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +4 -6
  107. data/app/views/decidim/proposals/collaborative_drafts/index.html.erb +6 -2
  108. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +27 -11
  109. data/app/views/decidim/proposals/proposal_votes/update_buttons_and_counters.js.erb +29 -9
  110. data/app/views/decidim/proposals/proposals/_actions.html.erb +4 -7
  111. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +17 -22
  112. data/app/views/decidim/proposals/proposals/_exit_modal.html.erb +17 -0
  113. data/app/views/decidim/proposals/proposals/_notification_alert_box.html.erb +1 -0
  114. data/app/views/decidim/proposals/proposals/_proposal_actions.html.erb +19 -0
  115. data/app/views/decidim/proposals/proposals/_proposal_aside.html.erb +9 -32
  116. data/app/views/decidim/proposals/proposals/_proposal_voting_rules.html.erb +33 -0
  117. data/app/views/decidim/proposals/proposals/_remaining_votes_count.html.erb +2 -2
  118. data/app/views/decidim/proposals/proposals/_remaining_votes_notification.html.erb +12 -0
  119. data/app/views/decidim/proposals/proposals/_update_proposal_voting_rules.html.erb +6 -0
  120. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +12 -8
  121. data/app/views/decidim/proposals/proposals/_votes_count.html.erb +2 -1
  122. data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +1 -7
  123. data/app/views/decidim/proposals/proposals/index.html.erb +10 -18
  124. data/app/views/decidim/proposals/proposals/index.js.erb +12 -0
  125. data/app/views/decidim/proposals/proposals/participatory_texts/_proposal_vote_button.html.erb +3 -1
  126. data/app/views/decidim/proposals/proposals/show.html.erb +36 -16
  127. data/config/locales/ar.yml +19 -75
  128. data/config/locales/bg.yml +7 -91
  129. data/config/locales/bn-BD.yml +1 -0
  130. data/config/locales/bs-BA.yml +87 -0
  131. data/config/locales/ca.yml +213 -73
  132. data/config/locales/cs.yml +229 -75
  133. data/config/locales/de.yml +217 -78
  134. data/config/locales/el.yml +9 -85
  135. data/config/locales/en.yml +209 -69
  136. data/config/locales/es-MX.yml +220 -80
  137. data/config/locales/es-PY.yml +215 -75
  138. data/config/locales/es.yml +222 -82
  139. data/config/locales/eu.yml +293 -147
  140. data/config/locales/fi-plain.yml +222 -81
  141. data/config/locales/fi.yml +239 -98
  142. data/config/locales/fr-CA.yml +119 -90
  143. data/config/locales/fr.yml +118 -89
  144. data/config/locales/ga-IE.yml +0 -19
  145. data/config/locales/gl.yml +9 -47
  146. data/config/locales/he-IL.yml +7 -0
  147. data/config/locales/hu.yml +7 -68
  148. data/config/locales/id-ID.yml +9 -36
  149. data/config/locales/is-IS.yml +0 -21
  150. data/config/locales/it.yml +10 -56
  151. data/config/locales/ja.yml +164 -91
  152. data/config/locales/lt.yml +9 -86
  153. data/config/locales/lv.yml +8 -47
  154. data/config/locales/nl.yml +7 -54
  155. data/config/locales/no.yml +9 -46
  156. data/config/locales/pl.yml +7 -91
  157. data/config/locales/pt-BR.yml +7 -77
  158. data/config/locales/pt.yml +9 -57
  159. data/config/locales/ro-RO.yml +17 -63
  160. data/config/locales/ru.yml +0 -25
  161. data/config/locales/sk.yml +9 -48
  162. data/config/locales/sl.yml +0 -4
  163. data/config/locales/sr-CS.yml +0 -14
  164. data/config/locales/sv.yml +132 -88
  165. data/config/locales/tr-TR.yml +9 -54
  166. data/config/locales/uk.yml +0 -25
  167. data/config/locales/zh-CN.yml +9 -54
  168. data/config/locales/zh-TW.yml +9 -87
  169. data/db/migrate/20171220084719_add_published_at_to_proposals.rb +1 -1
  170. data/db/migrate/20181016132225_add_organization_as_author.rb +1 -1
  171. data/db/migrate/20200120215928_move_proposal_endorsements_to_core_endorsements.rb +1 -1
  172. data/db/migrate/20200827154156_add_commentable_counter_cache_to_proposals.rb +3 -3
  173. data/db/migrate/20210310102839_add_followable_counter_cache_to_proposals.rb +1 -1
  174. data/db/migrate/20240110203504_create_default_proposal_states.rb +4 -3
  175. data/db/migrate/20240404202756_add_valuation_assignments_count_to_decidim_proposals_proposals.rb +1 -1
  176. data/db/migrate/20240617091140_add_email_on_assigned_proposals_to_users.rb +7 -0
  177. data/db/migrate/20240617170052_add_parent_relation_to_decidim_proposal_notes.rb +7 -0
  178. data/db/migrate/20240828103755_add_deleted_at_to_decidim_proposals_proposals.rb +8 -0
  179. data/decidim-proposals.gemspec +2 -2
  180. data/lib/decidim/api/functions/proposal_finder_helper.rb +12 -0
  181. data/lib/decidim/api/functions/proposal_list_helper.rb +12 -0
  182. data/lib/decidim/api/proposal_type.rb +30 -25
  183. data/lib/decidim/api/proposals_type.rb +5 -22
  184. data/lib/decidim/proposals/admin_engine.rb +12 -3
  185. data/lib/decidim/proposals/admin_filter.rb +3 -6
  186. data/lib/decidim/proposals/component.rb +4 -5
  187. data/lib/decidim/proposals/download_your_data_proposal_serializer.rb +15 -0
  188. data/lib/decidim/proposals/engine.rb +5 -0
  189. data/lib/decidim/proposals/import/proposal_creator.rb +4 -4
  190. data/lib/decidim/proposals/proposal_serializer.rb +15 -29
  191. data/lib/decidim/proposals/seeds.rb +21 -17
  192. data/lib/decidim/proposals/test/factories.rb +8 -6
  193. data/lib/decidim/proposals/version.rb +1 -1
  194. data/lib/decidim/proposals.rb +4 -0
  195. metadata +69 -30
  196. data/app/commands/decidim/proposals/admin/update_proposal_category.rb +0 -70
  197. data/app/commands/decidim/proposals/admin/update_proposal_scope.rb +0 -75
  198. data/app/events/decidim/proposals/admin/update_proposal_category_event.rb +0 -11
  199. data/app/events/decidim/proposals/admin/update_proposal_scope_event.rb +0 -11
  200. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_recategorize.html.erb +0 -15
  201. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_scope-change.html.erb +0 -21
  202. data/app/views/decidim/proposals/collaborative_drafts/_actions.html.erb +0 -7
@@ -9,12 +9,23 @@ module Decidim
9
9
 
10
10
  belongs_to :proposal, foreign_key: "decidim_proposal_id", class_name: "Decidim::Proposals::Proposal", counter_cache: true
11
11
  belongs_to :author, foreign_key: "decidim_author_id", class_name: "Decidim::User"
12
+ has_many :replies, foreign_key: "parent_id", class_name: "Decidim::Proposals::ProposalNote", inverse_of: :parent, dependent: :destroy
13
+ belongs_to :parent, class_name: "Decidim::Proposals::ProposalNote", inverse_of: :replies, optional: true
12
14
 
15
+ scope :not_reply, -> { where(parent_id: nil) }
13
16
  default_scope { order(created_at: :asc) }
14
17
 
15
18
  def self.log_presenter_class_for(_log)
16
19
  Decidim::Proposals::AdminLog::ProposalNotePresenter
17
20
  end
21
+
22
+ def reply?
23
+ parent.present?
24
+ end
25
+
26
+ def formatted_body
27
+ Decidim::ContentProcessor.render_without_format(body)
28
+ end
18
29
  end
19
30
  end
20
31
  end
@@ -38,7 +38,7 @@ module Decidim
38
38
  protected
39
39
 
40
40
  def generate_token
41
- self.token = ensure_unique_token(translated_attribute(title).parameterize(separator: "_"))
41
+ self.token = ensure_unique_token(token.presence || translated_attribute(title).parameterize(separator: "_"))
42
42
  end
43
43
 
44
44
  def ensure_unique_token(token)
@@ -1,6 +1,7 @@
1
1
  import "src/decidim/proposals/utils"
2
2
  import "src/decidim/proposals/add_proposal"
3
3
  import "src/decidim/proposals/choose_proposals"
4
+ import "src/decidim/proposals/exit_handler"
4
5
 
5
6
  // Images
6
7
  require.context("../images", true)
@@ -0,0 +1,2 @@
1
+ import "src/decidim/proposals/reverse_geocoding.js"
2
+ import "stylesheets/decidim/proposals/geocoding_addons.scss";
@@ -13,13 +13,20 @@ $(() => {
13
13
  return $(".table-list [data-published-state=false] .js-check-all-proposal:checked").length
14
14
  }
15
15
 
16
+ const selectedProposalsAllowsAnswerCount = function() {
17
+ return $(".table-list [data-allow-answer=true] .js-check-all-proposal:checked").length
18
+ }
19
+
16
20
  const selectedProposalsCountUpdate = function() {
17
21
  const selectedProposals = selectedProposalsCount();
18
22
  const selectedProposalsNotPublishedAnswer = selectedProposalsNotPublishedAnswerCount();
23
+ const allowAnswerProposals = selectedProposalsAllowsAnswerCount();
24
+
19
25
  if (selectedProposals === 0) {
20
26
  $("#js-selected-proposals-count").text("")
21
27
  $("#js-assign-proposals-to-valuator-actions").addClass("hide");
22
28
  $("#js-unassign-proposals-from-valuator-actions").addClass("hide");
29
+ $("#js-taxonomy-change-proposals-actions").addClass("hide");
23
30
  } else {
24
31
  $("#js-selected-proposals-count").text(selectedProposals);
25
32
  }
@@ -36,6 +43,13 @@ $(() => {
36
43
  } else {
37
44
  $('button[data-action="publish-answers"]').parent().hide();
38
45
  }
46
+
47
+ if (allowAnswerProposals > 0) {
48
+ $('button[data-action="apply-answer-template"]').parent().show();
49
+ $("#js-form-apply-answer-template-number").text(allowAnswerProposals);
50
+ } else {
51
+ $('button[data-action="apply-answer-template"]').parent().hide();
52
+ }
39
53
  }
40
54
 
41
55
  const showBulkActionsButton = function() {
@@ -91,7 +105,8 @@ $(() => {
91
105
  let action = $(e.target).data("action");
92
106
  const panelActions = [
93
107
  "assign-proposals-to-valuator",
94
- "unassign-proposals-from-valuator"
108
+ "unassign-proposals-from-valuator",
109
+ "taxonomy-change-proposals"
95
110
  ];
96
111
 
97
112
  if (!action) {
@@ -0,0 +1,73 @@
1
+ const allowExitFrom = (el) => {
2
+ if (el.id === "exit-proposal-notification-link" || el.classList.contains("no-modal")) {
3
+ return true;
4
+ }
5
+
6
+ return false;
7
+ };
8
+
9
+ document.addEventListener("DOMContentLoaded", () => {
10
+ const exitNotification = document.getElementById("exit-proposal-notification");
11
+ const exitLink = document.getElementById("exit-proposal-notification-link");
12
+ if (!exitLink) {
13
+ return;
14
+ }
15
+ const defaultExitUrl = exitLink.href;
16
+ const defaultExitLinkText = exitLink.textContent;
17
+ const signOutPath = window.Decidim.config.get("sign_out_path");
18
+ let exitLinkText = defaultExitLinkText;
19
+
20
+ if (!exitNotification) {
21
+ // Do not apply when not inside the voting pipeline
22
+ return;
23
+ }
24
+
25
+ const openExitNotification = (url, method = null) => {
26
+ if (method && method !== "get") {
27
+ exitLink.setAttribute("data-method", method);
28
+ } else {
29
+ exitLink.removeAttribute("data-method");
30
+ }
31
+
32
+ exitLink.setAttribute("href", url);
33
+ exitLink.textContent = exitLinkText;
34
+ window.Decidim.currentDialogs["exit-proposal-notification"].open();
35
+ };
36
+
37
+ const handleClicks = (link) => {
38
+ link.addEventListener("click", (event) => {
39
+ exitLinkText = defaultExitLinkText;
40
+
41
+ if (
42
+ !allowExitFrom(link) &&
43
+ ((window.Decidim.currentDialogs["exit-proposal-notification"].dialog.querySelector("[data-dialog-container]")).dataset.minimumVotesReached !== "true") &&
44
+ ((window.Decidim.currentDialogs["exit-proposal-notification"].dialog.querySelector("[data-dialog-container]")).dataset.minimumVotesCount > 0)
45
+ ) {
46
+ event.preventDefault();
47
+ openExitNotification(link.getAttribute("href"), link.dataset.method);
48
+ }
49
+ });
50
+ };
51
+
52
+ document.querySelectorAll("a").forEach(handleClicks);
53
+ // Custom handling for the header sign-out link
54
+ const signOutLink = document.querySelector(`[href='${signOutPath}']`);
55
+ if (signOutLink) {
56
+ signOutLink.addEventListener("click", (event) => {
57
+ event.preventDefault();
58
+ event.stopPropagation();
59
+
60
+ exitLinkText = signOutLink.textContent;
61
+ openExitNotification(signOutLink.getAttribute("href"), signOutLink.dataset.method);
62
+ });
63
+ }
64
+
65
+ // Custom handling for links that open the exit notification dialog
66
+ const dialogOpenLinks = document.querySelectorAll("a[data-dialog-open='exit-proposal-notification']");
67
+ dialogOpenLinks.forEach((link) => {
68
+ link.addEventListener("click", () => {
69
+ exitLinkText = defaultExitLinkText;
70
+ openExitNotification(defaultExitUrl);
71
+ });
72
+ });
73
+ });
@@ -103,15 +103,213 @@
103
103
  }
104
104
 
105
105
  &__grid-text-title {
106
- @apply flex justify-between flex-row md:flex-col md:items-start lg:flex-row lg:items-center;
106
+ @apply flex justify-between items-start gap-y-2 flex-row md:flex-col lg:flex-row;
107
+ }
108
+
109
+ &__list-list {
110
+ .card__proposals-item {
111
+ @apply border-l-4 rounded-[10px] md:rounded-md border-[#F5F5F5] hover:border-tertiary focus-visible:border-tertiary flex flex-col md:items-center md:flex-row md:justify-between min-h-0 md:min-h-[127px] lg:min-h-[83px];
112
+
113
+ .card__list {
114
+ @apply border-none md:flex-1 md:items-center mb-2.5 md:mb-0;
115
+
116
+ &-metadata {
117
+ @apply gap-y-1 md:flex md:flex-row md:items-center md:gap-x-2 md:mt-0.5;
118
+
119
+ & > div {
120
+ @apply md:pl-0 md:pr-2;
121
+ }
122
+ }
123
+ }
124
+
125
+ .card__proposals-votes {
126
+ @apply flex md:flex-col lg:flex-row bg-[#F5F5F5] justify-around md:flex-[0.6] lg:flex-[0.8] items-center md:items-stretch lg:items-center lg:min-w-[196px] h-[68px] md:h-auto lg:h-[68px];
127
+
128
+ button {
129
+ @apply bg-[var(--secondary)];
130
+
131
+ &[disabled] {
132
+ @apply opacity-50 text-white border-current cursor-not-allowed;
133
+ }
134
+ }
135
+
136
+ &-limited {
137
+ @apply flex flex-col p-0 md:p-2 lg:p-0 md:flex-row md:flex-wrap lg:flex-col lg:flex-nowrap flex-1 md:flex-none lg:flex-1 justify-center;
138
+
139
+ .proposals__aside-progress {
140
+ @apply flex flex-col w-[80%] items-center md:order-1 lg:order-none md:flex-[1_1_100%] lg:flex-none;
141
+ }
142
+
143
+ .progress-bar {
144
+ &__units {
145
+ @apply md:order-none;
146
+ }
147
+
148
+ &__number {
149
+ span {
150
+ @apply text-sm;
151
+ }
152
+ }
153
+ }
154
+ }
155
+
156
+ &-unlimited {
157
+ @apply flex flex-row flex-1 lg:flex-1 justify-center md:flex-none;
158
+
159
+ .progress-bar__number {
160
+ span {
161
+ @apply text-xl;
162
+ }
163
+ }
164
+ }
165
+
166
+ .progress-bar {
167
+ &__number {
168
+ @apply flex justify-center items-center mx-1;
169
+
170
+ span {
171
+ @apply leading-6 font-semibold #{!important};
172
+ }
173
+ }
174
+
175
+ &__units {
176
+ @apply text-sm leading-[22px] mx-1;
177
+ }
178
+ }
179
+
180
+ &-container {
181
+ @apply flex-1 md:w-full md:flex-none p-2 lg:p-0 lg:m-3 lg:w-[164px];
107
182
 
108
- .label {
109
- @apply md:mt-2;
183
+ button {
184
+ @apply text-sm leading-[18px] font-semibold py-1;
185
+ }
186
+ }
187
+
188
+ &-hidden {
189
+ @apply md:flex-none;
190
+
191
+ .card__proposals-votes-container {
192
+ @apply md:flex-none md:w-[130px] lg:w-[164px] lg:p-0;
193
+ }
194
+ }
195
+ }
110
196
  }
111
197
  }
112
198
 
113
- &__list-metadata {
114
- @apply md:flex md:flex-row md:items-center md:gap-4;
199
+ &__grid-grid {
200
+ @apply md:gap-4;
201
+
202
+ .card__proposals-item {
203
+ @apply flex flex-col justify-between border-solid border-[#D3D5D9] border rounded;
204
+
205
+ .card__grid {
206
+ @apply mb-2.5 md:mb-0 flex-1 justify-between;
207
+
208
+ box-shadow: none !important;
209
+
210
+ &-text {
211
+ @apply justify-end lg:gap-y-8;
212
+ }
213
+
214
+ &-metadata {
215
+ @apply mt-0 md:flex md:flex-row;
216
+
217
+ > :first-child {
218
+ flex: 1 !important;
219
+ }
220
+
221
+ > :not(:first-child) {
222
+ @apply border-r border-[#D3D5D9];
223
+ }
224
+
225
+ & > div {
226
+ @apply px-2 md:px-2;
227
+ }
228
+ }
229
+ }
230
+
231
+ .card__proposals-votes {
232
+ @apply flex bg-[#F5F5F5EE] justify-around items-center px-4 h-[68px];
233
+
234
+ button {
235
+ @apply bg-[var(--secondary)];
236
+
237
+ &[disabled] {
238
+ @apply opacity-50 text-white border-current cursor-not-allowed;
239
+ }
240
+ }
241
+
242
+ &-limited {
243
+ @apply flex flex-col lg:items-start flex-1 md:mr-4 lg:mr-0;
244
+
245
+ .proposals__aside-progress {
246
+ @apply flex flex-col-reverse w-[80%] items-center;
247
+ }
248
+
249
+ .progress-bar {
250
+ &__number {
251
+ @apply lg:w-[80%];
252
+
253
+ span {
254
+ @apply text-sm;
255
+ }
256
+ }
257
+
258
+ &__units {
259
+ @apply flex justify-center w-[80%];
260
+ }
261
+ }
262
+ }
263
+
264
+ &-unlimited {
265
+ @apply flex flex-row flex-1 lg:flex-1 md:flex-none md:mr-4 lg:mr-0;
266
+
267
+ .progress-bar__number {
268
+ span {
269
+ @apply text-xl;
270
+ }
271
+ }
272
+ }
273
+
274
+ .progress-bar {
275
+ &__number {
276
+ @apply flex justify-center items-center;
277
+
278
+ span {
279
+ @apply leading-6 font-semibold #{!important};
280
+ }
281
+ }
282
+
283
+ &__units {
284
+ @apply text-sm leading-[22px] mx-1;
285
+ }
286
+ }
287
+
288
+ &-container {
289
+ @apply flex-1 lg:w-[164px] lg:flex-none;
290
+
291
+ button {
292
+ @apply text-sm leading-[18px] font-semibold py-1;
293
+
294
+ .already-voted-icon {
295
+ @apply w-4 h-4;
296
+ }
297
+ }
298
+ }
299
+
300
+ &-hidden {
301
+ @apply md:justify-end;
302
+
303
+ .card__proposals-votes-container {
304
+ @apply md:flex-none md:w-[130px] lg:w-[164px];
305
+
306
+ button {
307
+ @apply md:px-0 lg:px-6;
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
115
313
  }
116
314
  }
117
315
 
@@ -133,3 +331,46 @@
133
331
  }
134
332
  }
135
333
  }
334
+
335
+ #proposal-voting-rules {
336
+ [id="dropdown-menu-proposal-voting-rules"] {
337
+ &[aria-hidden="true"] {
338
+ @apply hidden;
339
+ }
340
+ }
341
+
342
+ [data-target="dropdown-menu-proposal-voting-rules"] {
343
+ @apply w-full flex items-center justify-between gap-2 p-2 first-of-type:[&>svg]:block last-of-type:[&>svg]:hidden;
344
+
345
+ & > span {
346
+ @apply hidden font-semibold text-secondary;
347
+
348
+ &:only-of-type,
349
+ &.is-active {
350
+ @apply flex items-center gap-2 [&_svg]:fill-current;
351
+ }
352
+ }
353
+
354
+ > svg {
355
+ @apply w-6 h-6 flex-none text-secondary fill-current;
356
+ }
357
+
358
+ &[aria-expanded="false"] > svg:last-of-type,
359
+ &[aria-expanded="true"] > svg:first-of-type {
360
+ @apply hidden;
361
+ }
362
+
363
+ &[aria-expanded="true"] > svg:last-of-type,
364
+ &[aria-expanded="false"] > svg:first-of-type {
365
+ @apply block;
366
+ }
367
+ }
368
+ }
369
+
370
+ .layout-item-complementary {
371
+ @apply container grid grid-cols-1 lg:grid-cols-12;
372
+
373
+ .item_voting_rules {
374
+ @apply lg:col-start-2 lg:col-span-10;
375
+ }
376
+ }
@@ -30,11 +30,8 @@ module Decidim
30
30
  # time limit.
31
31
  allow! if permission_action.subject == :proposal && permission_action.action == :edit && admin_edition_is_available?
32
32
 
33
- # Every user allowed by the space can update the category of the proposal
34
- allow! if permission_action.subject == :proposal_category && permission_action.action == :update
35
-
36
- # Every user allowed by the space can update the scope of the proposal
37
- allow! if permission_action.subject == :proposal_scope && permission_action.action == :update
33
+ # Every user allowed by the space can update the taxonomy of the proposal
34
+ allow! if permission_action.subject == :proposal_taxonomy && permission_action.action == :update
38
35
 
39
36
  # Every user allowed by the space can import proposals from another_component
40
37
  allow! if permission_action.subject == :proposals && permission_action.action == :import
@@ -4,17 +4,20 @@ module Decidim
4
4
  module Proposals
5
5
  class Permissions < Decidim::DefaultPermissions
6
6
  def permissions
7
- return permission_action unless user
8
-
9
7
  # Delegate the admin permission checks to the admin permissions class
10
8
  return Decidim::Proposals::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
11
9
  return permission_action if permission_action.scope != :public
12
10
 
11
+ toggle_allow(!proposal.hidden?) if permission_action.subject == :proposal && permission_action.action == :read
12
+ return permission_action unless user
13
+
13
14
  case permission_action.subject
14
15
  when :proposal
15
- apply_proposal_permissions(permission_action)
16
+ apply_proposal_permissions(permission_action) unless permission_action.action == :read
16
17
  when :collaborative_draft
17
18
  apply_collaborative_draft_permissions(permission_action)
19
+ when :proposal_coauthor_invites
20
+ apply_proposal_coauthor_invites(permission_action)
18
21
  else
19
22
  permission_action
20
23
  end
@@ -158,6 +161,46 @@ module Decidim
158
161
 
159
162
  toggle_allow(collaborative_draft.created_by?(user))
160
163
  end
164
+
165
+ def apply_proposal_coauthor_invites(permission_action)
166
+ return toggle_allow(false) unless coauthor
167
+ return toggle_allow(false) unless proposal
168
+
169
+ case permission_action.action
170
+ when :invite
171
+ toggle_allow(valid_coauthor? && !notification_already_sent?)
172
+ when :cancel
173
+ toggle_allow(valid_coauthor? && notification_already_sent?)
174
+ when :accept, :decline
175
+ toggle_allow(can_be_coauthor?)
176
+ end
177
+ end
178
+
179
+ def coauthor
180
+ context.fetch(:coauthor, nil)
181
+ end
182
+
183
+ def notification_already_sent?
184
+ @notification_already_sent ||= proposal.coauthor_invitations_for(coauthor).any?
185
+ end
186
+
187
+ def coauthor_in_comments?
188
+ @coauthor_in_comments ||= proposal.comments.where(author: coauthor).any?
189
+ end
190
+
191
+ def valid_coauthor?
192
+ return false unless proposal.authors.include?(user)
193
+ return false unless proposal.user_has_actions?(coauthor)
194
+
195
+ coauthor_in_comments?
196
+ end
197
+
198
+ def can_be_coauthor?
199
+ return false unless user == coauthor
200
+ return false unless proposal.user_has_actions?(coauthor)
201
+
202
+ notification_already_sent?
203
+ end
161
204
  end
162
205
  end
163
206
  end
@@ -27,7 +27,7 @@ module Decidim
27
27
 
28
28
  def action_string
29
29
  case action
30
- when "answer", "create", "update", "publish_answer"
30
+ when "answer", "create", "update", "publish_answer", "soft_delete", "restore"
31
31
  "decidim.proposals.admin_log.proposal.#{action}"
32
32
  else
33
33
  super
@@ -40,7 +40,7 @@ module Decidim
40
40
  def title(links: false, extras: true, html_escape: false, all_locales: false)
41
41
  return unless proposal
42
42
 
43
- super proposal.title, links, html_escape, all_locales, extras:
43
+ super(proposal.title, links, html_escape, all_locales, extras:)
44
44
  end
45
45
 
46
46
  def id_and_title(links: false, extras: true, html_escape: false)
@@ -28,8 +28,8 @@ module Decidim
28
28
  # by a range of dates.
29
29
  def query
30
30
  proposals = Decidim::Proposals::Proposal.where(component: @components)
31
- proposals = proposals.where("created_at >= ?", @start_at) if @start_at.present?
32
- proposals = proposals.where("created_at <= ?", @end_at) if @end_at.present?
31
+ proposals = proposals.where(created_at: @start_at..) if @start_at.present?
32
+ proposals = proposals.where(created_at: ..@end_at) if @end_at.present?
33
33
  proposals
34
34
  end
35
35
  end
@@ -18,13 +18,13 @@ module Decidim
18
18
  end
19
19
  @query = Decidim::Proposals::Proposal.where(component: visible_components_from_spaces(spaces)).joins(:component)
20
20
  .left_outer_joins(:category)
21
- @query = @query.where("decidim_proposals_proposals.created_at <= ?", end_time).accepted
21
+ @query = @query.where(decidim_proposals_proposals: { created_at: ..end_time }).accepted
22
22
  @query = @query.group("decidim_categorizations.id", :participatory_space_type, :participatory_space_id)
23
23
  @query
24
24
  end
25
25
 
26
26
  def quantity
27
- @quantity ||= query.where("decidim_proposals_proposals.created_at >= ?", start_time).count
27
+ @quantity ||= query.where(decidim_proposals_proposals: { created_at: start_time.. }).count
28
28
  end
29
29
  end
30
30
  end
@@ -13,9 +13,9 @@ module Decidim
13
13
  next if cumulative_value.zero?
14
14
 
15
15
  quantity_value = quantity[key] || 0
16
- category_id, space_type, space_id, proposal_id = key
16
+ taxonomy_id, space_type, space_id, proposal_id = key
17
17
  record = Decidim::Metric.find_or_initialize_by(day: @day.to_s, metric_type: @metric_name,
18
- organization: @organization, decidim_category_id: category_id,
18
+ organization: @organization, decidim_taxonomy_id: taxonomy_id,
19
19
  participatory_space_type: space_type, participatory_space_id: space_id,
20
20
  related_object_type: "Decidim::Proposals::Proposal", related_object_id: proposal_id)
21
21
  record.assign_attributes(cumulative: cumulative_value, quantity: quantity_value)
@@ -31,18 +31,18 @@ module Decidim
31
31
  components = Decidim::Component.where(participatory_space: retrieve_participatory_spaces).published
32
32
  proposals = Decidim::Proposals::Proposal.where(component: components).not_withdrawn
33
33
  join_components = "INNER JOIN decidim_components ON decidim_components.manifest_name = 'proposals' AND proposals.decidim_component_id = decidim_components.id"
34
- join_categories = <<~EOJOINCATS
35
- LEFT OUTER JOIN decidim_categorizations
36
- ON (proposals.id = decidim_categorizations.categorizable_id
37
- AND decidim_categorizations.categorizable_type = 'Decidim::Proposals::Proposal')
34
+ join_taxonomies = <<~EOJOINCATS
35
+ LEFT OUTER JOIN decidim_taxonomizations
36
+ ON (proposals.id = decidim_taxonomizations.taxonomizable_id
37
+ AND decidim_taxonomizations.taxonomizable_type = 'Decidim::Proposals::Proposal')
38
38
  EOJOINCATS
39
39
  @query = Decidim::Endorsement.joins("INNER JOIN decidim_proposals_proposals proposals ON resource_id = proposals.id")
40
40
  .joins(join_components)
41
- .joins(join_categories)
41
+ .joins(join_taxonomies)
42
42
  .where(resource_id: proposals.pluck(:id))
43
43
  .where(resource_type: Decidim::Proposals::Proposal.name)
44
- @query = @query.where("decidim_endorsements.created_at <= ?", end_time)
45
- @query = @query.group("decidim_categorizations.id",
44
+ @query = @query.where(decidim_endorsements: { created_at: ..end_time })
45
+ @query = @query.group("decidim_taxonomizations.taxonomy_id",
46
46
  :participatory_space_type,
47
47
  :participatory_space_id,
48
48
  :resource_id)
@@ -50,7 +50,7 @@ module Decidim
50
50
  end
51
51
 
52
52
  def quantity
53
- @quantity ||= query.where("decidim_endorsements.created_at >= ?", start_time).count
53
+ @quantity ||= query.where(decidim_endorsements: { created_at: start_time.. }).count
54
54
  end
55
55
  end
56
56
  end
@@ -30,17 +30,17 @@ module Decidim
30
30
 
31
31
  def retrieve_proposals_followers(from_start: false)
32
32
  @proposals_followers ||= Decidim::Follow.where(followable: retrieve_proposals).joins(:user)
33
- .where("decidim_follows.created_at <= ?", end_time)
33
+ .where(decidim_follows: { created_at: ..end_time })
34
34
 
35
- return @proposals_followers.where("decidim_follows.created_at >= ?", start_time) if from_start
35
+ return @proposals_followers.where(decidim_follows: { created_at: start_time.. }) if from_start
36
36
 
37
37
  @proposals_followers
38
38
  end
39
39
 
40
40
  def retrieve_drafts_followers(from_start: false)
41
41
  @drafts_followers ||= Decidim::Follow.where(followable: retrieve_collaborative_drafts).joins(:user)
42
- .where("decidim_follows.created_at <= ?", end_time)
43
- return @drafts_followers.where("decidim_follows.created_at >= ?", start_time) if from_start
42
+ .where(decidim_follows: { created_at: ..end_time })
43
+ return @drafts_followers.where(decidim_follows: { created_at: start_time.. }) if from_start
44
44
 
45
45
  @drafts_followers
46
46
  end
@@ -41,19 +41,19 @@ module Decidim
41
41
  "Decidim::Meetings::Meeting"
42
42
  ]
43
43
  })
44
- .where("decidim_proposals_proposals.published_at <= ?", end_time)
44
+ .where(decidim_proposals_proposals: { published_at: ..end_time })
45
45
  .not_withdrawn
46
46
 
47
- return @proposals.where("decidim_proposals_proposals.published_at >= ?", start_time) if from_start
47
+ return @proposals.where(decidim_proposals_proposals: { published_at: start_time.. }) if from_start
48
48
 
49
49
  @proposals
50
50
  end
51
51
 
52
52
  def retrieve_votes(from_start: false)
53
53
  @votes ||= Decidim::Proposals::ProposalVote.joins(:proposal).where(proposal: retrieve_proposals).joins(:author)
54
- .where("decidim_proposals_proposal_votes.created_at <= ?", end_time)
54
+ .where(decidim_proposals_proposal_votes: { created_at: ..end_time })
55
55
 
56
- return @votes.where("decidim_proposals_proposal_votes.created_at >= ?", start_time) if from_start
56
+ return @votes.where(decidim_proposals_proposal_votes: { created_at: start_time.. }) if from_start
57
57
 
58
58
  @votes
59
59
  end
@@ -61,10 +61,10 @@ module Decidim
61
61
  def retrieve_endorsements(from_start: false)
62
62
  @endorsements ||= Decidim::Endorsement.joins("INNER JOIN decidim_proposals_proposals proposals ON resource_id = proposals.id")
63
63
  .where(resource: retrieve_proposals)
64
- .where("decidim_endorsements.created_at <= ?", end_time)
64
+ .where(decidim_endorsements: { created_at: ..end_time })
65
65
  .where(decidim_author_type: "Decidim::UserBaseEntity")
66
66
 
67
- return @endorsements.where("decidim_endorsements.created_at >= ?", start_time) if from_start
67
+ return @endorsements.where(decidim_endorsements: { created_at: start_time.. }) if from_start
68
68
 
69
69
  @endorsements
70
70
  end