decidim-proposals 0.30.2 → 0.31.0.rc1

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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/proposals/collaborative_draft_metadata_cell.rb +1 -1
  3. data/app/cells/decidim/proposals/proposal_g_cell.rb +4 -4
  4. data/app/cells/decidim/proposals/proposal_l_cell.rb +4 -4
  5. data/app/cells/decidim/proposals/proposal_metadata_cell.rb +2 -2
  6. data/app/commands/decidim/proposals/admin/{assign_proposals_to_valuator.rb → assign_proposals_to_evaluator.rb} +16 -16
  7. data/app/commands/decidim/proposals/admin/create_proposal.rb +1 -2
  8. data/app/commands/decidim/proposals/admin/create_proposal_note.rb +4 -4
  9. data/app/commands/decidim/proposals/admin/merge_proposals.rb +60 -13
  10. data/app/commands/decidim/proposals/admin/notify_proposal_answer.rb +2 -2
  11. data/app/commands/decidim/proposals/admin/proposal_notes_methods.rb +5 -5
  12. data/app/commands/decidim/proposals/admin/reply_proposal_note.rb +1 -1
  13. data/app/commands/decidim/proposals/admin/{unassign_proposals_from_valuator.rb → unassign_proposals_from_evaluator.rb} +7 -7
  14. data/app/commands/decidim/proposals/admin/update_proposal.rb +1 -2
  15. data/app/commands/decidim/proposals/create_collaborative_draft.rb +3 -8
  16. data/app/commands/decidim/proposals/create_proposal.rb +4 -17
  17. data/app/commands/decidim/proposals/publish_collaborative_draft.rb +2 -2
  18. data/app/commands/decidim/proposals/publish_proposal.rb +1 -5
  19. data/app/commands/decidim/proposals/update_collaborative_draft.rb +2 -4
  20. data/app/commands/decidim/proposals/update_proposal.rb +5 -18
  21. data/app/controllers/concerns/decidim/proposals/admin/filterable.rb +6 -6
  22. data/app/controllers/concerns/decidim/proposals/orderable.rb +3 -3
  23. data/app/controllers/decidim/proposals/admin/evaluation_assignments_controller.rb +55 -0
  24. data/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb +6 -6
  25. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +1 -1
  26. data/app/controllers/decidim/proposals/admin/proposal_states_controller.rb +2 -2
  27. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +2 -2
  28. data/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +1 -1
  29. data/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb +12 -3
  30. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +2 -3
  31. data/app/controllers/decidim/proposals/proposals_controller.rb +5 -6
  32. data/app/events/decidim/proposals/admin/{proposal_assigned_to_valuator_event.rb → proposal_assigned_to_evaluator_event.rb} +1 -1
  33. data/app/events/decidim/proposals/{endorsing_enabled_event.rb → liking_enabled_event.rb} +1 -1
  34. data/app/events/decidim/proposals/merged_proposal_event.rb +9 -0
  35. data/app/events/decidim/proposals/proposal_liked_event.rb +33 -0
  36. data/app/forms/decidim/proposals/admin/evaluation_assignment_form.rb +38 -0
  37. data/app/forms/decidim/proposals/admin/proposal_base_form.rb +1 -27
  38. data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +1 -1
  39. data/app/forms/decidim/proposals/admin/proposals_merge_form.rb +58 -2
  40. data/app/forms/decidim/proposals/collaborative_draft_form.rb +1 -5
  41. data/app/forms/decidim/proposals/proposal_form.rb +0 -29
  42. data/app/helpers/decidim/proposals/admin/proposal_bulk_actions_helper.rb +8 -8
  43. data/app/helpers/decidim/proposals/admin/proposal_rankings_helper.rb +6 -6
  44. data/app/helpers/decidim/proposals/admin/proposals_helper.rb +2 -17
  45. data/app/helpers/decidim/proposals/application_helper.rb +3 -6
  46. data/app/jobs/decidim/proposals/settings_change_job.rb +6 -6
  47. data/app/models/decidim/proposals/collaborative_draft.rb +1 -1
  48. data/app/models/decidim/proposals/{valuation_assignment.rb → evaluation_assignment.rb} +7 -7
  49. data/app/models/decidim/proposals/proposal.rb +22 -32
  50. data/app/packs/entrypoints/decidim_proposals_admin.js +1 -0
  51. data/app/packs/src/decidim/proposals/add_proposal.js +1 -1
  52. data/app/packs/src/decidim/proposals/admin/proposals.js +22 -11
  53. data/app/packs/src/decidim/proposals/admin/proposals_form.js +1 -1
  54. data/app/packs/src/decidim/proposals/admin/proposals_merge.js +92 -0
  55. data/app/packs/src/decidim/proposals/choose_proposals.js +1 -1
  56. data/app/packs/src/decidim/proposals/exit_handler.js +1 -1
  57. data/app/packs/src/decidim/proposals/utils.js +1 -1
  58. data/app/packs/stylesheets/decidim/proposals/proposals.scss +29 -1
  59. data/app/permissions/decidim/proposals/admin/permissions.rb +20 -20
  60. data/app/presenters/decidim/proposals/admin_log/{valuation_assignment_presenter.rb → evaluation_assignment_presenter.rb} +7 -7
  61. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +15 -0
  62. data/app/presenters/decidim/proposals/admin_log/value_types/{valuator_role_user_presenter.rb → evaluator_role_user_presenter.rb} +2 -2
  63. data/app/presenters/decidim/proposals/admin_log/value_types/proposal_title_body_presenter.rb +1 -1
  64. data/app/presenters/decidim/proposals/collaborative_draft_presenter.rb +1 -6
  65. data/app/presenters/decidim/proposals/log/{valuation_assignment_presenter.rb → evaluation_assignment_presenter.rb} +1 -1
  66. data/app/presenters/decidim/proposals/proposal_presenter.rb +9 -13
  67. data/app/services/decidim/proposals/diff_renderer.rb +0 -1
  68. data/app/services/decidim/proposals/proposal_builder.rb +5 -10
  69. data/app/views/decidim/proposals/admin/participatory_texts/_article-preview.html.erb +1 -1
  70. data/app/views/decidim/proposals/admin/participatory_texts/index.html.erb +1 -2
  71. data/app/views/decidim/proposals/admin/proposal_notes/_form.html.erb +1 -1
  72. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes.html.erb +1 -1
  73. data/app/views/decidim/proposals/admin/proposal_states/index.html.erb +42 -12
  74. data/app/views/decidim/proposals/admin/proposals/_actions.html.erb +87 -21
  75. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +9 -13
  76. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +2 -24
  77. data/app/views/decidim/proposals/admin/proposals/_likes.html.erb +25 -0
  78. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +13 -12
  79. data/app/views/decidim/proposals/admin/proposals/_proposals-thead.html.erb +1 -1
  80. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_assign_to_evaluator.html.erb +19 -0
  81. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +45 -49
  82. data/app/views/decidim/proposals/admin/proposals/bulk_actions/{_valuators_picker.html.erb → _evaluators_picker.html.erb} +4 -4
  83. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_merge.html.erb +7 -14
  84. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_unassign_from_evaluator.html.erb +19 -0
  85. data/app/views/decidim/proposals/admin/proposals/index.html.erb +9 -5
  86. data/app/views/decidim/proposals/admin/proposals/manage_trash.html.erb +2 -1
  87. data/app/views/decidim/proposals/admin/proposals/show.html.erb +17 -17
  88. data/app/views/decidim/proposals/admin/proposals_merges/_form.html.erb +49 -0
  89. data/app/views/decidim/proposals/admin/proposals_merges/new.html.erb +14 -0
  90. data/app/views/decidim/proposals/collaborative_drafts/_collaborative_actions.html.erb +2 -2
  91. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +1 -21
  92. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +1 -1
  93. data/app/views/decidim/proposals/proposals/_actions.html.erb +2 -2
  94. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +1 -21
  95. data/app/views/decidim/proposals/proposals/_proposal_actions.html.erb +4 -4
  96. data/app/views/decidim/proposals/proposals/_proposal_aside.html.erb +2 -2
  97. data/app/views/decidim/proposals/proposals/_proposal_voting_rules.html.erb +1 -1
  98. data/app/views/decidim/proposals/proposals/participatory_texts/_view_index.html.erb +1 -1
  99. data/app/views/decidim/proposals/proposals/preview.html.erb +1 -1
  100. data/app/views/decidim/proposals/proposals/show.html.erb +2 -2
  101. data/config/assets.rb +2 -2
  102. data/config/locales/ar.yml +0 -65
  103. data/config/locales/bg.yml +0 -71
  104. data/config/locales/bs-BA.yml +0 -25
  105. data/config/locales/ca-IT.yml +64 -72
  106. data/config/locales/ca.yml +64 -72
  107. data/config/locales/cs.yml +52 -81
  108. data/config/locales/de.yml +66 -73
  109. data/config/locales/el.yml +0 -66
  110. data/config/locales/en.yml +69 -77
  111. data/config/locales/es-MX.yml +68 -76
  112. data/config/locales/es-PY.yml +68 -76
  113. data/config/locales/es.yml +68 -76
  114. data/config/locales/eu.yml +66 -74
  115. data/config/locales/fi-plain.yml +67 -75
  116. data/config/locales/fi.yml +67 -75
  117. data/config/locales/fr-CA.yml +49 -74
  118. data/config/locales/fr.yml +49 -74
  119. data/config/locales/ga-IE.yml +0 -22
  120. data/config/locales/gl.yml +0 -47
  121. data/config/locales/hu.yml +0 -64
  122. data/config/locales/id-ID.yml +0 -34
  123. data/config/locales/is-IS.yml +0 -14
  124. data/config/locales/it.yml +0 -58
  125. data/config/locales/ja.yml +68 -76
  126. data/config/locales/lb.yml +0 -3
  127. data/config/locales/lt.yml +0 -68
  128. data/config/locales/lv.yml +0 -62
  129. data/config/locales/nl.yml +0 -63
  130. data/config/locales/no.yml +0 -42
  131. data/config/locales/pl.yml +0 -73
  132. data/config/locales/pt-BR.yml +0 -59
  133. data/config/locales/pt.yml +0 -60
  134. data/config/locales/ro-RO.yml +45 -64
  135. data/config/locales/ru.yml +0 -15
  136. data/config/locales/sk.yml +0 -60
  137. data/config/locales/sr-CS.yml +0 -25
  138. data/config/locales/sv.yml +58 -76
  139. data/config/locales/tr-TR.yml +0 -58
  140. data/config/locales/uk.yml +0 -15
  141. data/config/locales/zh-CN.yml +0 -57
  142. data/config/locales/zh-TW.yml +0 -65
  143. data/db/migrate/20240110203500_add_withdrawn_at_field_to_proposals.rb +1 -1
  144. data/db/migrate/20240110203504_create_default_proposal_states.rb +1 -1
  145. data/db/migrate/20250121110014_rename_proposal_valuation_assignments_to_evaluation_assignments.rb +15 -0
  146. data/db/migrate/20250121110904_rename_valuation_assignments_count_to_evaluation_assignments_count.rb +16 -0
  147. data/db/migrate/20250211141313_rename_valuator_columns.rb +8 -0
  148. data/db/migrate/20250515132351_rename_proposals_endorsements_count_to_likes.rb +7 -0
  149. data/decidim-proposals.gemspec +1 -1
  150. data/lib/decidim/api/mutations/answer_proposal_attributes.rb +17 -0
  151. data/lib/decidim/api/mutations/proposal_answer_type.rb +57 -0
  152. data/lib/decidim/api/mutations/proposal_mutation_type.rb +14 -0
  153. data/lib/decidim/api/mutations/proposals_mutation_type.rb +23 -0
  154. data/lib/decidim/api/proposal_input_sort.rb +1 -1
  155. data/lib/decidim/api/proposal_state_type.rb +16 -0
  156. data/lib/decidim/api/proposal_type.rb +59 -9
  157. data/lib/decidim/proposals/admin_engine.rb +3 -3
  158. data/lib/decidim/proposals/admin_filter.rb +3 -3
  159. data/lib/decidim/proposals/api.rb +5 -0
  160. data/lib/decidim/proposals/component.rb +44 -24
  161. data/lib/decidim/proposals/engine.rb +18 -83
  162. data/lib/decidim/proposals/evaluable.rb +22 -0
  163. data/lib/decidim/proposals/import/proposal_creator.rb +1 -1
  164. data/lib/decidim/proposals/proposal_serializer.rb +9 -11
  165. data/lib/decidim/proposals/seeds.rb +16 -27
  166. data/lib/decidim/proposals/test/factories.rb +21 -53
  167. data/lib/decidim/proposals/version.rb +1 -1
  168. data/lib/decidim/proposals.rb +3 -3
  169. data/lib/tasks/proposals/upgrade/decidim_proposals_upgrade_tasks.rake +11 -11
  170. metadata +57 -47
  171. data/app/commands/decidim/proposals/hashtags_methods.rb +0 -36
  172. data/app/controllers/decidim/proposals/admin/valuation_assignments_controller.rb +0 -55
  173. data/app/events/decidim/proposals/proposal_endorsed_event.rb +0 -33
  174. data/app/forms/decidim/proposals/admin/proposals_file_import_form.rb +0 -31
  175. data/app/forms/decidim/proposals/admin/valuation_assignment_form.rb +0 -38
  176. data/app/queries/decidim/proposals/metrics/accepted_proposals_metric_manage.rb +0 -32
  177. data/app/queries/decidim/proposals/metrics/endorsements_metric_manage.rb +0 -58
  178. data/app/queries/decidim/proposals/metrics/proposal_followers_metric_measure.rb +0 -58
  179. data/app/queries/decidim/proposals/metrics/proposal_participants_metric_measure.rb +0 -74
  180. data/app/queries/decidim/proposals/metrics/proposals_metric_manage.rb +0 -48
  181. data/app/queries/decidim/proposals/metrics/votes_metric_manage.rb +0 -52
  182. data/app/views/decidim/proposals/admin/imports/_proposals_fields.html.erb +0 -11
  183. data/app/views/decidim/proposals/admin/proposals/_endorsers.html.erb +0 -25
  184. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_assign_to_valuator.html.erb +0 -19
  185. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_unassign_from_valuator.html.erb +0 -19
  186. data/lib/decidim/proposals/valuatable.rb +0 -22
