decidim-stratified_sortitions 0.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +91 -0
- data/Rakefile +42 -0
- data/app/cells/decidim/stratified_sortitions/stratified_sortition_cell.rb +21 -0
- data/app/cells/decidim/stratified_sortitions/stratified_sortition_l_cell.rb +22 -0
- data/app/cells/decidim/stratified_sortitions/stratified_sortition_metadata_cell.rb +63 -0
- data/app/commands/decidim/stratified_sortitions/admin/create_stratified_sortition.rb +84 -0
- data/app/commands/decidim/stratified_sortitions/admin/destroy_stratified_sortition.rb +49 -0
- data/app/commands/decidim/stratified_sortitions/admin/duplicate_stratified_sortition.rb +74 -0
- data/app/commands/decidim/stratified_sortitions/admin/import_sample.rb +40 -0
- data/app/commands/decidim/stratified_sortitions/admin/remove_uploaded_samples.rb +53 -0
- data/app/commands/decidim/stratified_sortitions/admin/update_stratified_sortition.rb +174 -0
- data/app/controllers/concerns/decidim/stratified_sortitions/orderable_stratified_sortitions.rb +37 -0
- data/app/controllers/concerns/decidim/stratified_sortitions/strata_charts_data.rb +91 -0
- data/app/controllers/decidim/stratified_sortitions/admin/application_controller.rb +19 -0
- data/app/controllers/decidim/stratified_sortitions/admin/samples_controller.rb +143 -0
- data/app/controllers/decidim/stratified_sortitions/admin/stratified_sortitions_controller.rb +235 -0
- data/app/controllers/decidim/stratified_sortitions/application_controller.rb +13 -0
- data/app/controllers/decidim/stratified_sortitions/charts_pdf_controller_helper.rb +17 -0
- data/app/controllers/decidim/stratified_sortitions/stratified_sortitions_controller.rb +61 -0
- data/app/forms/decidim/stratified_sortitions/admin/sample_upload_form.rb +15 -0
- data/app/forms/decidim/stratified_sortitions/admin/stratified_sortitions_form.rb +155 -0
- data/app/forms/decidim/stratified_sortitions/admin/stratum_form.rb +69 -0
- data/app/forms/decidim/stratified_sortitions/admin/substratum_form.rb +26 -0
- data/app/helpers/decidim/stratified_sortitions/admin/stratified_sortitions_helper.rb +18 -0
- data/app/helpers/decidim/stratified_sortitions/application_helper.rb +85 -0
- data/app/helpers/decidim/stratified_sortitions/charts_pdf_helper.rb +73 -0
- data/app/helpers/decidim/stratified_sortitions/stratified_sortition_cells_helper.rb +56 -0
- data/app/javascript/channels/sample_import_progress.js +12 -0
- data/app/jobs/decidim/stratified_sortitions/admin/execute_sortition_job.rb +21 -0
- data/app/jobs/decidim/stratified_sortitions/admin/import_sample_job.rb +170 -0
- data/app/jobs/decidim/stratified_sortitions/admin/remove_samples_job.rb +19 -0
- data/app/jobs/decidim/stratified_sortitions/admin/sortition_results_export_job.rb +28 -0
- data/app/mailers/decidim/stratified_sortitions/admin/import_mailer.rb +26 -0
- data/app/models/decidim/stratified_sortitions/application_record.rb +9 -0
- data/app/models/decidim/stratified_sortitions/panel_portfolio.rb +165 -0
- data/app/models/decidim/stratified_sortitions/sample_import.rb +14 -0
- data/app/models/decidim/stratified_sortitions/sample_participant.rb +12 -0
- data/app/models/decidim/stratified_sortitions/sample_participant_stratum.rb +11 -0
- data/app/models/decidim/stratified_sortitions/stratified_sortition.rb +74 -0
- data/app/models/decidim/stratified_sortitions/stratum.rb +22 -0
- data/app/models/decidim/stratified_sortitions/substratum.rb +19 -0
- data/app/packs/entrypoints/decidim_stratified_sortitions.js +10 -0
- data/app/packs/entrypoints/decidim_stratified_sortitions_admin.js +9 -0
- data/app/packs/entrypoints/decidim_stratified_sortitions_admin.scss +1 -0
- data/app/packs/images/decidim/stratified_sortitions/icon.svg +1 -0
- data/app/packs/src/decidim/stratified_sortitions/application.js +3 -0
- data/app/packs/src/decidim/stratified_sortitions/results_tabs.js +59 -0
- data/app/packs/src/decidim/stratified_sortitions/stratum_fields.js +302 -0
- data/app/packs/src/decidim/stratified_sortitions/substratum_fields.js +165 -0
- data/app/packs/src/decidim/stratified_sortitions/upload_sample.js +16 -0
- data/app/packs/stylesheets/decidim/stratified_sortitions/admin/stratified_sortitions.scss +210 -0
- data/app/packs/stylesheets/decidim/stratified_sortitions/charts_pdf.scss +148 -0
- data/app/packs/stylesheets/stratified_sortitions.scss +56 -0
- data/app/permissions/decidim/stratified_sortitions/admin/permissions.rb +74 -0
- data/app/permissions/decidim/stratified_sortitions/permissions.rb +23 -0
- data/app/presenters/decidim/stratified_sortitions/admin_log/stratified_sortition_presenter.rb +35 -0
- data/app/queries/decidim/stratified_sortitions/filtered_stratified_sortitions.rb +39 -0
- data/app/serializers/decidim/stratified_sortitions/sortition_result_serializer.rb +116 -0
- data/app/services/decidim/stratified_sortitions/charts_pdf_generator.rb +96 -0
- data/app/services/decidim/stratified_sortitions/fair_sortition_service.rb +247 -0
- data/app/services/decidim/stratified_sortitions/leximin/constraint_builder.rb +180 -0
- data/app/services/decidim/stratified_sortitions/leximin/distribution_solver.rb +217 -0
- data/app/services/decidim/stratified_sortitions/leximin/feasibility_checker.rb +222 -0
- data/app/services/decidim/stratified_sortitions/leximin/panel_generator.rb +149 -0
- data/app/services/decidim/stratified_sortitions/leximin/panel_sampler.rb +125 -0
- data/app/services/decidim/stratified_sortitions/leximin_selector.rb +136 -0
- data/app/services/decidim/stratified_sortitions/sortition_results_exporter.rb +161 -0
- data/app/views/decidim/admin/components/index.html.erb +54 -0
- data/app/views/decidim/stratified_sortitions/admin/import_mailer/import.html.erb +22 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_confirm_execute_modal.html.erb +19 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_confirm_participants_modal.html.erb +20 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_form.html.erb +55 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_navigation_menu.html.erb +10 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_strata.html.erb +22 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_stratum.html.erb +75 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_substrata.html.erb +34 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_substratum.html.erb +54 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/edit.html.erb +21 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/execute.html.erb +155 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/export_charts_pdf.html.erb +38 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/index.html.erb +75 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/new.html.erb +21 -0
- data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/upload_sample.html.erb +117 -0
- data/app/views/decidim/stratified_sortitions/shared/_strata_charts.html.erb +21 -0
- data/app/views/decidim/stratified_sortitions/stratified_sortitions/_results_count.html.erb +15 -0
- data/app/views/decidim/stratified_sortitions/stratified_sortitions/_stratified_sortition.html.erb +1 -0
- data/app/views/decidim/stratified_sortitions/stratified_sortitions/_stratified_sortitions.html.erb +13 -0
- data/app/views/decidim/stratified_sortitions/stratified_sortitions/_tags.html.erb +9 -0
- data/app/views/decidim/stratified_sortitions/stratified_sortitions/index.html.erb +22 -0
- data/app/views/decidim/stratified_sortitions/stratified_sortitions/index.js.erb +5 -0
- data/app/views/decidim/stratified_sortitions/stratified_sortitions/show.html.erb +142 -0
- data/app/views/layouts/decidim/admin/_sidebar_menu.html.erb +45 -0
- data/app/views/layouts/decidim/stratified_sortitions/charts_pdf.html.erb +14 -0
- data/config/assets.rb +24 -0
- data/config/locales/ca.yml +361 -0
- data/config/locales/en.yml +360 -0
- data/config/locales/es.yml +360 -0
- data/config/locales/oc.yml +2 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20251023103900_create_decidim_stratified_sortitions_stratified_sortitions.rb +18 -0
- data/db/migrate/20251104120000_create_stratified_sortitions_strata_and_substrata.decidim_stratified_sortitions.rb +27 -0
- data/db/migrate/20251219120000_create_sample_imports.rb +17 -0
- data/db/migrate/20251219120100_create_sample_participants.rb +19 -0
- data/db/migrate/20251219120200_create_sample_participant_strata.rb +16 -0
- data/db/migrate/20251230130000_change_value_to_text_in_substrata.rb +11 -0
- data/db/migrate/20260102114744_add_status_to_stratified_sortitions.rb +11 -0
- data/db/migrate/20260109105643_allow_null_value_in_substrata.rb +10 -0
- data/db/migrate/20260113121726_add_position_to_strata_and_substrata.rb +8 -0
- data/db/migrate/20260127100000_rename_weighing_to_max_quota_percentage.rb +12 -0
- data/db/migrate/20260127120000_create_panel_portfolios.rb +46 -0
- data/db/migrate/20260518000000_add_foreign_key_to_stratified_sortitions_component.rb +10 -0
- data/db/migrate/20260521000000_add_cascade_to_stratified_sortitions_foreign_keys.rb +64 -0
- data/db/migrate/20260616000000_add_execution_error_to_stratified_sortitions.rb +11 -0
- data/lib/decidim/stratified_sortitions/admin.rb +10 -0
- data/lib/decidim/stratified_sortitions/admin_engine.rb +49 -0
- data/lib/decidim/stratified_sortitions/component.rb +41 -0
- data/lib/decidim/stratified_sortitions/engine.rb +34 -0
- data/lib/decidim/stratified_sortitions/seeds.rb +24 -0
- data/lib/decidim/stratified_sortitions/test/factories.rb +80 -0
- data/lib/decidim/stratified_sortitions/version.rb +13 -0
- data/lib/decidim/stratified_sortitions.rb +29 -0
- metadata +222 -0
data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/upload_sample.html.erb
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<% add_decidim_page_title(t(".title")) %>
|
|
2
|
+
<div class="item_show__header stratified_sortition_header">
|
|
3
|
+
<h1 class="item_show__header-title">
|
|
4
|
+
<%= t(".title") %>
|
|
5
|
+
</h1>
|
|
6
|
+
</div>
|
|
7
|
+
<%= render 'navigation_menu' %>
|
|
8
|
+
<div class="card mt-12">
|
|
9
|
+
<div class="item_show__header">
|
|
10
|
+
<h1 class="item_show__header-title">
|
|
11
|
+
<div>
|
|
12
|
+
<%= t(".upload_census") %>
|
|
13
|
+
</div>
|
|
14
|
+
</h1>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="mt-1">
|
|
17
|
+
<%= t(".description").html_safe %>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="card-section mt-4 example-file-census-container">
|
|
20
|
+
<table>
|
|
21
|
+
<tr>
|
|
22
|
+
<td><%= t('.example_headers.personal_data_1') %></td>
|
|
23
|
+
<td><%= t('.example_headers.personal_data_2') %></td>
|
|
24
|
+
<td><%= t('.example_headers.personal_data_3') %></td>
|
|
25
|
+
<td><%= t('.example_headers.personal_data_4') %></td>
|
|
26
|
+
<td><%= t('.example_headers.gender') %></td>
|
|
27
|
+
<td><%= t('.example_headers.age') %></td>
|
|
28
|
+
</tr>
|
|
29
|
+
<% Array(t('.example_rows')).each do |row| %>
|
|
30
|
+
<tr>
|
|
31
|
+
<% row.each do |cell| %>
|
|
32
|
+
<td><%= cell %></td>
|
|
33
|
+
<% end %>
|
|
34
|
+
</tr>
|
|
35
|
+
<% end %>
|
|
36
|
+
</table>
|
|
37
|
+
<div class="mt-12">
|
|
38
|
+
<button type="button" class="button button__sm button__secondary" data-toggle="sample-template-dropdown">
|
|
39
|
+
<%= t(".download_template") %>
|
|
40
|
+
<%= icon "arrow-down-s-line", class: "dropdown-filter-icon" %>
|
|
41
|
+
</button>
|
|
42
|
+
<div class="dropdown-pane" id="sample-template-dropdown" data-dropdown data-position="bottom" data-alignment="left" data-auto-focus="true" data-close-on-click="true">
|
|
43
|
+
<ul class="vertical menu add-components">
|
|
44
|
+
<%= link_to download_template_samples_path(id: @stratified_sortition.id, format: :csv) do %>
|
|
45
|
+
<li><%= t(".download_template_csv") %></li>
|
|
46
|
+
<% end %>
|
|
47
|
+
<%= link_to download_template_samples_path(id: @stratified_sortition.id, format: :xlsx) do %>
|
|
48
|
+
<li><%= t(".download_template_xlsx") %></li>
|
|
49
|
+
<% end %>
|
|
50
|
+
</ul>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="row mt-4 <%= 'upload-disabled-wrapper' if @stratified_sortition.executed? %>">
|
|
55
|
+
<%= decidim_form_for(@form, url: samples_path(id: @stratified_sortition.id), method: :post, html: { id: "sample-upload-form", class: "form", multipart: true }) do |form| %>
|
|
56
|
+
<%= form.upload :file,
|
|
57
|
+
label: false,
|
|
58
|
+
required: true,
|
|
59
|
+
help: [t(".help_csv"), t(".help_submit")],
|
|
60
|
+
button_label: t(".upload_file"),
|
|
61
|
+
button_class: "button button__sm button__secondary upload-census-btn" %>
|
|
62
|
+
<% end %>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="card mt-16">
|
|
66
|
+
<div class="item_show__header">
|
|
67
|
+
<h1 class="item_show__header-title">
|
|
68
|
+
<div>
|
|
69
|
+
<%= t(".uploaded_file") %>
|
|
70
|
+
</div>
|
|
71
|
+
</h1>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="mt-2">
|
|
74
|
+
<% if @stratified_sortition.status == "pending" %>
|
|
75
|
+
<%= link_to t('.remove_uploaded_samples'), remove_multiple_samples_path(id: @stratified_sortition.id), class: 'button button__sm button__secondary', data: { method: :delete, confirm: t('.confirm_remove_uploaded_samples') } %>
|
|
76
|
+
<% end %>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="mt-4 mb-4">
|
|
79
|
+
<div class="flex justify-between gap-x-4">
|
|
80
|
+
<span>
|
|
81
|
+
<%= t(".count_uploaded_files", count: @sample_participants_count).html_safe %>
|
|
82
|
+
</span>
|
|
83
|
+
<% if @last_sample.present? %>
|
|
84
|
+
<span class="last-census-upload">
|
|
85
|
+
<%= t(".last_upload_date", date: @last_sample.created_at.strftime("%d/%m/%Y %H:%M")) %>
|
|
86
|
+
</span>
|
|
87
|
+
<% end %>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="mt-4 mb-4">
|
|
91
|
+
<div class="row chart-row">
|
|
92
|
+
<div class="col-md-6 charts-column">
|
|
93
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @strata_data, title: t(".target") } %>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="col-md-6 charts-column target">
|
|
96
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @candidates_data, title: t(".candidates") } %>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="mt-16 census_file_type">
|
|
100
|
+
<span>
|
|
101
|
+
<%= t(".uploaded_files") %>
|
|
102
|
+
</span>
|
|
103
|
+
<% if @samples.empty? %>
|
|
104
|
+
<p><%= t('.no_uploaded_files') %></p>
|
|
105
|
+
<% else %>
|
|
106
|
+
<div>
|
|
107
|
+
<% @samples.each do |sample| %>
|
|
108
|
+
<p><%= t('.filename_data', filename: sample.filename, date: sample.created_at.strftime("%d/%m/%Y %H:%M"), count: sample.imported_rows) %></p>
|
|
109
|
+
<% end %>
|
|
110
|
+
</div>
|
|
111
|
+
<% end %>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<%= append_javascript_pack_tag "decidim_stratified_sortitions_admin" %>
|
|
117
|
+
<%= append_stylesheet_pack_tag "decidim_stratified_sortitions_admin" %>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<span>
|
|
2
|
+
<h3 class="h4 mb-4">
|
|
3
|
+
<%= local_assigns[:title] || "" %>
|
|
4
|
+
</h3>
|
|
5
|
+
</span>
|
|
6
|
+
<% (strata_data || []).each do |stratum_data| %>
|
|
7
|
+
<div class="chart-col">
|
|
8
|
+
<b><%= translated_attribute(stratum_data[:stratum].name).upcase %></b>
|
|
9
|
+
<% if stratum_data[:chart_data].present? %>
|
|
10
|
+
<div style="width:100%;min-width:0">
|
|
11
|
+
<%= pie_chart stratum_data[:chart_data],
|
|
12
|
+
legend: "bottom",
|
|
13
|
+
donut: false %>
|
|
14
|
+
</div>
|
|
15
|
+
<% else %>
|
|
16
|
+
<p class="text-muted">
|
|
17
|
+
<%= t("no_data", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
18
|
+
</p>
|
|
19
|
+
<% end %>
|
|
20
|
+
</div>
|
|
21
|
+
<% end %>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<% executed = stratified_sortition.panel_portfolio&.sampled? %>
|
|
2
|
+
<% count = executed ? stratified_sortition.panel_portfolio.selected_panel.size : stratified_sortition.num_candidates %>
|
|
3
|
+
|
|
4
|
+
<div id="stratified-sortition-<%= stratified_sortition.id %>-results-count">
|
|
5
|
+
<span class="stratified-sortition__aside__count-number">
|
|
6
|
+
<%= count %>
|
|
7
|
+
</span>
|
|
8
|
+
<span class="stratified-sortition__aside__count-text">
|
|
9
|
+
<% if executed %>
|
|
10
|
+
<%= t(".count_selected", count:) %>
|
|
11
|
+
<% else %>
|
|
12
|
+
<%= t(".count", count:) %>
|
|
13
|
+
<% end %>
|
|
14
|
+
</span>
|
|
15
|
+
</div>
|
data/app/views/decidim/stratified_sortitions/stratified_sortitions/_stratified_sortition.html.erb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= card_for stratified_sortition %>
|
data/app/views/decidim/stratified_sortitions/stratified_sortitions/_stratified_sortitions.html.erb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<% if @stratified_sortitions.any? %>
|
|
2
|
+
<h2 class="h5 md:h3 decorator" aria-live="polite" aria-atomic="true"><%= t("count", scope: "decidim.stratified_sortitions.stratified_sortitions.stratified_sortitions_count", count: @stratified_sortitions.total_count) %></h2>
|
|
3
|
+
|
|
4
|
+
<%= order_selector available_orders, i18n_scope: "decidim.stratified_sortitions.stratified_sortitions.orders" %>
|
|
5
|
+
|
|
6
|
+
<div class="card__list-list">
|
|
7
|
+
<%= render @stratified_sortitions %>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<%= decidim_paginate @stratified_sortitions %>
|
|
11
|
+
<% else %>
|
|
12
|
+
<%= cell "decidim/announcement", t("empty", scope: "decidim.stratified_sortitions.stratified_sortitions.index") %>
|
|
13
|
+
<% end %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<ul>
|
|
2
|
+
<li>
|
|
3
|
+
<%= link_to t("filters.pending", scope: "decidim.stratified_sortitions.stratified_sortitions"),
|
|
4
|
+
stratified_sortitions_path(filter: { with_any_state: "pending" }) if stratified_sortition.status == "pending" %>
|
|
5
|
+
|
|
6
|
+
<%= link_to t("filters.executed", scope: "decidim.stratified_sortitions.stratified_sortitions"),
|
|
7
|
+
stratified_sortitions_path(filter: { with_any_state: "executed" }) if stratified_sortition.status == "executed" %>
|
|
8
|
+
</li>
|
|
9
|
+
</ul>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<% add_decidim_meta_tags(
|
|
2
|
+
description: translated_attribute(current_component.participatory_space.try(:description)),
|
|
3
|
+
title: t("decidim.components.pagination.page_title",
|
|
4
|
+
component_name:,
|
|
5
|
+
current_page: @stratified_sortitions.current_page,
|
|
6
|
+
total_pages: @stratified_sortitions.total_pages ),
|
|
7
|
+
url: stratified_sortitions_url,
|
|
8
|
+
resource: current_component) %>
|
|
9
|
+
|
|
10
|
+
<% content_for :aside do %>
|
|
11
|
+
<h1 class="title-decorator"><%= component_name %></h1>
|
|
12
|
+
|
|
13
|
+
<%= render layout: "decidim/shared/filters", locals: { filter_sections: filter_sections_stratified_sortitions, search_variable: :search_text_cont, skip_to_id: "stratified_sortitions" } do %>
|
|
14
|
+
<%= hidden_field_tag :order, order, id: nil, class: "order_filter" %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
|
|
18
|
+
<%= render layout: "layouts/decidim/shared/layout_two_col" do %>
|
|
19
|
+
<section id="stratified_sortitions" class="layout-main__section layout-main__heading">
|
|
20
|
+
<%= render partial: "stratified_sortitions" %>
|
|
21
|
+
</section>
|
|
22
|
+
<% end %>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<% add_decidim_meta_tags({
|
|
2
|
+
description: decidim_sanitize_editor(translated_attribute(stratified_sortition.description)),
|
|
3
|
+
title: decidim_escape_translated(stratified_sortition.title),
|
|
4
|
+
url: stratified_sortition_url(stratified_sortition.to_param)
|
|
5
|
+
}) %>
|
|
6
|
+
|
|
7
|
+
<%
|
|
8
|
+
edit_link(
|
|
9
|
+
resource_locator(stratified_sortition).edit,
|
|
10
|
+
:update,
|
|
11
|
+
:stratified_sortition,
|
|
12
|
+
stratified_sortition:
|
|
13
|
+
)
|
|
14
|
+
%>
|
|
15
|
+
|
|
16
|
+
<%= append_javascript_pack_tag "decidim_stratified_sortitions" %>
|
|
17
|
+
<%= append_stylesheet_pack_tag "decidim_stratified_sortitions" %>
|
|
18
|
+
|
|
19
|
+
<%= render layout: "layouts/decidim/shared/layout_item", locals: { back_path: :stratified_sortitions, commentable: nil } do %>
|
|
20
|
+
<section class="layout-main__section layout-main__heading">
|
|
21
|
+
<h1 class="h1 decorator mb-4">
|
|
22
|
+
<%= decidim_escape_translated(stratified_sortition.title) %>
|
|
23
|
+
</h1>
|
|
24
|
+
</section>
|
|
25
|
+
|
|
26
|
+
<% if translated_attribute(stratified_sortition.description).present? %>
|
|
27
|
+
<section class="layout-main__section">
|
|
28
|
+
<h2 class="h3">
|
|
29
|
+
<%= t("description", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
30
|
+
</h2>
|
|
31
|
+
<div class="editor-content">
|
|
32
|
+
<%= decidim_sanitize_editor_admin translated_attribute stratified_sortition.description %>
|
|
33
|
+
</div>
|
|
34
|
+
</section>
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<% if translated_attribute(stratified_sortition.selection_criteria).present? %>
|
|
38
|
+
<section class="layout-main__section">
|
|
39
|
+
<h2 class="h3">
|
|
40
|
+
<%= t("selection_criteria", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
41
|
+
</h2>
|
|
42
|
+
<div class="editor-content">
|
|
43
|
+
<%= decidim_sanitize_editor_admin translated_attribute stratified_sortition.selection_criteria %>
|
|
44
|
+
</div>
|
|
45
|
+
</section>
|
|
46
|
+
<% end %>
|
|
47
|
+
|
|
48
|
+
<% if translated_attribute(stratified_sortition.selected_profiles_description).present? %>
|
|
49
|
+
<section class="layout-main__section">
|
|
50
|
+
<h2 class="h3">
|
|
51
|
+
<% if stratified_sortition.executed? %>
|
|
52
|
+
<%= t("selected_profiles_description", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
53
|
+
<% else %>
|
|
54
|
+
<%= t("to_be_selected_profiles_description", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
55
|
+
<% end %>
|
|
56
|
+
</h2>
|
|
57
|
+
<div class="editor-content">
|
|
58
|
+
<%= decidim_sanitize_editor_admin translated_attribute stratified_sortition.selected_profiles_description %>
|
|
59
|
+
</div>
|
|
60
|
+
</section>
|
|
61
|
+
<% end %>
|
|
62
|
+
|
|
63
|
+
<% if @strata_data.present? || @candidates_data.present? %>
|
|
64
|
+
<section class="layout-main__section">
|
|
65
|
+
<h2 class="h3">
|
|
66
|
+
<%= t("strata_charts", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
67
|
+
</h2>
|
|
68
|
+
<div class="flex public-charts">
|
|
69
|
+
<div class="charts-column">
|
|
70
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @strata_data, title: t("target", scope: "decidim.stratified_sortitions.stratified_sortitions.show") } %>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<% if @candidates_data %>
|
|
74
|
+
<div class="charts-column target">
|
|
75
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @candidates_data, title: t("candidates", scope: "decidim.stratified_sortitions.stratified_sortitions.show") } %>
|
|
76
|
+
</div>
|
|
77
|
+
<% end %>
|
|
78
|
+
|
|
79
|
+
<% if @results_data.present? %>
|
|
80
|
+
<div class="charts-column target">
|
|
81
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @results_data, title: t("results", scope: "decidim.stratified_sortitions.stratified_sortitions.show") } %>
|
|
82
|
+
</div>
|
|
83
|
+
<% end %>
|
|
84
|
+
</div>
|
|
85
|
+
</section>
|
|
86
|
+
<% end %>
|
|
87
|
+
|
|
88
|
+
<% content_for :aside do %>
|
|
89
|
+
<section class="layout-aside__section">
|
|
90
|
+
<%= render partial: "results_count", locals: { stratified_sortition: } %>
|
|
91
|
+
</section>
|
|
92
|
+
<section class="layout-aside__section">
|
|
93
|
+
<div class="text-sm text-gray-2 uppercase font-semibold mb-4">
|
|
94
|
+
<%= t("sortition_details", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="stratified-sortition__aside-element bg-background p-4 rounded">
|
|
97
|
+
<div class="stratified-sortition__aside-element-item">
|
|
98
|
+
<span class="stratified-sortition__aside-element-item__title">
|
|
99
|
+
<%= t("status", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
100
|
+
</span>
|
|
101
|
+
<span class="stratified-sortition__aside-element-item__text">
|
|
102
|
+
<%= t(stratified_sortition.status, scope: "decidim.stratified_sortitions.stratified_sortitions.show.statuses") %>
|
|
103
|
+
</span>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="stratified-sortition__aside-element-item">
|
|
106
|
+
<span class="stratified-sortition__aside-element-item__title">
|
|
107
|
+
<%= t("algorithm_description", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
108
|
+
</span>
|
|
109
|
+
<div class="stratified-sortition__aside-element-item">
|
|
110
|
+
<%= link_to t("algorithm_name", scope: "decidim.stratified_sortitions.stratified_sortitions.show"), Decidim::StratifiedSortitions.leximin_algorithm, class: "stratified-sortition__aside-element-item__title" %>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
<% if stratified_sortition.panel_portfolio&.sampled? %>
|
|
114
|
+
<div class="stratified-sortition__aside-element-item">
|
|
115
|
+
<span class="stratified-sortition__aside-element-item__title">
|
|
116
|
+
<%= t("random_value_used", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
117
|
+
</span>
|
|
118
|
+
<span class="stratified-sortition__aside-element-item__text">
|
|
119
|
+
<%= stratified_sortition.panel_portfolio.random_value_used %>
|
|
120
|
+
</span>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="stratified-sortition__aside-element-item">
|
|
123
|
+
<span class="stratified-sortition__aside-element-item__title">
|
|
124
|
+
<%= t("selected_at", scope: "decidim.stratified_sortitions.stratified_sortitions.show") %>
|
|
125
|
+
</span>
|
|
126
|
+
<span class="stratified-sortition__aside-element-item__text">
|
|
127
|
+
<%= l stratified_sortition.panel_portfolio.selected_at, format: :decidim_short %>
|
|
128
|
+
</span>
|
|
129
|
+
</div>
|
|
130
|
+
<% end %>
|
|
131
|
+
</div>
|
|
132
|
+
</section>
|
|
133
|
+
<section class="layout-aside__section actions__secondary">
|
|
134
|
+
<%= cell "decidim/share_button", nil %>
|
|
135
|
+
</section>
|
|
136
|
+
<% end %>
|
|
137
|
+
<% content_for :item_footer do %>
|
|
138
|
+
<ul class="metadata__container layout-main__section" data-metadata-footer>
|
|
139
|
+
<%= content_tag :li, resource_reference(stratified_sortition), class: "metadata__item" %>
|
|
140
|
+
</ul>
|
|
141
|
+
<% end %>
|
|
142
|
+
<% end %>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<%
|
|
2
|
+
allowed_emails = ENV.fetch("STRATIFIED_SORTITIONS_ALLOWED_EMAILS", "").split(",").map { |email| email.strip.downcase }.reject(&:blank?)
|
|
3
|
+
stratified_sortitions_paths = if defined?(current_participatory_space) && current_participatory_space.respond_to?(:components) && !allowed_emails.include?(current_user&.email.to_s.strip.downcase)
|
|
4
|
+
current_participatory_space.components.filter_map do |component|
|
|
5
|
+
manage_component_path(component) if component.manifest_name.to_s == "stratified_sortitions"
|
|
6
|
+
end
|
|
7
|
+
else
|
|
8
|
+
[]
|
|
9
|
+
end
|
|
10
|
+
menu_html = sidebar_menu(secondary_root_menu).render
|
|
11
|
+
|
|
12
|
+
if stratified_sortitions_paths.any?
|
|
13
|
+
menu_fragment = Nokogiri::HTML::DocumentFragment.parse(menu_html)
|
|
14
|
+
menu_fragment.css("a").each do |link|
|
|
15
|
+
next unless stratified_sortitions_paths.include?(link["href"])
|
|
16
|
+
|
|
17
|
+
link.ancestors("li").first&.remove
|
|
18
|
+
end
|
|
19
|
+
menu_html = menu_fragment.to_html.html_safe
|
|
20
|
+
end
|
|
21
|
+
%>
|
|
22
|
+
|
|
23
|
+
<div class="sidebar-menu__container">
|
|
24
|
+
<div class="sidebar-menu">
|
|
25
|
+
<div id="admin-sidebar-menu-settings">
|
|
26
|
+
<div class="hidden md:block">
|
|
27
|
+
<%= menu_html %>
|
|
28
|
+
</div>
|
|
29
|
+
<button data-component="dropdown" data-target="dropdown-menu-sidebar" data-auto-close="true" data-scroll-to-menu="true">
|
|
30
|
+
<span><%= t("menu", scope: "decidim.admin.titles") %></span>
|
|
31
|
+
<%= icon "arrow-down-s-line" %>
|
|
32
|
+
<%= icon "arrow-up-s-line" %>
|
|
33
|
+
</button>
|
|
34
|
+
|
|
35
|
+
<ul id="dropdown-menu-sidebar" class="md:hidden" aria-hidden="true">
|
|
36
|
+
<%= menu_html %>
|
|
37
|
+
</ul>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="item_show__wrapper">
|
|
42
|
+
<%= admin_tabs(tab_menu_name).render if defined?(has_tab_menu?) && has_tab_menu? %>
|
|
43
|
+
<%= yield %>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="<%= I18n.locale %>" class="no-js">
|
|
3
|
+
<head>
|
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width">
|
|
6
|
+
<title><%= @title %></title>
|
|
7
|
+
<style>
|
|
8
|
+
<%= File.read(Decidim::StratifiedSortitions::Engine.root.join("app/packs/stylesheets/decidim/stratified_sortitions/charts_pdf.scss")).html_safe %>
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<%= yield %>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
data/config/assets.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is located at `config/assets.rb` of your module.
|
|
4
|
+
|
|
5
|
+
# Define the base path of your module. Please note that `Rails.root` may not be
|
|
6
|
+
# used because we are not inside the Rails environment when this file is loaded.
|
|
7
|
+
base_path = File.expand_path("..", __dir__)
|
|
8
|
+
|
|
9
|
+
# Register an additional load path for webpack. All the assets within these
|
|
10
|
+
# directories will be available for inclusion within the Decidim assets. For
|
|
11
|
+
# example, if you have `app/packs/src/decidim/foo.js`, you can include that file
|
|
12
|
+
# in your JavaScript entrypoints (or other JavaScript files within Decidim)
|
|
13
|
+
# using `import "src/decidim/foo"` after you have registered the additional path
|
|
14
|
+
# as follows.
|
|
15
|
+
Decidim::Webpacker.register_path("#{base_path}/app/packs")
|
|
16
|
+
|
|
17
|
+
# Register the entrypoints for your module. These entrypoints can be included
|
|
18
|
+
# within your application using `javascript_pack_tag` and if you include any
|
|
19
|
+
# SCSS files within the entrypoints, they become available for inclusion using
|
|
20
|
+
# `stylesheet_pack_tag`.
|
|
21
|
+
Decidim::Webpacker.register_entrypoints(
|
|
22
|
+
decidim_stratified_sortitions: "#{base_path}/app/packs/entrypoints/decidim_stratified_sortitions.js",
|
|
23
|
+
decidim_stratified_sortitions_admin: "#{base_path}/app/packs/entrypoints/decidim_stratified_sortitions_admin.js",
|
|
24
|
+
)
|