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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<div class="form__wrapper">
|
|
2
|
+
<div class="card" data-component="accordion" id="accordion-data">
|
|
3
|
+
<div class="card-divider">
|
|
4
|
+
<button class="card-divider-button" data-open="true" data-controls="panel-data" type="button">
|
|
5
|
+
<%= icon "arrow-right-s-line" %>
|
|
6
|
+
<h2 class="card-title" id="data">
|
|
7
|
+
<%= t("data", scope: "decidim.stratified_sortitions.admin.stratified_sortitions.form") %>
|
|
8
|
+
</h2>
|
|
9
|
+
</button>
|
|
10
|
+
</div>
|
|
11
|
+
<div id="panel-data" class="card-section">
|
|
12
|
+
<div class="row columns">
|
|
13
|
+
<%= form.translated :text_field, :title, autofocus: true, aria: { label: :title } %>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="row column mt-4">
|
|
17
|
+
<%= form.number_field :num_candidates, readonly: stratified_sortition&.executed? %>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div class="row column">
|
|
21
|
+
<%= form.translated :editor, :description %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="row column">
|
|
25
|
+
<%= form.translated :editor, :selection_criteria, help_text: t("selection_criteria_help", scope: "decidim.stratified_sortitions.admin.stratified_sortitions.form") %>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="row column">
|
|
29
|
+
<%= form.translated :editor, :selected_profiles_description, help_text: t("selected_profiles_description_help", scope: "decidim.stratified_sortitions.admin.stratified_sortitions.form") %>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="card" data-component="accordion" id="accordion-strata">
|
|
35
|
+
<div class="card-divider">
|
|
36
|
+
<button class="card-divider-button" data-open="true" data-controls="panel-strata" type="button">
|
|
37
|
+
<svg viewBox="0 0 24 24" id="ri-arrow-right-s-line">
|
|
38
|
+
<path fill="none" d="M0 0h24v24H0z" />
|
|
39
|
+
<path d="M13.172 12l-4.95-4.95 1.414-1.414L16 12l-6.364 6.364-1.414-1.414z" />
|
|
40
|
+
</svg>
|
|
41
|
+
<h2 class="card-title" id="strata">
|
|
42
|
+
<%= t("title", scope: "decidim.stratified_sortitions.admin.stratified_sortitions.strata") %>
|
|
43
|
+
</h2>
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
46
|
+
<div id="panel-strata" class="card-section">
|
|
47
|
+
<div class="row column">
|
|
48
|
+
<%= render "decidim/stratified_sortitions/admin/stratified_sortitions/strata", form: form %>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<%= append_javascript_pack_tag "decidim_stratified_sortitions_admin" %>
|
|
55
|
+
<%= append_stylesheet_pack_tag "decidim_stratified_sortitions_admin" %>
|
data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/_navigation_menu.html.erb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<div class="flex items-left stratified_sortition_nav">
|
|
2
|
+
<% navigation_menu_items(stratified_sortition).each do |item| %>
|
|
3
|
+
<%= button_to item[:path],
|
|
4
|
+
method: :get,
|
|
5
|
+
class: "import-sample-btn #{'active' if item[:active]}",
|
|
6
|
+
disabled: item[:disabled] do %>
|
|
7
|
+
<%= icon item[:icon] %> <%= item[:label] %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% end %>
|
|
10
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<div id="panel-strata" class="card-section">
|
|
2
|
+
<%= field_errors_block(form, :strata) %>
|
|
3
|
+
|
|
4
|
+
<div class="stratified-sortition-strata row column">
|
|
5
|
+
<template class="decidim-template">
|
|
6
|
+
<%= fields_for "stratified_sortition[strata][STRATUM_ID]", blank_stratum do |stratum_form| %>
|
|
7
|
+
<%= render "stratum", form: stratum_form, id: tabs_id_for_stratum(blank_stratum) %>
|
|
8
|
+
<% end %>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<div class="stratified-sortition-strata-list">
|
|
12
|
+
<% form.object.strata.each do |stratum| %>
|
|
13
|
+
<%= fields_for "stratified_sortition[strata][]", stratum do |stratum_form| %>
|
|
14
|
+
<%= render "stratum", form: stratum_form, id: tabs_id_for_stratum(stratum) %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
18
|
+
<button class="button button__sm button__secondary add-stratum mt-2" type="button" <%= 'disabled' if @stratified_sortition&.sample_participants&.any? %>>
|
|
19
|
+
<%= t(".add_stratum") %>
|
|
20
|
+
</button>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<% stratum = form.object %>
|
|
2
|
+
|
|
3
|
+
<div class="card stratified-sortition-stratum" data-component="accordion" id="accordion-<%= id %>-field">
|
|
4
|
+
<div class="card-divider stratum-divider">
|
|
5
|
+
<h2 class="card-title flex items-center">
|
|
6
|
+
<span>
|
|
7
|
+
<%= icon("drag-move-2-fill") %>
|
|
8
|
+
<%= dynamic_title(translated_attribute(stratum.name), class: "stratum-title-statement", max_length: 50, omission: "...", placeholder: t(".title")) %>
|
|
9
|
+
</span>
|
|
10
|
+
|
|
11
|
+
<div class="ml-auto flex flex-row-reverse items-center gap-x-4">
|
|
12
|
+
<button type="button" class="stratum--collapse" data-controls="panel-<%= id %>-stratum-card">
|
|
13
|
+
<span class="icon-collapse">
|
|
14
|
+
<%== icon("arrow-up-s-line", role: "img") %>
|
|
15
|
+
</span>
|
|
16
|
+
|
|
17
|
+
<span class="icon-expand">
|
|
18
|
+
<%== icon("arrow-down-s-line", role: "img") %>
|
|
19
|
+
</span>
|
|
20
|
+
</button>
|
|
21
|
+
<button
|
|
22
|
+
type="button"
|
|
23
|
+
class="button button__sm button__transparent-secondary small alert move-up-stratum button--title"
|
|
24
|
+
<%= 'disabled' if @stratified_sortition&.sample_participants&.any? %>>
|
|
25
|
+
<%= icon "arrow-up-line" %> <%= t(".up") %>
|
|
26
|
+
</button>
|
|
27
|
+
|
|
28
|
+
<button
|
|
29
|
+
type="button"
|
|
30
|
+
class="button button__sm button__transparent-secondary small alert move-down-stratum button--title"
|
|
31
|
+
<%= 'disabled' if @stratified_sortition&.sample_participants&.any? %>>
|
|
32
|
+
<%= icon "arrow-down-line" %> <%= t(".down") %>
|
|
33
|
+
</button>
|
|
34
|
+
|
|
35
|
+
<button
|
|
36
|
+
type="button"
|
|
37
|
+
class="button button__sm button__transparent-secondary small alert remove-stratum button--title"
|
|
38
|
+
<%= 'disabled' if @stratified_sortition&.sample_participants&.any? %>>
|
|
39
|
+
<%= t(".remove") %>
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
</h2>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div id="panel-<%= id %>-stratum-card" class="card-divider collapsible">
|
|
46
|
+
<div class="card-section stratum-fields">
|
|
47
|
+
<div class="translated-field">
|
|
48
|
+
<%= form.translated(
|
|
49
|
+
:text_field,
|
|
50
|
+
:name,
|
|
51
|
+
tabs_id: id,
|
|
52
|
+
label: t(".name"),
|
|
53
|
+
maxlength: 100,
|
|
54
|
+
readonly: @stratified_sortition&.sample_participants&.any?) %>
|
|
55
|
+
</div>
|
|
56
|
+
<div>
|
|
57
|
+
<%= form.select :kind,
|
|
58
|
+
[[t("decidim.stratified_sortitions.admin.stratified_sortitions.stratum.kind.value"), "value"],
|
|
59
|
+
[t("decidim.stratified_sortitions.admin.stratified_sortitions.stratum.kind.numeric_range"), "numeric_range"]],
|
|
60
|
+
{ label: t("decidim.stratified_sortitions.admin.stratified_sortitions.stratum.kind.title") },
|
|
61
|
+
{ disabled: @stratified_sortition&.sample_participants&.any? } %>
|
|
62
|
+
<%= form.hidden_field :kind if @stratified_sortition&.sample_participants&.any? %>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<%= form.hidden_field :id %>
|
|
66
|
+
<%= form.hidden_field :position, value: form.object.position || 0 %>
|
|
67
|
+
<%= form.hidden_field :deleted, value: false %>
|
|
68
|
+
|
|
69
|
+
<% blank_substratum = Decidim::StratifiedSortitions::Admin::SubstratumForm.new(stratum: stratum) %>
|
|
70
|
+
<%= render "substrata",
|
|
71
|
+
form: form,
|
|
72
|
+
stratum: stratum,
|
|
73
|
+
blank_substratum: blank_substratum %>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<div id="panel-substrata" class="card-section">
|
|
2
|
+
<%= field_errors_block(form, :substrata) %>
|
|
3
|
+
|
|
4
|
+
<div class="stratified-sortition-substrata row column" id="substrata-<%= form.object.object_id %>">
|
|
5
|
+
|
|
6
|
+
<script type="text/template" class="decidim-template">
|
|
7
|
+
<% new_substratum = Decidim::StratifiedSortitions::Admin::SubstratumForm.new(stratum: form.object) %>
|
|
8
|
+
<% stratum_id = form.object.id || "STRATUM_ID" %>
|
|
9
|
+
<% field_name_base = "stratified_sortition[strata][#{stratum_id}][substrata][SUBSTRATUM_ID]" %>
|
|
10
|
+
<%= fields_for field_name_base, new_substratum do |substratum_form| %>
|
|
11
|
+
<%= render "substratum",
|
|
12
|
+
form: substratum_form,
|
|
13
|
+
id: tabs_id_for_substratum("SUBSTRATUM_ID"),
|
|
14
|
+
stratum: form.object %>
|
|
15
|
+
<% end %>
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<div class="stratified-sortition-substrata-list">
|
|
19
|
+
<% form.object.substrata.each_with_index do |substratum, index| %>
|
|
20
|
+
<%= form.fields_for "[substrata][#{index}]", substratum do |substratum_form| %>
|
|
21
|
+
<%= render "substratum",
|
|
22
|
+
form: substratum_form,
|
|
23
|
+
id: tabs_id_for_substratum(substratum),
|
|
24
|
+
stratum: form.object %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|
|
28
|
+
<button
|
|
29
|
+
class="button button__sm button__secondary add-substratum mt-2"
|
|
30
|
+
type="button" <%= 'disabled' if @stratified_sortition&.sample_participants&.any? %>>
|
|
31
|
+
<%= t(".add_substratum") %>
|
|
32
|
+
</button>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<% substratum = form.object %>
|
|
2
|
+
|
|
3
|
+
<div class="card stratified-sortition-substratum" id="<%= id %>-field">
|
|
4
|
+
<div class="card-divider substratum-divider">
|
|
5
|
+
<h2 class="card-title mb-4">
|
|
6
|
+
<span><%= t(".title") %></span>
|
|
7
|
+
|
|
8
|
+
<div class="ml-auto flex gap-x-4">
|
|
9
|
+
<button
|
|
10
|
+
type="button"
|
|
11
|
+
class="button button__sm button__transparent-secondary small alert remove-substratum button--title"
|
|
12
|
+
<%= 'disabled' if @stratified_sortition&.sample_participants&.any? %>>
|
|
13
|
+
<%= t(".remove") %>
|
|
14
|
+
</button>
|
|
15
|
+
</div>
|
|
16
|
+
</h2>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="card-section">
|
|
20
|
+
<div class="row column substratum-fields">
|
|
21
|
+
<div class="translated-field">
|
|
22
|
+
<%= form.translated(
|
|
23
|
+
:text_field,
|
|
24
|
+
:name,
|
|
25
|
+
tabs_id: id,
|
|
26
|
+
label: t(".name"),
|
|
27
|
+
maxlength: 100,
|
|
28
|
+
readonly: @stratified_sortition&.sample_participants&.any?) %>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="substratum-value-field">
|
|
31
|
+
<%= form.text_field :value,
|
|
32
|
+
label: t(".value"),
|
|
33
|
+
placeholder: t(".value_placeholder",default: "Value"),
|
|
34
|
+
readonly: @stratified_sortition&.sample_participants&.any? %>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="substratum-range-field">
|
|
37
|
+
<%= form.text_field :range,
|
|
38
|
+
label: t(".range"),
|
|
39
|
+
placeholder: t(".range_placeholder", default: "Range (e.g. 0-18)"),
|
|
40
|
+
readonly: @stratified_sortition&.sample_participants&.any? %>
|
|
41
|
+
</div>
|
|
42
|
+
<div>
|
|
43
|
+
<%= form.number_field :max_quota_percentage,
|
|
44
|
+
step: 0.1, label: t(".max_quota_percentage"),
|
|
45
|
+
placeholder: t(".max_quota_percentage_placeholder"),
|
|
46
|
+
readonly: @stratified_sortition&.executed? %>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<%= form.hidden_field :id %>
|
|
52
|
+
<%= form.hidden_field :deleted, value: false %>
|
|
53
|
+
<%= form.hidden_field :position, value: form.object.position || 0 %>
|
|
54
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
|
|
8
|
+
<%= render 'navigation_menu' %>
|
|
9
|
+
|
|
10
|
+
<div class="item__edit item__edit-1col">
|
|
11
|
+
<div class="item__edit-form">
|
|
12
|
+
<%= decidim_form_for(@form, html: { class: "form-defaults form edit_stratified_sortition stratified_sortition_form_admin" }) do |f| %>
|
|
13
|
+
<%= render partial: "form", object: f, locals: { title: t(".title") } %>
|
|
14
|
+
<div class="item__edit-sticky">
|
|
15
|
+
<div class="item__edit-sticky-container">
|
|
16
|
+
<%= f.submit t(".update"), class: "button button__sm button__secondary" %>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<% end %>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,155 @@
|
|
|
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
|
+
<% if stratified_sortition.executing? %>
|
|
9
|
+
<div class="callout warning">
|
|
10
|
+
<%= t('.executing_notice') %>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% if stratified_sortition.failed? %>
|
|
14
|
+
<div class="callout alert">
|
|
15
|
+
<p><strong><%= t('.execution_failed') %></strong></p>
|
|
16
|
+
<p><%= stratified_sortition.execution_error %></p>
|
|
17
|
+
</div>
|
|
18
|
+
<% end %>
|
|
19
|
+
<div class="card">
|
|
20
|
+
<div class="item_show__header actions-container">
|
|
21
|
+
<button type="button"
|
|
22
|
+
class="button button__sm button__secondary"
|
|
23
|
+
data-dialog-open="confirm-execute-modal"
|
|
24
|
+
<%= 'disabled' if stratified_sortition.panel_portfolio&.sampled? || stratified_sortition.executing? || !stratified_sortition.can_execute? %>>
|
|
25
|
+
<%= t('.execute_stratified_sortition') %>
|
|
26
|
+
</button>
|
|
27
|
+
<% if stratified_sortition.panel_portfolio&.sampled? %>
|
|
28
|
+
<span class="exports button button__sm button__secondary" data-toggle="export-dropdown">
|
|
29
|
+
<%= t(".export") %>
|
|
30
|
+
<%= icon "arrow-down-s-line", class: "dropdown-filter-icon" %>
|
|
31
|
+
</span>
|
|
32
|
+
<div class="dropdown-pane" id="export-dropdown" data-dropdown data-position="bottom" data-alignment="right" data-auto-focus="true" data-close-on-click="true">
|
|
33
|
+
<ul class="vertical menu add-components">
|
|
34
|
+
<%= link_to export_results_stratified_sortition_path(stratified_sortition, format: "csv"), method: :post do %>
|
|
35
|
+
<li class="exports--format--csv"><%= t(".export_csv") %></li>
|
|
36
|
+
<% end %>
|
|
37
|
+
<%= link_to export_results_stratified_sortition_path(stratified_sortition, format: "excel"), method: :post do %>
|
|
38
|
+
<li class="exports--format--excel"><%= t(".export_excel") %></li>
|
|
39
|
+
<% end %>
|
|
40
|
+
<%= link_to export_results_stratified_sortition_path(stratified_sortition, format: "json"), method: :post do %>
|
|
41
|
+
<li class="exports--format--json"><%= t(".export_json") %></li>
|
|
42
|
+
<% end %>
|
|
43
|
+
<%= link_to export_charts_pdf_stratified_sortition_path(stratified_sortition), method: :post do %>
|
|
44
|
+
<li class="exports--format--pdf"><%= t(".export_charts_pdf") %></li>
|
|
45
|
+
<% end %>
|
|
46
|
+
</ul>
|
|
47
|
+
</div>
|
|
48
|
+
<% end %>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<% if stratified_sortition.panel_portfolio&.sampled? %>
|
|
52
|
+
<div class="card mt-12">
|
|
53
|
+
<div class="item_show__header">
|
|
54
|
+
<h1 class="item_show__header-title">
|
|
55
|
+
<%= t(".results") %>
|
|
56
|
+
</h1>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="mt-4 mb-4">
|
|
59
|
+
<% if @portfolio&.sampled? %>
|
|
60
|
+
<div class="sortition-metadata mb-8">
|
|
61
|
+
<table class="table-list">
|
|
62
|
+
<thead>
|
|
63
|
+
<tr>
|
|
64
|
+
<th><%= t(".algorithm") %></th>
|
|
65
|
+
<th><%= t(".total_participants") %></th>
|
|
66
|
+
<th><%= t(".selected_participants_title") %></th>
|
|
67
|
+
<th><%= t(".generated_at") %></th>
|
|
68
|
+
<th><%= t(".generation_time") %></th>
|
|
69
|
+
<th><%= t(".num_panels") %></th>
|
|
70
|
+
<th><%= t(".selected_at") %></th>
|
|
71
|
+
<th><%= t(".random_value_used") %></th>
|
|
72
|
+
<th><%= t(".selected_panel_probability") %></th>
|
|
73
|
+
</tr>
|
|
74
|
+
</thead>
|
|
75
|
+
<tbody>
|
|
76
|
+
<tr>
|
|
77
|
+
<td><%= @portfolio.audit_log[:algorithm] %> v<%= @portfolio.audit_log[:version] %></td>
|
|
78
|
+
<td><%= stratified_sortition.sample_participants.count %></td>
|
|
79
|
+
<td><%= @portfolio.selected_panel.size %></td>
|
|
80
|
+
<td><%= l @portfolio.generated_at, format: :decidim_short %></td>
|
|
81
|
+
<td><%= number_with_precision(@portfolio.generation_time_seconds, precision: 2) %>s</td>
|
|
82
|
+
<td><%= @portfolio.num_panels %></td>
|
|
83
|
+
<td><%= l @portfolio.selected_at, format: :decidim_short %></td>
|
|
84
|
+
<td><code><%= @portfolio.random_value_used %></code></td>
|
|
85
|
+
<td><%= number_to_percentage(@portfolio.selected_panel_probability.to_f * 100, precision: 2) %></td>
|
|
86
|
+
</tr>
|
|
87
|
+
</tbody>
|
|
88
|
+
</table>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div class="results-sub-nav flex items-left" data-results-tabs>
|
|
92
|
+
<button type="button" class="results-tab active" data-tab-target="charts-section">
|
|
93
|
+
<%= icon "bar-chart-box-line" %> <%= t(".tab_charts") %>
|
|
94
|
+
</button>
|
|
95
|
+
<button type="button" class="results-tab" data-tab-target="participants-section" data-dialog-open="confirm-participants-modal">
|
|
96
|
+
<%= icon "group-line" %> <%= t(".tab_participants") %>
|
|
97
|
+
</button>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div id="charts-section" class="results-tab-panel" data-tab-panel>
|
|
101
|
+
<div class="chart-row">
|
|
102
|
+
<div class="charts-column">
|
|
103
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @strata_data, title: t(".target") } %>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="charts-column target">
|
|
106
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @candidates_data, title: t(".candidates") } %>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="charts-column target">
|
|
109
|
+
<%= render partial: "decidim/stratified_sortitions/shared/strata_charts", locals: { strata_data: @results_data, title: t(".results") } %>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div id="participants-section" class="results-tab-panel" style="display: none;" data-tab-panel>
|
|
115
|
+
<h2 class="h4 mb-4"><%= t(".selected_participants", count: @selected_participants.size) %></h2>
|
|
116
|
+
<table class="table-list">
|
|
117
|
+
<thead>
|
|
118
|
+
<tr>
|
|
119
|
+
<th><%= t(".personal_data_1") %></th>
|
|
120
|
+
<th><%= t(".personal_data_2") %></th>
|
|
121
|
+
<th><%= t(".personal_data_3") %></th>
|
|
122
|
+
<th><%= t(".personal_data_4") %></th>
|
|
123
|
+
<% @strata.each do |stratum| %>
|
|
124
|
+
<th><%= translated_attribute(stratum.name) %></th>
|
|
125
|
+
<% end %>
|
|
126
|
+
</tr>
|
|
127
|
+
</thead>
|
|
128
|
+
<tbody>
|
|
129
|
+
<% @selected_participants.each do |participant| %>
|
|
130
|
+
<tr>
|
|
131
|
+
<td><%= participant.personal_data_1 %></td>
|
|
132
|
+
<td><%= participant.personal_data_2 %></td>
|
|
133
|
+
<td><%= participant.personal_data_3 %></td>
|
|
134
|
+
<td><%= participant.personal_data_4 %></td>
|
|
135
|
+
<% @strata.each do |stratum| %>
|
|
136
|
+
<% participant_stratum = participant.sample_participant_strata.find { |ps| ps.decidim_stratified_sortitions_stratum_id == stratum.id } %>
|
|
137
|
+
<td><%= participant_stratum ? translated_attribute(participant_stratum.decidim_stratified_sortitions_substratum&.name) : "-" %></td>
|
|
138
|
+
<% end %>
|
|
139
|
+
</tr>
|
|
140
|
+
<% end %>
|
|
141
|
+
</tbody>
|
|
142
|
+
</table>
|
|
143
|
+
</div>
|
|
144
|
+
<% else %>
|
|
145
|
+
<p class="text-muted"><%= t(".no_results_yet") %></p>
|
|
146
|
+
<% end %>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
<% end %>
|
|
150
|
+
|
|
151
|
+
<%= render stratified_sortition.panel_portfolio&.sampled? ? "confirm_participants_modal" : "confirm_execute_modal" %>
|
|
152
|
+
|
|
153
|
+
<%= append_javascript_pack_tag "decidim_stratified_sortitions_admin" %>
|
|
154
|
+
<%= append_stylesheet_pack_tag "decidim_stratified_sortitions_admin" %>
|
|
155
|
+
|
data/app/views/decidim/stratified_sortitions/admin/stratified_sortitions/export_charts_pdf.html.erb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<h1><%= @title %></h1>
|
|
2
|
+
<h2><%= @subtitle %></h2>
|
|
3
|
+
<hr>
|
|
4
|
+
|
|
5
|
+
<div class="info">
|
|
6
|
+
<p><%= @belongs_to %></p>
|
|
7
|
+
<p><%= @algorithm %></p>
|
|
8
|
+
<p><%= @executed_at %></p>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<table class="column-headers">
|
|
12
|
+
<tr>
|
|
13
|
+
<td class="col-header"><%= @col_target %></td>
|
|
14
|
+
<td class="col-header"><%= @col_candidates %></td>
|
|
15
|
+
<td class="col-header"><%= @col_results %></td>
|
|
16
|
+
</tr>
|
|
17
|
+
</table>
|
|
18
|
+
|
|
19
|
+
<% @strata_chart_data.each do |stratum_row| %>
|
|
20
|
+
<div class="stratum-section">
|
|
21
|
+
<div class="stratum-title"><%= stratum_row[:name] %></div>
|
|
22
|
+
<table class="charts-table">
|
|
23
|
+
<tr>
|
|
24
|
+
<% [:target, :candidates, :results].each do |col| %>
|
|
25
|
+
<td class="chart-cell">
|
|
26
|
+
<% chart_data = stratum_row[col] %>
|
|
27
|
+
<% if chart_data.present? %>
|
|
28
|
+
<%= svg_pie_chart(chart_data) %>
|
|
29
|
+
<%= legend_html(chart_data) %>
|
|
30
|
+
<% else %>
|
|
31
|
+
<div class="no-data"><%= @no_data_text %></div>
|
|
32
|
+
<% end %>
|
|
33
|
+
</td>
|
|
34
|
+
<% end %>
|
|
35
|
+
</tr>
|
|
36
|
+
</table>
|
|
37
|
+
</div>
|
|
38
|
+
<% end %>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<% add_decidim_page_title(t(".title")) %>
|
|
2
|
+
<div class="card">
|
|
3
|
+
<div class="item_show__header">
|
|
4
|
+
<h1 class="item_show__header-title">
|
|
5
|
+
<div>
|
|
6
|
+
<%= t(".title") %>
|
|
7
|
+
<span id="js-selected-stratified_sortitions-count" class="component-counter component-counter--inline" title="<%= t("decidim.stratified_sortitions.admin.stratified_sortitions.index.selected") %>"></span>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="flex items-center gap-x-4">
|
|
10
|
+
<% if allowed_to? :create, :stratified_sortition %>
|
|
11
|
+
<%= link_to t("actions.new_stratified_sortition", scope: "decidim.stratified_sortitions.admin"),
|
|
12
|
+
new_stratified_sortition_path,
|
|
13
|
+
class: "button button__sm button__secondary" %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<%= render partial: "decidim/admin/components/resource_action" %>
|
|
17
|
+
</div>
|
|
18
|
+
</h1>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="table-scroll mt-16">
|
|
22
|
+
<table class="table-list">
|
|
23
|
+
<thead>
|
|
24
|
+
<tr>
|
|
25
|
+
<th>
|
|
26
|
+
<%= t("models.stratified_sortition.fields.title", scope: "decidim.stratified_sortitions.admin") %>
|
|
27
|
+
</th>
|
|
28
|
+
<th>
|
|
29
|
+
<%= t("models.stratified_sortition.fields.num_candidates", scope: "decidim.stratified_sortitions.admin") %>
|
|
30
|
+
</th>
|
|
31
|
+
<th>
|
|
32
|
+
<%= t("models.stratified_sortition.fields.status", scope: "decidim.stratified_sortitions.admin") %>
|
|
33
|
+
</th>
|
|
34
|
+
<th>
|
|
35
|
+
<%= t("models.stratified_sortition.fields.created_at", scope: "decidim.stratified_sortitions.admin") %>
|
|
36
|
+
</th>
|
|
37
|
+
<th class="actions"><%= t("actions.title", scope: "decidim.stratified_sortitions.admin") %></th>
|
|
38
|
+
</tr>
|
|
39
|
+
</thead>
|
|
40
|
+
<tbody>
|
|
41
|
+
<% @stratified_sortitions.each do |stratified_sortition| %>
|
|
42
|
+
<tr>
|
|
43
|
+
<td>
|
|
44
|
+
<%= link_to translated_attribute(stratified_sortition.title), edit_stratified_sortition_path(stratified_sortition) %>
|
|
45
|
+
</td>
|
|
46
|
+
<td>
|
|
47
|
+
<%= stratified_sortition.num_candidates %>
|
|
48
|
+
</td>
|
|
49
|
+
<td>
|
|
50
|
+
<strong class="label <%= stratified_sortition_state_css_class(stratified_sortition) %>">
|
|
51
|
+
<%= t(stratified_sortition.status, scope: "decidim.stratified_sortitions.stratified_sortitions.filters") %>
|
|
52
|
+
</strong>
|
|
53
|
+
</td>
|
|
54
|
+
<td>
|
|
55
|
+
<%= l(stratified_sortition.created_at, format: :decidim_short) if stratified_sortition.created_at %>
|
|
56
|
+
</td>
|
|
57
|
+
<td class="table-list__actions">
|
|
58
|
+
<% if allowed_to? :duplicate, :stratified_sortition %>
|
|
59
|
+
<%= icon_link_to "file-copy-line", duplicate_stratified_sortition_path(stratified_sortition), t("actions.duplicate", scope: "decidim.stratified_sortitions.admin"), class: "action-icon--new", method: :post %>
|
|
60
|
+
<% end %>
|
|
61
|
+
<% if allowed_to? :edit, :stratified_sortition %>
|
|
62
|
+
<%= icon_link_to "pencil-line", edit_stratified_sortition_path(stratified_sortition), t("actions.configure", scope: "decidim.stratified_sortitions.admin"), class: "action-icon--new" %>
|
|
63
|
+
<% end %>
|
|
64
|
+
<% if allowed_to? :destroy, :stratified_sortition, stratified_sortition: stratified_sortition %>
|
|
65
|
+
<%= icon_link_to "delete-bin-line", stratified_sortition, t("actions.destroy", scope: "decidim.stratified_sortitions.admin"), class: "action-icon--remove", method: :delete, data: { confirm: t("actions.confirm_destroy", scope: "decidim.stratified_sortitions.admin", name: translated_attribute(stratified_sortition.title)) } %>
|
|
66
|
+
<% end %>
|
|
67
|
+
</td>
|
|
68
|
+
</tr>
|
|
69
|
+
<% end %>
|
|
70
|
+
</tbody>
|
|
71
|
+
</table>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<%= decidim_paginate @stratified_sortitions %>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<% add_decidim_page_title(t(".title")) %>
|
|
2
|
+
<div class="item_show__header">
|
|
3
|
+
<h1 class="item_show__header-title">
|
|
4
|
+
<%= t(".title") %>
|
|
5
|
+
</h1>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<%= render 'navigation_menu' %>
|
|
9
|
+
|
|
10
|
+
<div class="item__edit item__edit-1col">
|
|
11
|
+
<div class="item__edit-form">
|
|
12
|
+
<%= decidim_form_for(@form, html: { class: "form-defaults form new_stratified_sortition stratified_sortition_form_admin" }) do |f| %>
|
|
13
|
+
<%= render partial: "form", object: f, locals: { title: t(".title") } %>
|
|
14
|
+
<div class="item__edit-sticky">
|
|
15
|
+
<div class="item__edit-sticky-container">
|
|
16
|
+
<%= f.submit t(".create"), class: "button button__sm button__secondary" %>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<% end %>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|