@@ -36,8 +36,8 @@ module Decidim
36
36
  end
37
37
  end
38
38
 
39
- def endorsers_presenters_for(proposal)
40
- proposal.endorsements.for_listing.map { |identity| present(identity.normalized_author) }
39
+ def likes_presenters_for(proposal)
40
+ proposal.likes.for_listing.map { |identity| present(identity.author) }
41
41
  end
42
42
 
43
43
  def proposal_complete_state(proposal)
@@ -46,21 +46,6 @@ module Decidim
46
46
 
47
47
  translated_attribute(proposal&.proposal_state&.title)
48
48
  end
49
-
50
- def icon_with_link_to_proposal(proposal)
51
- icon, tooltip = if allowed_to?(:create, :proposal_answer, proposal:) && !proposal.emendation?
52
- [
53
- "question-answer-line",
54
- t(:answer_proposal, scope: "decidim.proposals.actions")
55
- ]
56
- else
57
- [
58
- "information-line",
59
- t(:show, scope: "decidim.proposals.actions")
60
- ]
61
- end
62
- icon_link_to(icon, proposal_path(proposal), tooltip, class: "icon--small action-icon--show-proposal")
63
- end
64
49
  end
65
50
  end
66
51
  end
@@ -8,7 +8,7 @@ module Decidim
8
8
  include Decidim::Comments::CommentsHelper
