decidim-accountability 0.7.4 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +5 -2
- data/app/assets/config/decidim_accountability_manifest.js +1 -0
- data/app/assets/javascripts/decidim/accountability/accountability.js.es6 +1 -0
- data/app/assets/javascripts/decidim/accountability/version_diff.js.es6 +37 -0
- data/app/assets/stylesheets/decidim/accountability/accountability/_versions.scss +8 -0
- data/app/commands/decidim/accountability/admin/create_result.rb +3 -1
- data/app/commands/decidim/accountability/admin/update_result.rb +3 -1
- data/app/controllers/decidim/accountability/results_controller.rb +3 -19
- data/app/controllers/decidim/accountability/versions_controller.rb +24 -0
- data/app/helpers/decidim/accountability/breadcrumb_helper.rb +27 -0
- data/app/models/decidim/accountability/result.rb +1 -0
- data/app/models/decidim/accountability/status.rb +1 -1
- data/app/services/decidim/accountability/diff_renderer.rb +83 -0
- data/app/views/decidim/accountability/results/_show_parent.html.erb +9 -5
- data/app/views/decidim/accountability/results/_stats_box.html.erb +46 -27
- data/app/views/decidim/accountability/versions/_version.html.erb +20 -0
- data/app/views/decidim/accountability/versions/index.html.erb +30 -0
- data/app/views/decidim/accountability/versions/show.html.erb +41 -0
- data/config/locales/ca.yml +17 -0
- data/config/locales/en.yml +17 -0
- data/config/locales/es.yml +17 -0
- data/config/locales/eu.yml +17 -0
- data/config/locales/fi.yml +17 -0
- data/config/locales/fr.yml +17 -0
- data/config/locales/it.yml +44 -27
- data/config/locales/nl.yml +33 -16
- data/config/locales/pl.yml +17 -0
- data/config/locales/pt.yml +174 -0
- data/config/locales/uk.yml +11 -0
- data/lib/decidim/accountability/engine.rb +1 -0
- data/lib/decidim/accountability/feature.rb +11 -2
- data/lib/decidim/accountability/test/factories.rb +7 -4
- data/lib/decidim/accountability/version.rb +1 -1
- metadata +45 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b9e4ccd5f0cb93b7caf07991bf0f69d1de1002dc
|
4
|
+
data.tar.gz: fff3cc52314258d1d18d159be8ebf3b41854210b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e615fb44d4e96e40555b689c2885652a7ba0ba6c7f7ad27663ad80019a86c96b6762c2f129a22c454e37c461b2f3eee990a539b0355ba6c705cfbd2ecdbc5b7
|
7
|
+
data.tar.gz: 107326f7daeefd26291889a25798a8e21a301c7abe0b6df8a5390b1e6ad421f68bc6ad233eb31345fbd862685ee3d9b68fc2ed01ad44ef7bd0eadead9fda76d6
|
data/README.md
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
The Accountability module adds results to any participatory process. It adds a CRUD engine to the admin and public views scoped inside the participatory process. Accountability will link to related meetings and proposals and will be used to show the progress on the related proposals.
|
4
4
|
|
5
|
-
|
6
5
|
## Usage
|
7
6
|
|
8
7
|
Accountability will be available as a Feature for a Participatory Process.
|
9
8
|
|
10
9
|
## Installation
|
10
|
+
|
11
11
|
Add this line to your application's Gemfile:
|
12
12
|
|
13
13
|
```ruby
|
@@ -15,12 +15,15 @@ gem 'decidim-accountability'
|
|
15
15
|
```
|
16
16
|
|
17
17
|
And then execute:
|
18
|
+
|
18
19
|
```bash
|
19
|
-
|
20
|
+
bundle
|
20
21
|
```
|
21
22
|
|
22
23
|
## Contributing
|
24
|
+
|
23
25
|
See [Decidim](https://github.com/AjuntamentdeBarcelona/decidim).
|
24
26
|
|
25
27
|
## License
|
28
|
+
|
26
29
|
See [Decidim](https://github.com/AjuntamentdeBarcelona/decidim).
|
@@ -0,0 +1,37 @@
|
|
1
|
+
/* global JsDiff */
|
2
|
+
|
3
|
+
$(() => {
|
4
|
+
$(".diff-i18n_html, .diff-i18n").each(function(_index, element) {
|
5
|
+
const diffElement = $(element);
|
6
|
+
const valueElement = diffElement.find(".diff__value");
|
7
|
+
const oldValue = valueElement.data("old-value").
|
8
|
+
replace(/</g, "<").
|
9
|
+
replace(/>/g, ">");
|
10
|
+
const newValue = valueElement.data("new-value").
|
11
|
+
replace(/</g, "<").
|
12
|
+
replace(/>/g, ">");
|
13
|
+
|
14
|
+
const diff = JsDiff.diffChars(oldValue, newValue);
|
15
|
+
let outputHTML = "";
|
16
|
+
|
17
|
+
diff.forEach(({added, removed, value}) => {
|
18
|
+
let color = "";
|
19
|
+
|
20
|
+
if (added) {
|
21
|
+
color = "#89ffaa";
|
22
|
+
} else if (removed) {
|
23
|
+
color = "red";
|
24
|
+
}
|
25
|
+
|
26
|
+
if (added || removed) {
|
27
|
+
outputHTML += `<span style="background-color: ${color}">${value}</span>`;
|
28
|
+
} else {
|
29
|
+
outputHTML += value;
|
30
|
+
}
|
31
|
+
});
|
32
|
+
|
33
|
+
outputHTML = outputHTML.replace(/\n/g, "<br><br>");
|
34
|
+
|
35
|
+
valueElement.html(outputHTML);
|
36
|
+
});
|
37
|
+
})
|
@@ -6,8 +6,10 @@ module Decidim
|
|
6
6
|
class ResultsController < Decidim::Accountability::ApplicationController
|
7
7
|
include FilterResource
|
8
8
|
helper Decidim::WidgetUrlsHelper
|
9
|
+
helper Decidim::TraceabilityHelper
|
10
|
+
helper Decidim::Accountability::BreadcrumbHelper
|
9
11
|
|
10
|
-
helper_method :results, :result, :
|
12
|
+
helper_method :results, :result, :first_class_categories, :count_calculator
|
11
13
|
|
12
14
|
private
|
13
15
|
|
@@ -20,10 +22,6 @@ module Decidim
|
|
20
22
|
@result ||= Result.includes(:timeline_entries).where(feature: current_feature).find(params[:id])
|
21
23
|
end
|
22
24
|
|
23
|
-
def stats_calculator
|
24
|
-
@stats_calculator ||= ResultStatsCalculator.new(result)
|
25
|
-
end
|
26
|
-
|
27
25
|
def search_klass
|
28
26
|
ResultSearch
|
29
27
|
end
|
@@ -44,23 +42,9 @@ module Decidim
|
|
44
42
|
@first_class_categories ||= current_participatory_space.categories.first_class
|
45
43
|
end
|
46
44
|
|
47
|
-
def category
|
48
|
-
if params[:filter] && params[:filter][:category_id].present?
|
49
|
-
current_participatory_space.categories.find(params[:filter][:category_id])
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def progress_calculator(scope_id, category_id)
|
54
|
-
Decidim::Accountability::ResultsCalculator.new(current_feature, scope_id, category_id).progress
|
55
|
-
end
|
56
|
-
|
57
45
|
def count_calculator(scope_id, category_id)
|
58
46
|
Decidim::Accountability::ResultsCalculator.new(current_feature, scope_id, category_id).count
|
59
47
|
end
|
60
|
-
|
61
|
-
def current_scope
|
62
|
-
params[:filter][:scope_id] if params[:filter]
|
63
|
-
end
|
64
48
|
end
|
65
49
|
end
|
66
50
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
# Exposes result versions so users can see how a result
|
6
|
+
# has been updated through time.
|
7
|
+
class VersionsController < Decidim::Accountability::ApplicationController
|
8
|
+
helper Decidim::TraceabilityHelper
|
9
|
+
helper Decidim::Accountability::BreadcrumbHelper
|
10
|
+
helper_method :current_version, :result
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def result
|
15
|
+
@result ||= Result.includes(:timeline_entries).where(feature: current_feature).find(params[:result_id])
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_version
|
19
|
+
return nil if params[:id].to_i < 1
|
20
|
+
@current_version ||= result.versions[params[:id].to_i - 1]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
# Helpers needed to render the navigation breadcrumbs in results.
|
6
|
+
#
|
7
|
+
module BreadcrumbHelper
|
8
|
+
def stats_calculator
|
9
|
+
@stats_calculator ||= ResultStatsCalculator.new(result)
|
10
|
+
end
|
11
|
+
|
12
|
+
def current_scope
|
13
|
+
params[:filter][:scope_id] if params[:filter]
|
14
|
+
end
|
15
|
+
|
16
|
+
def progress_calculator(scope_id, category_id)
|
17
|
+
Decidim::Accountability::ResultsCalculator.new(current_feature, scope_id, category_id).progress
|
18
|
+
end
|
19
|
+
|
20
|
+
def category
|
21
|
+
if params[:filter] && params[:filter][:category_id].present?
|
22
|
+
current_participatory_space.categories.find(params[:filter][:category_id])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -9,7 +9,7 @@ module Decidim
|
|
9
9
|
|
10
10
|
feature_manifest_name "accountability"
|
11
11
|
|
12
|
-
has_many :results, foreign_key: "decidim_accountability_status_id", class_name: "Decidim::Accountability::Result", inverse_of: :status
|
12
|
+
has_many :results, foreign_key: "decidim_accountability_status_id", class_name: "Decidim::Accountability::Result", inverse_of: :status, dependent: :nullify
|
13
13
|
|
14
14
|
validates :key, presence: true, uniqueness: { scope: :decidim_feature_id }
|
15
15
|
validates :name, presence: true
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
class DiffRenderer
|
6
|
+
def initialize(version)
|
7
|
+
@version = version
|
8
|
+
end
|
9
|
+
|
10
|
+
# Renders the diff of the given changeset. Takes into account translatable fields.
|
11
|
+
#
|
12
|
+
# Returns a Hash, where keys are the fields that have changed and values are an
|
13
|
+
# array, the first element being the previous value and the last being the new one.
|
14
|
+
def diff
|
15
|
+
version.changeset.inject({}) do |diff, (attribute, values)|
|
16
|
+
attribute = attribute.to_sym
|
17
|
+
type = attribute_types[attribute]
|
18
|
+
|
19
|
+
if type.blank?
|
20
|
+
diff
|
21
|
+
else
|
22
|
+
parse_changeset(attribute, values, type, diff)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :version
|
30
|
+
|
31
|
+
# Lists which attributes will be diffable and how
|
32
|
+
# they should be rendered.
|
33
|
+
def attribute_types
|
34
|
+
{
|
35
|
+
start_date: :date,
|
36
|
+
end_date: :date,
|
37
|
+
description: :i18n_html,
|
38
|
+
title: :i18n,
|
39
|
+
decidim_scope_id: :scope,
|
40
|
+
progress: :percentage
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_i18n_changeset(attribute, values, type, diff)
|
45
|
+
values.last.each_key do |locale, _value|
|
46
|
+
first_value = values.first.try(:[], locale)
|
47
|
+
last_value = values.last.try(:[], locale)
|
48
|
+
next if first_value == last_value
|
49
|
+
|
50
|
+
attribute_locale = "#{attribute}_#{locale}".to_sym
|
51
|
+
diff.update(
|
52
|
+
attribute_locale => {
|
53
|
+
type: type,
|
54
|
+
label: generate_i18n_label(attribute, locale),
|
55
|
+
old_value: first_value,
|
56
|
+
new_value: last_value
|
57
|
+
}
|
58
|
+
)
|
59
|
+
end
|
60
|
+
diff
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_changeset(attribute, values, type, diff)
|
64
|
+
return parse_i18n_changeset(attribute, values, type, diff) if [:i18n, :i18n_html].include?(type)
|
65
|
+
|
66
|
+
diff.update(
|
67
|
+
attribute => {
|
68
|
+
type: type,
|
69
|
+
label: I18n.t(attribute, scope: "activemodel.attributes.result"),
|
70
|
+
old_value: values[0],
|
71
|
+
new_value: values[1]
|
72
|
+
}
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def generate_i18n_label(attribute, locale)
|
77
|
+
label = I18n.t(attribute, scope: "activemodel.attributes.result")
|
78
|
+
locale_name = I18n.t("locale.name", locale: locale)
|
79
|
+
"#{label} (#{locale_name})"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -6,13 +6,17 @@
|
|
6
6
|
<div class="small-12 columns">
|
7
7
|
<h2 class="heading2"><%= translated_attribute result.title %></h2>
|
8
8
|
|
9
|
-
<div class="
|
10
|
-
<div class="
|
11
|
-
<div class="
|
12
|
-
|
9
|
+
<div class="row">
|
10
|
+
<div class="mediumlarge-8 columns">
|
11
|
+
<div class="section">
|
12
|
+
<div class="description">
|
13
|
+
<%== translated_attribute result.description %>
|
14
|
+
</div>
|
15
|
+
<%= render partial: "decidim/shared/tags", locals: { resource: result, tags_class_extra: "tags--result" } %>
|
13
16
|
</div>
|
14
|
-
<%= render partial: "decidim/shared/tags", locals: { resource: result, tags_class_extra: "tags--result" } %>
|
15
17
|
</div>
|
18
|
+
|
19
|
+
<%= render partial: "stats_box" %>
|
16
20
|
</div>
|
17
21
|
|
18
22
|
<%= render partial: "results_leaf", locals: { results: result.children.page(1).per(result.children_count), total_count: result.children_count } %>
|
@@ -1,31 +1,50 @@
|
|
1
|
-
<div class="columns section
|
2
|
-
<% if result.linked_resources(:proposals, "included_proposals").any? %>
|
1
|
+
<div class="columns section mediumlarge-4 large-3">
|
2
|
+
<% if result.versions.any? || result.linked_resources(:proposals, "included_proposals").any? %>
|
3
3
|
<div class="card extra line-stats">
|
4
4
|
<div class="definition-data">
|
5
|
-
|
6
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
<
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
<
|
28
|
-
|
5
|
+
<% if result.versions.any? %>
|
6
|
+
<div class="definition-data__item versions_count">
|
7
|
+
<span class="definition-data__title"><%= t("results.show.stats.version_number", scope: "decidim.accountability") %></span>
|
8
|
+
<%= result.versions.count %>
|
9
|
+
<%= link_to t("results.show.stats.show_all_versions", scope: "decidim.accountability"), result_versions_path(result), class: "button button--sc hollow secondary small expanded" %>
|
10
|
+
</div>
|
11
|
+
<% if result.last_editor.present? %>
|
12
|
+
<div class="definition-data__item last_revision_by">
|
13
|
+
<span class="definition-data__title"><%= t("results.show.stats.last_edited_by", scope: "decidim.accountability") %></span>
|
14
|
+
<%= render_resource_last_editor(result) %>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
17
|
+
<div class="definition-data__item last_updated_at">
|
18
|
+
<span class="definition-data__title"><%= t("results.show.stats.last_updated_at", scope: "decidim.accountability") %></span>
|
19
|
+
<%= l result.versions.last.created_at, format: :decidim_short %>
|
20
|
+
</div>
|
21
|
+
<% end %>
|
22
|
+
<% if result.linked_resources(:proposals, "included_proposals").any? %>
|
23
|
+
<div class="definition-data__item definition-data__item--double">
|
24
|
+
<span class="definition-data__title"><%= t("results.show.stats.proposals", scope: "decidim.accountability") %></span>
|
25
|
+
<span class="definition-data__number"><%= stats_calculator.proposals_count %></span>
|
26
|
+
</div>
|
27
|
+
<div class="definition-data__item definition-data__item--double">
|
28
|
+
<span class="definition-data__title"><%= t("results.show.stats.meetings", scope: "decidim.accountability") %></span>
|
29
|
+
<span class="definition-data__number"><%= stats_calculator.meetings_count %></span>
|
30
|
+
</div>
|
31
|
+
<div class="definition-data__item definition-data__item--double">
|
32
|
+
<span class="definition-data__title"><%= t("results.show.stats.comments", scope: "decidim.accountability") %></span>
|
33
|
+
<span class="definition-data__number"><%= stats_calculator.comments_count %></span>
|
34
|
+
</div>
|
35
|
+
<div class="definition-data__item definition-data__item--double">
|
36
|
+
<span class="definition-data__title"><%= t("results.show.stats.attendees", scope: "decidim.accountability") %></span>
|
37
|
+
<span class="definition-data__number"><%= stats_calculator.attendees_count %></span>
|
38
|
+
</div>
|
39
|
+
<div class="definition-data__item definition-data__item--double">
|
40
|
+
<span class="definition-data__title"><%= t("results.show.stats.votes", scope: "decidim.accountability") %></span>
|
41
|
+
<span class="definition-data__number"><%= stats_calculator.votes_count %></span>
|
42
|
+
</div>
|
43
|
+
<div class="definition-data__item definition-data__item--double">
|
44
|
+
<span class="definition-data__title"><%= t("results.show.stats.contributions", scope: "decidim.accountability") %></span>
|
45
|
+
<span class="definition-data__number"><%= stats_calculator.contributions_count %></span>
|
46
|
+
</div>
|
47
|
+
<% end %>
|
29
48
|
</div>
|
30
49
|
</div>
|
31
50
|
<% end %>
|
@@ -33,4 +52,4 @@
|
|
33
52
|
<%= feature_reference(result) %>
|
34
53
|
<%= render partial: "decidim/shared/share_modal" %>
|
35
54
|
<%= embed_modal_for result_result_widget_url(result, format: :js) %>
|
36
|
-
</div>
|
55
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div class="card--list__item">
|
2
|
+
<div class="card--list__text">
|
3
|
+
<div>
|
4
|
+
<%= link_to result_version_path(result, index + 1) do %>
|
5
|
+
<h6 class="card--list__heading heading6">
|
6
|
+
<%= t(".version_index", index: index + 1) %>
|
7
|
+
</h6>
|
8
|
+
<% end %>
|
9
|
+
<div class="author-data">
|
10
|
+
<%= render_resource_editor(version) %>
|
11
|
+
<%= l version.created_at, format: :decidim_short %>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<div class="card--list__data">
|
16
|
+
<%= link_to result_version_path(result, index + 1), class: "card--list__data__icon" do %>
|
17
|
+
<%= icon "chevron-right" %>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
</div>
|