9
9
  include PaginateHelper
10
10
  include ProposalVotesHelper
11
- include ::Decidim::EndorsableHelper
11
+ include ::Decidim::LikeableHelper
12
12
  include ::Decidim::FollowableHelper
13
13
  include Decidim::MapHelper
14
14
  include Decidim::Proposals::MapHelper
@@ -118,9 +118,8 @@ module Decidim
118
118
  # Returns :text_area or :editor based on the organization' settings.
119
119
  def text_editor_for_proposal_body(form)
120
120
  options = {
121
- class: "js-hashtags",
122
- hashtaggable: true,
123
- value: form_presenter.body(extras: false, strip_tags: !current_organization.rich_text_editor_in_public_views).strip
121
+ value: form_presenter.body(strip_tags: !current_organization.rich_text_editor_in_public_views).strip,
122
+ data: { controller: "character-counter" }
124
123
  }
125
124
 
126
125
  text_editor_for(form, :body, options)
@@ -171,7 +170,6 @@ module Decidim
171
170
  # Explicitly commenting the used I18n keys so their are not flagged as unused
172
171
  # i18n-tasks-use t('decidim.proposals.application_helper.filter_origin_values.official')
173
172
  # i18n-tasks-use t('decidim.proposals.application_helper.filter_origin_values.participants')
174
- # i18n-tasks-use t('decidim.proposals.application_helper.filter_origin_values.user_groups')
175
173
  # i18n-tasks-use t('decidim.proposals.application_helper.filter_origin_values.official')
176
174
  # i18n-tasks-use t('decidim.proposals.application_helper.filter_origin_values.meetings')
177
175
  # i18n-tasks-use t('decidim.proposals.application_helper.filter_origin_values.all')
@@ -180,7 +178,6 @@ module Decidim
180
178
  origin_values = []
181
179
  origin_values << TreePoint.new("official", t("official", scope:)) if component_settings.official_proposals_enabled
182
180
  origin_values << TreePoint.new("participants", t("participants", scope:))
183
- origin_values << TreePoint.new("user_group", t("user_groups", scope:)) if current_organization.user_groups_enabled?
184
181
  origin_values << TreePoint.new("meeting", t("meetings", scope:))
185
182
 
186
183
  TreeNode.new(
@@ -12,9 +12,9 @@ module Decidim
12
12
  elsif voting_enabled?(previous_settings, current_settings)
13
13
  event = "decidim.events.proposals.voting_enabled"
14
14
  event_class = Decidim::Proposals::VotingEnabledEvent
15
- elsif endorsing_enabled?(previous_settings, current_settings)
16
- event = "decidim.events.proposals.endorsing_enabled"
17
- event_class = Decidim::Proposals::EndorsingEnabledEvent
15
+ elsif liking_enabled?(previous_settings, current_settings)
16
+ event = "decidim.events.proposals.liking_enabled"
17
+ event_class = Decidim::Proposals::LikingEnabledEvent
18
18
  end
19
19
 
20
20
  return unless event && event_class
@@ -40,9 +40,9 @@ module Decidim
40
40
  (!!previous_settings[:votes_enabled] == false || previous_settings[:votes_blocked] == true)
41
41
  end
42
42
 
43
- def endorsing_enabled?(previous_settings, current_settings)
44
- (current_settings[:endorsements_enabled] == true && !!current_settings[:endorsements_blocked] == false) &&
45
- (!!previous_settings[:endorsements_enabled] == false || previous_settings[:endorsements_blocked] == true)
43
+ def liking_enabled?(previous_settings, current_settings)
44
+ (current_settings[:likes_enabled] == true && !!current_settings[:likes_blocked] == false) &&
45
+ (!!previous_settings[:likes_enabled] == false || previous_settings[:likes_blocked] == true)
46
46
  end
47
47
  # rubocop:enable Style/DoubleNegation
48
48
  end
@@ -34,7 +34,7 @@ module Decidim
34
34
 
35
35
  STATES = { open: 0, published: 10, withdrawn: -1 }.freeze
36
36
 
37
- enum state: STATES, _default: "open"
37
+ enum :state, STATES, default: "open"
38
38
  scope :except_withdrawn, -> { not_withdrawn.or(where(state: nil)) }
39
39
 
40
40
  scope_search_multi :with_any_state, [:open, :published, :withdrawn]
@@ -2,23 +2,23 @@
2
2
 
3
3
  module Decidim
4
4
  module Proposals
5
- # A valuation assignment links a proposal and a Valuator user role.
6
- # Valuators will be users in charge of defining the monetary cost of a
5
+ # An evaluation assignment links a proposal and an Evaluator user role.
6
+ # Evaluators will be users in charge of defining the monetary cost of a
7
7
  # proposal.
8
- class ValuationAssignment < ApplicationRecord
8
+ class EvaluationAssignment < ApplicationRecord
9
9
  include Decidim::Traceable
10
10
  include Decidim::Loggable
11
11
 
12
12
  belongs_to :proposal, foreign_key: "decidim_proposal_id", class_name: "Decidim::Proposals::Proposal",
13
13
  counter_cache: true
14
- belongs_to :valuator_role, polymorphic: true
14
+ belongs_to :evaluator_role, polymorphic: true
15
15
 
16
16
  def self.log_presenter_class_for(_log)
17
- Decidim::Proposals::AdminLog::ValuationAssignmentPresenter
17
+ Decidim::Proposals::AdminLog::EvaluationAssignmentPresenter
18
18
  end
19
19
 
20
- def valuator
21
- valuator_role.user
20
+ def evaluator
21
+ evaluator_role.user
22
22
  end
23
23
  end
24
24
  end
@@ -24,12 +24,13 @@ module Decidim
24
24
  include Decidim::Amendable
25
25
  include Decidim::NewsletterParticipant
26
26
  include Decidim::Randomable
27
- include Decidim::Endorsable
28
- include Decidim::Proposals::Valuatable
27
+ include Decidim::Likeable
28
+ include Decidim::Proposals::Evaluable
29
29
  include Decidim::TranslatableResource
30
30
  include Decidim::TranslatableAttributes
31
31
  include Decidim::FilterableResource
32
32
  include Decidim::SoftDeletable
33
+ include Decidim::Publicable
33
34
 
34
35
  def assign_state(token)
35
36
  proposal_state = Decidim::Proposals::ProposalState.where(component:, token:).first
@@ -94,7 +95,6 @@ module Decidim
94
95
  scope :not_withdrawn, -> { where(withdrawn_at: nil) }
95
96
 
96
97
  scope :drafts, -> { where(published_at: nil) }
97
- scope :published, -> { where.not(published_at: nil) }
98
98
  scope :order_by_most_recent, -> { order(created_at: :desc) }
99
99
 
100
100
  scope :with_availability, lambda { |state_key|
@@ -121,12 +121,12 @@ module Decidim
121
121
  includes(:votes).where(decidim_proposals_proposal_votes: { decidim_author_id: user })
122
122
  }
123
123
 
124
- scope :sort_by_valuation_assignments_count_asc, lambda {
125
- order(valuation_assignments_count: :asc)
124
+ scope :sort_by_evaluation_assignments_count_asc, lambda {
125
+ order(evaluation_assignments_count: :asc)
126
126
  }
127
127
 
128
- scope :sort_by_valuation_assignments_count_desc, lambda {
129
- order(valuation_assignments_count: :desc)
128
+ scope :sort_by_evaluation_assignments_count_desc, lambda {
129
+ order(evaluation_assignments_count: :desc)
130
130
  }
131
131
 
132
132
  scope :state_eq, lambda { |state|
@@ -158,11 +158,11 @@ module Decidim
158
158
  scoped_query
159
159
  }
160
160
 
161
- def self.with_valuation_assigned_to(user, space)
162
- valuator_roles = space.user_roles(:valuator).where(user:)
161
+ def self.with_evaluation_assigned_to(user, space)
162
+ evaluator_roles = space.user_roles(:evaluator).where(user:)
163
163
 
164
- includes(:valuation_assignments)
165
- .where(decidim_proposals_valuation_assignments: { valuator_role_id: valuator_roles })
164
+ includes(:evaluation_assignments)
165
+ .where(decidim_proposals_evaluation_assignments: { evaluator_role_id: evaluator_roles })
166
166
  end
167
167
 
168
168
  acts_as_list scope: :decidim_component_id
@@ -193,7 +193,7 @@ module Decidim
193
193
 
194
194
  def self.retrieve_proposals_for(component)
195
195
  Decidim::Proposals::Proposal.where(component:).joins(:coauthorships)
196
- .includes(:votes, :endorsements)
196
+ .includes(:votes, :likes)
197
197
  .where(decidim_coauthorships: { decidim_author_type: "Decidim::UserBaseEntity" })
198
198
  .not_hidden
199
199
  .published
@@ -207,13 +207,13 @@ module Decidim
207
207
 
208
208
  participants_has_voted_ids = Decidim::Proposals::ProposalVote.joins(:proposal).where(proposal: proposals).joins(:author).map(&:decidim_author_id).flatten.compact.uniq
209
209
 
210
- endorsements_participants_ids = Decidim::Endorsement.where(resource: proposals)
211
- .where(decidim_author_type: "Decidim::UserBaseEntity")
212
- .pluck(:decidim_author_id).to_a.compact.uniq
210
+ likes_participants_ids = Decidim::Like.where(resource: proposals)
211
+ .where(decidim_author_type: "Decidim::UserBaseEntity")
212
+ .pluck(:decidim_author_id).to_a.compact.uniq
213
213
 
214
214
  commentators_ids = Decidim::Comments::Comment.user_commentators_ids_in(proposals)
215
215
 
216
- (endorsements_participants_ids + participants_has_voted_ids + coauthors_recipients_ids + commentators_ids).flatten.compact.uniq
216
+ (likes_participants_ids + participants_has_voted_ids + coauthors_recipients_ids + commentators_ids).flatten.compact.uniq
217
217
  end
218
218
 
219
219
  # Public: Updates the vote count of this proposal.
@@ -232,13 +232,6 @@ module Decidim
232
232
  ProposalVote.where(proposal: self, author: user).any?
233
233
  end
234
234
 
235
- # Public: Checks if the proposal has been published or not.
236
- #
237
- # Returns Boolean.
238
- def published?
239
- published_at.present?
240
- end
241
-
242
235
  # Public: Returns the published state of the proposal.
243
236
  #
244
237
  # Returns Boolean.
@@ -249,9 +242,6 @@ module Decidim
249
242
  proposal_state&.token || "not_answered"
250
243
  end
251
244
 
252
- # This is only used to define the setter, as the getter will be overridden below.
253
- alias_attribute :internal_state, :state
254
-
255
245
  # Public: Returns the internal state of the proposal.
256
246
  #
257
247
  # Returns Boolean.
@@ -386,13 +376,13 @@ module Decidim
386
376
  ProposalSearch.new(self, params, options)
387
377
  end
388
378
 
389
- # method to filter by assigned valuator role ID
390
- def self.valuator_role_ids_has(value)
379
+ # method to filter by assigned evaluator role ID
380
+ def self.evaluator_role_ids_has(value)
391
381
  query = <<-SQL.squish
392
382
  :value = any(
393
- (SELECT decidim_proposals_valuation_assignments.valuator_role_id
394
- FROM decidim_proposals_valuation_assignments
395
- WHERE decidim_proposals_valuation_assignments.decidim_proposal_id = decidim_proposals_proposals.id
383
+ (SELECT decidim_proposals_evaluation_assignments.evaluator_role_id
384
+ FROM decidim_proposals_evaluation_assignments
385
+ WHERE decidim_proposals_evaluation_assignments.decidim_proposal_id = decidim_proposals_proposals.id
396
386
  )
397
387
  )
398
388
  SQL
@@ -400,7 +390,7 @@ module Decidim
400
390
  end
401
391
 
402
392
  def self.ransackable_scopes(_auth_object = nil)
403
- [:with_any_origin, :with_any_state, :state_eq, :voted_by, :coauthored_by, :related_to, :with_any_taxonomies, :valuator_role_ids_has]
393
+ [:with_any_origin, :with_any_state, :state_eq, :voted_by, :coauthored_by, :related_to, :with_any_taxonomies, :evaluator_role_ids_has]
404
394
  end
405
395
 
406
396
  # Create i18n ransackers for :title and :body.
@@ -1,2 +1,3 @@
1
1
  import "src/decidim/proposals/admin/proposals"
2
2
  import "src/decidim/proposals/admin/proposals_form"
3
+ import "src/decidim/proposals/admin/proposals_merge"
@@ -1,7 +1,7 @@
1
1
  import attachGeocoding from "src/decidim/geocoding/attach_input"
2
2
  import getCoordinateInputName from "src/decidim/geocoding/coordinate_input";
3
3
 
4
- $(() => {
4
+ document.addEventListener("turbo:load", () => {
5
5
  const $map = $("#address_map");
6
6
  const $addressInputField = $("[data-decidim-geocoding]");
7
7
 
@@ -4,7 +4,12 @@
4
4
 
5
5
  import TomSelect from "tom-select/dist/cjs/tom-select.popular";
6
6
 
7
- $(() => {
7
+ document.addEventListener("turbo:load", () => {
8
+ let isMergeProposalsClicked = false;
9
+ $('button[data-action="merge-proposals"]').on("click", function() {
10
+ isMergeProposalsClicked = true;
11
+ });
12
+
8
13
  const selectedProposalsCount = function() {
9
14
  return $(".table-list .js-check-all-proposal:checked").length
10
15
  }
@@ -24,8 +29,8 @@ $(() => {
24
29
 
25
30
  if (selectedProposals === 0) {
26
31
  $("#js-selected-proposals-count").text("")
27
- $("#js-assign-proposals-to-valuator-actions").addClass("hide");
28
- $("#js-unassign-proposals-from-valuator-actions").addClass("hide");
32
+ $("#js-assign-proposals-to-evaluator-actions").addClass("hide");
33
+ $("#js-unassign-proposals-from-evaluator-actions").addClass("hide");
29
34
  $("#js-taxonomy-change-proposals-actions").addClass("hide");
30
35
  } else {
31
36
  $("#js-selected-proposals-count").text(selectedProposals);
@@ -72,10 +77,16 @@ $(() => {
72
77
  }
73
78
 
74
79
  const showOtherActionsButtons = function() {
80
+ if (isMergeProposalsClicked) {
81
+ return;
82
+ }
75
83
  $("#js-other-actions-wrapper").removeClass("hide");
76
84
  }
77
85
 
78
86
  const hideOtherActionsButtons = function() {
87
+ if (isMergeProposalsClicked) {
88
+ return;
89
+ }
79
90
  $("#js-other-actions-wrapper").addClass("hide");
80
91
  }
81
92
 
@@ -98,14 +109,14 @@ $(() => {
98
109
  hideBulkActionForms();
99
110
  $("#js-bulk-actions-button").addClass("hide");
100
111
 
101
- $("#js-bulk-actions-dropdown ul li button").click(function (e) {
112
+ $("#js-bulk-actions-dropdown li button").click(function (e) {
102
113
  $("#js-bulk-actions-dropdown").removeClass("is-open");
103
114
  hideBulkActionForms();
104
115
 
105
116
  let action = $(e.target).data("action");
106
117
  const panelActions = [
107
- "assign-proposals-to-valuator",
108
- "unassign-proposals-from-valuator",
118
+ "assign-proposals-to-evaluator",
119
+ "unassign-proposals-from-evaluator",
109
120
  "taxonomy-change-proposals"
110
121
  ];
111
122
 
@@ -125,7 +136,7 @@ $(() => {
125
136
  });
126
137
 
127
138
  $(`#js-${action}-actions`).removeClass("hide");
128
- hideBulkActionsButton(true);
139
+ hideBulkActionsButton(!isMergeProposalsClicked);
129
140
  hideOtherActionsButtons();
130
141
  }
131
142
  });
@@ -184,12 +195,12 @@ $(() => {
184
195
  }
185
196
  });
186
197
 
187
- document.addEventListener("DOMContentLoaded", () => {
188
- const valuatorMultiselectContainers = document.querySelectorAll(
189
- ".js-valuator-multiselect"
198
+ document.addEventListener("turbo:load", () => {
199
+ const evaluatorMultiselectContainers = document.querySelectorAll(
200
+ ".js-evaluator-multiselect"
190
201
  );
191
202
 
192
- valuatorMultiselectContainers.forEach((container) => {
203
+ evaluatorMultiselectContainers.forEach((container) => {
193
204
  const config = {
194
205
  plugins: ["remove_button", "dropdown_input"],
195
206
  allowEmptyOption: true
@@ -1,6 +1,6 @@
1
1
  import attachGeocoding from "src/decidim/geocoding/attach_input"
2
2
 
3
- $(() => {
3
+ document.addEventListener("turbo:load", () => {
4
4
  const $form = $(".proposal_form_admin");
5
5
 
6
6
  if ($form.length > 0) {
@@ -0,0 +1,92 @@
1
+ import { createDialog } from "src/decidim/a11y"
2
+ import createEditor from "src/decidim/editor";
3
+ import attachGeocoding from "src/decidim/geocoding/attach_input";
4
+ import { initializeUploadFields } from "src/decidim/direct_uploads/upload_field";
5
+ import { initializeReverseGeocoding } from "src/decidim/geocoding/reverse_geocoding"
6
+
7
+ document.addEventListener("decidim:loaded", () => {
8
+ document.querySelectorAll('button[data-action="merge-proposals"]').forEach((button) => {
9
+ const url = button.dataset.mergeUrl;
10
+ const drawer = window.Decidim.currentDialogs[button.dataset.mergeDialog];
11
+ const container = drawer.dialog.querySelector("#merge-proposals-actions");
12
+
13
+ // Handles changes on the form
14
+ const activateDrawerForm = () => {
15
+ const saveForm = drawer.dialog.querySelector("#form-merge-proposals");
16
+
17
+ // Handles editor initialization
18
+ saveForm.querySelectorAll(".editor-container").forEach((element) => createEditor(element));
19
+ const form = document.querySelector(".proposals_merge_form_admin");
20
+
21
+ // Handles meeting checkbox
22
+ if (form) {
23
+ const proposalCreatedInMeeting = form.querySelector("#proposals_merge_created_in_meeting");
24
+ const proposalMeeting = form.querySelector("#proposals_merge_meeting");
25
+
26
+ const toggleDisabledHiddenFields = () => {
27
+ const enabledMeeting = proposalCreatedInMeeting.checked;
28
+ proposalMeeting.querySelector("select").setAttribute("disabled", "disabled");
29
+
30
+ proposalMeeting.classList.add("hidden");
31
+
32
+ if (enabledMeeting) {
33
+ proposalMeeting.querySelector("select").removeAttribute("disabled");
34
+ proposalMeeting.classList.remove("hidden");
35
+ }
36
+ };
37
+
38
+ proposalCreatedInMeeting.addEventListener("change", toggleDisabledHiddenFields);
39
+ toggleDisabledHiddenFields();
40
+ }
41
+
42
+ // Handles address input (requires jQuery for the moment)
43
+ attachGeocoding($(document.getElementById("proposals_merge_address")));
44
+
45
+ // Handles address reverse_geocoding initialization
46
+ initializeReverseGeocoding()
47
+
48
+ // Handles upload files initialization
49
+ saveForm.querySelectorAll("[data-dialog]").forEach((component) => createDialog(component));
50
+ initializeUploadFields(saveForm.querySelectorAll("button[data-upload]"));
51
+
52
+ // Handles form errors and success
53
+ if (saveForm) {
54
+ saveForm.addEventListener("ajax:success", (event) => {
55
+ const response = event.detail[0];
56
+
57
+ if (response.status === "ok") {
58
+ window.location.reload();
59
+ } else {
60
+ window.location.href = response.redirect_url;
61
+ }
62
+ });
63
+
64
+ saveForm.addEventListener("ajax:error", (event) => {
65
+ const response = event.detail[2];
66
+ container.innerHTML = response.responseText;
67
+ activateDrawerForm();
68
+ });
69
+ }
70
+ }
71
+
72
+ const fetchUrl = (urlToFetch) => {
73
+ container.classList.add("spinner-container");
74
+ fetch(urlToFetch).then((response) => response.text()).then((html) => {
75
+ container.innerHTML = html;
76
+ container.classList.remove("spinner-container");
77
+ // We still need foundation for form validations
78
+ $(container).foundation();
79
+ activateDrawerForm();
80
+ });
81
+ };
82
+
83
+ button.addEventListener("click", () => {
84
+ const selectedProposals = Array.from(document.querySelectorAll(".js-check-all-proposal:checked")).map((checkbox) => checkbox.value);
85
+ const uniqueProposals = [...new Set(selectedProposals)];
86
+
87
+ const queryParams = uniqueProposals.map((id) => `proposal_ids[]=${encodeURIComponent(id)}`).join("&")
88
+ fetchUrl(`${url}?${queryParams}`);
89
+ drawer.open();
90
+ });
91
+ })
92
+ });
@@ -1,6 +1,6 @@
1
1
  import TomSelect from "tom-select/dist/cjs/tom-select.popular";
2
2
 
3
- document.addEventListener("DOMContentLoaded", () => {
3
+ document.addEventListener("turbo:load", () => {
4
4
  const tagContainers = document.querySelectorAll("#proposals_list");
5
5
  tagContainers.forEach((container) => {
6
6
  const { tmName, tmItems, tmNoResults } = container.dataset
@@ -6,7 +6,7 @@ const allowExitFrom = (el) => {
6
6
  return false;
7
7
  };
8
8
 
9
- document.addEventListener("DOMContentLoaded", () => {
9
+ document.addEventListener("turbo:load", () => {
10
10
  const exitNotification = document.getElementById("exit-proposal-notification");
11
11
  const exitLink = document.getElementById("exit-proposal-notification-link");
12
12
  if (!exitLink) {
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-invalid-this */
2
2
 
3
- $(() => {
3
+ document.addEventListener("turbo:load", () => {
4
4
  $("#vote_button").mouseover(function () {
5
5
  $(this).text($(this).data("replace"));
6
6
  });
@@ -1,4 +1,4 @@
1
- @import "tom-select/dist/scss/tom-select";
1
+ @use "tom-select/dist/scss/tom-select";
2
2
 
3
3
  .proposal-list {
4
4
  &__aside {
@@ -405,6 +405,34 @@
405
405
  }
406
406
  }
407
407
 
408
+ #form-merge-proposals {
409
+ .custom-inputs {
410
+ input {
411
+ @apply mt-0;
412
+ }
413
+ }
414
+
415
+ .upload-modal__files-container {
416
+ label {
417
+ @apply mb-0;
418
+ }
419
+
420
+ button {
421
+ @apply mt-0;
422
+ }
423
+ }
424
+ }
425
+
426
+ .form__wrapper,
427
+ .form-proposals-merge-styles {
428
+ .proposal-field-custom-style {
429
+ & label:not(&-checkbox-label),
430
+ &-block label:not(&-checkbox-label) {
431
+ @apply font-normal text-sm;
432
+ }
433
+ }
434
+ }
435
+
408
436
  .proposal__aside-vote {
409
437
  button[disabled] {
410
438
  @apply bg-[var(--secondary)] opacity-50 text-white border-current cursor-not-allowed;
@@ -8,12 +8,12 @@ module Decidim
8
8
  # The public part needs to be implemented yet
9
9
  return permission_action if permission_action.scope != :admin
10
10
 
11
- # Valuators can only perform these actions
12
- if user_is_valuator?
13
- if valuator_assigned_to_proposal?
11
+ # Evaluators can only perform these actions
12
+ if user_is_evaluator?
13
+ if evaluator_assigned_to_proposal?
14
14
  can_create_proposal_note?
15
15
  can_create_proposal_answer?
16
- can_assign_valuator_to_proposal?
16
+ can_assign_evaluator_to_proposal?
17
17
  end
18
18
  can_export_proposals?
19
19
 
@@ -45,11 +45,11 @@ module Decidim
45
45
  # Every user allowed by the space can split proposals to another component
46
46
  allow! if permission_action.subject == :proposals && permission_action.action == :split
47
47
 
48
- # Every user allowed by the space can assign proposals to a valuator
49
- can_assign_valuator_to_proposal?
48
+ # Every user allowed by the space can assign proposals to a evaluator
49
+ can_assign_evaluator_to_proposal?
50
50
 
51
- # Every user allowed by the space can unassign a valuator from proposals
52
- can_unassign_valuator_from_proposals?
51
+ # Every user allowed by the space can unassign a evaluator from proposals
52
+ can_unassign_evaluator_from_proposals?
53
53
 
54
54
  # Only admin users can publish many answers at once
55
55
  toggle_allow(user.admin?) if permission_action.subject == :proposals && permission_action.action == :publish_answers
@@ -80,20 +80,20 @@ module Decidim
80
80
  @proposal ||= context.fetch(:proposal, nil)
81
81
  end
82
82
 
83
- def user_valuator_role
84
- @user_valuator_role ||= space.user_roles(:valuator).find_by(user:)
83
+ def user_evaluator_role
84
+ @user_evaluator_role ||= space.user_roles(:evaluator).find_by(user:)
85
85
  end
86
86
 
87
- def user_is_valuator?
87
+ def user_is_evaluator?
88
88
  return if user.admin?
89
89
 
90
- user_valuator_role.present?
90
+ user_evaluator_role.present?
91
91
  end
92
92
 
93
- def valuator_assigned_to_proposal?
94
- @valuator_assigned_to_proposal ||=
95
- Decidim::Proposals::ValuationAssignment
96
- .where(proposal:, valuator_role: user_valuator_role)
93
+ def evaluator_assigned_to_proposal?
94
+ @evaluator_assigned_to_proposal ||=
95
+ Decidim::Proposals::EvaluationAssignment
96
+ .where(proposal:, evaluator_role: user_evaluator_role)
97
97
  .any?
98
98
  end
99
99
 
@@ -142,12 +142,12 @@ module Decidim
142
142
  toggle_allow(admin_proposal_answering_is_enabled?) if permission_action.subject == :proposal_answer
143
143
  end
144
144
 
145
- def can_unassign_valuator_from_proposals?
146
- allow! if permission_action.subject == :proposals && permission_action.action == :unassign_from_valuator
145
+ def can_unassign_evaluator_from_proposals?
146
+ allow! if permission_action.subject == :proposals && permission_action.action == :unassign_from_evaluator
147
147
  end
148
148
 
149
- def can_assign_valuator_to_proposal?
150
- allow! if permission_action.subject == :proposals && permission_action.action == :assign_to_valuator
149
+ def can_assign_evaluator_to_proposal?
150
+ allow! if permission_action.subject == :proposals && permission_action.action == :assign_to_evaluator
151
151
  end
152
152
 
153
153
  def can_export_proposals?