Implements #138 and #139

Implements graph with supports for the given  period.
This commit is contained in:
Juan Salvador Pérez García
2018-06-20 12:01:58 +02:00
parent 03e8d36fd1
commit 89f3da25b9
17 changed files with 398 additions and 262 deletions

View File

@@ -0,0 +1,123 @@
//= require d3
//= require c3
//= require c3ext
(function(){
'use strict';
var ProposalGraph = function(url) {
this.url = url;
this.targetId = null;
this.groupBy = null;
this.progressLabel = 'Progress';
this.supportsLabel = 'Supports';
};
ProposalGraph.prototype.refresh = function() {
$.ajax({
url: this.url,
cache: false,
success: function (data) {
this.draw(data);
}.bind(this),
data: {
group_by: this.groupBy
}
});
};
ProposalGraph.prototype.draw = function(data) {
var xColumnValues = [ 'x' ],
progressColumnValues = [ this.progressLabel ], // [ '<%= t('.progress') %>' ],
key;
for (key in data) {
if (data.hasOwnProperty(key)) {
xColumnValues.push(key);
progressColumnValues.push(data[key]);
}
}
c3.generate({
bindto: '#' + this.targetId,
data: {
x: 'x',
columns: [
xColumnValues,
progressColumnValues
]
},
axis: {
y: {
label: {
text: this.supportsLabel, // '<%= t '.supports' %> ',
position: 'outer-middle'
}
},
x: {
type: 'category'
}
}
});
};
$(document).ready(function () {
$('[data-proposal-graph-url]').each(function () {
var graph = new ProposalGraph($(this).data('proposal-graph-url'));
graph.targetId = $(this).attr('id');
graph.groupBy = $(this).data('proposal-graph-group-by');
graph.progressLabel = $(this).data('proposal-graph-progress-label');
graph.supportsLabel = $(this).data('proposal-graph-supports-label');
graph.refresh();
});
});
})();
// function drawProposalGraph(data) {
// var xColumnValues = [ 'x' ],
// progressColumnValues = [ 'Progreso' ]; // [ '<%= t('.progress') %>' ],
// key;
//
// for (key in data) {
// if (data.hasOwnProperty(key)) {
// xColumnValues.push(key);
// progressColumnValues.push(data[key]);
// }
// }
//
// c3.generate({
// bindto: '#proposal-graph',
// data: {
// x: 'x',
// columns: [
// xColumnValues,
// progressColumnValues
// ]
// },
// axis: {
// y: {
// label: {
// text: 'Apoyos', // '<%= t '.supports' %> ',
// position: 'outer-middle'
// }
// },
// x: {
// type: 'category'
// }
// }
// });
// }
//
// $(document).ready(function () {
// $.ajax({
// url: '<%= supports_proposal_dashboard_index_path(proposal, format: :json) %>',
// cache: false,
// success: function (data) {
// drawProposalGraph(data);
// },
// data: {
// group_by: '<%= params[:group_by] %>'
// }
// });
// });

View File

@@ -1,4 +1,4 @@
# Helper for generate C3.js graphs }# Helper for generate C3.js graphs
#---------------------------------------------------------------------- #----------------------------------------------------------------------
buildGraph = (el) -> buildGraph = (el) ->

View File

@@ -8,7 +8,6 @@
@import 'participation'; @import 'participation';
@import 'pages'; @import 'pages';
@import 'proposal'; @import 'proposal';
@import 'proposals_dashboard';
@import 'legislation'; @import 'legislation';
@import 'legislation_process'; @import 'legislation_process';
@import 'community'; @import 'community';

View File

@@ -16,3 +16,41 @@
background-color: #e7f3fd; background-color: #e7f3fd;
} }
} }
.proposal-dashboard {
margin-top: -1.5rem;
.columns {
padding: 0;
}
.row {
max-width: 100%;
}
.has-tip {
border-bottom: none;
font-weight: normal;
}
.title {
border-bottom: 1pt solid lightgray;
h5 {
padding: 1rem 1.5rem 1rem 1.5rem;
font-size: 16pt;
margin: 0;
}
}
.left-menu {
border-right: 1pt solid lightgray;
border-bottom: 1pt solid lightgray;
padding: 1rem 1.5rem 1rem 1.5rem;
background-color: #fbfbfb;
}
.body {
padding: 1rem 1.5rem 1rem 1.5rem;
}
}

View File

@@ -1,127 +0,0 @@
.proposals-dashboard {
display: flex;
flex-direction: column;
margin-top: -1.5rem;
.column-wrapper {
flex: 2;
display: flex;
.left-column {
flex: 0 0 150pt;
background: lightgray;
margin-right: 5px;
padding: 5pt;
.state-box {
.logo {
height: 100pt;
width: 100pt;
margin-left: 20pt;
margin-right: 20pt;
border-radius: 50pt;
background-color: #fff3cb;
border: 2pt solid white;
}
.status {
height: 25pt;
width: 100pt;
margin-left: 20pt;
margin-right: 20pt;
padding-top: 3pt;
color: #055392;
font-weight: bold;
text-align: center;
vertical-align: middle;
}
.draft {
background-color: #ffe699;
}
.published {
background-color: #d3ebd2;
}
}
.dashboard-menu {
color: #a9a9a9;
font-size: 16pt;
.menu-title {
margin-top: 10pt;
}
.menu-entry {
color: #a9a9a9;
padding-left: 25pt;
line-height: 30pt;
vertical-align: middle;
display: block;
}
.menu-entry:focus, .menu-entry:active, .menu-entry:hover {
outline: 0;
text-decoration: none;
}
.selected {
font-weight: bold;
color: #454545;
}
.menu-entry.selected {
text-decoration: underline #a9a9a9;
}
}
}
.right-column {
background: lightgray;
flex: 1 1;
padding: 5pt;
//min-height: 775px;
.progress-info {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-items: center;
align-content: stretch;
width: 1440px;
}
.cell-data {
flex-grow: 1;
width: 33%;
font-size: 16pt;
font-weight: bold;
line-height: 32pt;
vertical-align: middle;
padding-left: 42pt;
.caption {
width: 150pt;
float: left;
}
.value {
width: 50pt;
float: left;
text-align: right;
}
.value:after {
clear: both;
}
}
.body {
background-color: white;
height: 500px;
}
}
}
}

View File

@@ -50,6 +50,15 @@ class ProposalsDashboardController < ApplicationController
end end
end end
def stats
authorize! :dashboard, proposal
end
def supports
authorize! :dashboard, proposal
render json: ProposalSupportsQuery.for(params)
end
private private
def proposal_executed_dashboard_action_params def proposal_executed_dashboard_action_params

View File

@@ -0,0 +1,50 @@
# frozen_string_literal: true
class ProposalSupportsQuery
attr_reader :params
def self.for(params)
query = ProposalSupportsQuery.new params
query.results
end
def initialize(params)
@params = params
end
def results
grouped_votes = groups
grouped_votes.each do |group, votes|
grouped_votes[group] = votes.inject(0) { |sum, vote| sum + vote.vote_weight }
end
grouped_votes
end
private
def groups
return votes.group_by { |v| v.created_at.to_date.year } if params[:group_by] == 'year'
return votes.group_by { |v| "#{v.created_at.to_date.cweek}/#{v.created_at.to_date.year}" } if params[:group_by] == 'week'
return votes.group_by { |v| "#{v.created_at.to_date.year}-#{v.created_at.to_date.month}" } if params[:group_by] == 'month'
votes.group_by { |v| v.created_at.to_date }
end
def votes
Vote.where(votable: proposal, created_at: start_date..end_date).order(created_at: :asc)
end
def proposal
@proposal ||= Proposal.find(params[:proposal_id])
end
def start_date
return Date.parse(params[:start_date]) unless params[:start_date].blank?
proposal.created_at.to_date
end
def end_date
return Date.parse(params[:end_date]) unless params[:end_date].blank?
Date.today
end
end

View File

@@ -63,6 +63,7 @@
</div> </div>
</div> </div>
<% if with_subnavigation %>
<div class="subnavigation expanded"> <div class="subnavigation expanded">
<div class="row"> <div class="row">
<div class="hide-for-small-only"> <div class="hide-for-small-only">
@@ -73,5 +74,5 @@
</div> </div>
</div> </div>
</div> </div>
<% end %>
</header> </header>

View File

@@ -22,7 +22,7 @@
<h1 class="show-for-sr"><%= setting['org_name'] %></h1> <h1 class="show-for-sr"><%= setting['org_name'] %></h1>
<div class="wrapper <%= yield (:wrapper_class) %>"> <div class="wrapper <%= yield (:wrapper_class) %>">
<%= render 'layouts/header' %> <%= render partial: 'layouts/header', locals: {with_subnavigation: true} %>
<!--[if lt IE 9]> <!--[if lt IE 9]>
<% if browser.ie? && cookies['ie_alert_closed'] != 'true' %> <% if browser.ie? && cookies['ie_alert_closed'] != 'true' %>
@@ -45,8 +45,8 @@
<![endif]--> <![endif]-->
<%= render 'layouts/flash' %> <%= render 'layouts/flash' %>
<%= yield %> <%= yield %>
<div class="push"></div> <div class="push"></div>
</div> </div>
<div class="footer"> <div class="footer">

View File

@@ -29,7 +29,7 @@
<h1 class="show-for-sr"><%= setting['org_name'] %></h1> <h1 class="show-for-sr"><%= setting['org_name'] %></h1>
<div class="wrapper <%= yield (:wrapper_class) %>"> <div class="wrapper <%= yield (:wrapper_class) %>">
<%= render 'layouts/header' %> <%= render partial: 'layouts/header', locals: {with_subnavigation: false} %>
<!--[if lt IE 9]> <!--[if lt IE 9]>
<% if browser.ie? && cookies['ie_alert_closed'] != 'true' %> <% if browser.ie? && cookies['ie_alert_closed'] != 'true' %>
@@ -51,9 +51,21 @@
<% end %> <% end %>
<![endif]--> <![endif]-->
<%= render 'layouts/flash' %> <%= render partial: 'layouts/flash' %>
<div class="proposal-dashboard">
<div class="row small-12 columns title">
<h5><%= t '.title' %></h5>
</div>
<div class="row">
<div class="small-2 columns left-menu">
<%= render partial: 'proposals_dashboard/menu' %>
</div>
<div class="small-10 columns body">
<%= yield %> <%= yield %>
</div>
</div>
<div class="push"></div> <div class="push"></div>
</div> </div>
</body> </body>

View File

@@ -0,0 +1,99 @@
<% if current_editable?(proposal) || can?(:publish, proposal) %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns"><%= t '.general' %></div>
</div>
<% if current_editable?(proposal) %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('.edit_proposal_link'), edit_proposal_path(proposal), target: '_blank' %>
</div>
</div>
<% end %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('.send_notification'),
new_proposal_notification_path(proposal_id: proposal.id),
target: '_blank' %>
</div>
</div>
<% if can_destroy_image?(proposal) %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('images.remove_image'),
image_path(proposal.image, from: request.url),
method: :delete,
data: { confirm: t('images.actions.destroy.confirm') } %>
</div>
</div>
<% end %>
<% unless proposal.retired? %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('.retire'),
retire_form_proposal_path(proposal),
target: '_blank' %>
</div>
</div>
<% end %>
<% if can?(:publish, proposal) %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('.publish'), publish_proposal_dashboard_index_path(proposal), method: :patch %>
</div>
</div>
<% end %>
<% end %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns"><%= t('.progress') %></div>
</div>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('.graphic'), stats_proposal_dashboard_index_path(proposal.to_param) %>
</div>
</div>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<%= link_to t('.actions'), proposal_dashboard_index_path(proposal.to_param) %>
</div>
</div>
<% if proposed_actions.resources.any? %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns"><%= t '.resources' %></div>
</div>
<% proposed_actions.resources.each do |resource| %>
<div class="row">
<div class="small-2 columns"></div>
<div class="small-10 columns">
<span data-tooltip title="<%= resource.description %>">
<% if resource.request_to_administrators? %>
<%= link_to resource.title,
new_request_proposal_dashboard_path(proposal, resource) %>
<% else %>
<%= link_to resource.title, resource.link, target: '_blank' %>
<% end %>
</span>
</div>
</div>
<% end %>
<% end %>

View File

@@ -1,113 +1,6 @@
<div class="proposals-dashboard"> <table>
<div class="column-wrapper">
<div class="left-column">
<div class="state-box">
<div class="logo"></div>
<% if proposal.published? %>
<div class="status published"><%= t '.published' %></div>
<% end %>
<% if proposal.draft? %>
<div class="status draft"><%= t '.draft' %></div>
<% end %>
</div>
<div class="dashboard-menu">
<% if current_editable?(proposal) || can?(:publish, proposal) %>
<div class="menu-title"><span class="icon-user"></span><%= t '.general' %></div>
<% if current_editable?(proposal) %>
<%= link_to t('.edit_proposal_link'), edit_proposal_path(proposal), class: 'menu-entry', target: '_blank' %>
<% end %>
<%= link_to t('.send_notification'),
new_proposal_notification_path(proposal_id: proposal.id),
class: 'menu-entry',
target: '_blank' %>
<% if can_destroy_image?(proposal) %>
<%= link_to t('images.remove_image'),
image_path(proposal.image, from: request.url),
method: :delete,
class: 'menu-entry',
data: { confirm: t('images.actions.destroy.confirm') } %>
<% end %>
<% unless proposal.retired? %>
<%= link_to t('.retire'),
retire_form_proposal_path(proposal),
class: 'menu-entry',
target: '_blank' %>
<% end %>
<%= link_to t('.publish'), publish_proposal_dashboard_index_path(proposal), method: :patch, class: 'menu-entry' if can?(:publish, proposal) %>
<% end %>
<div class="menu-title"><span class="icon-user"></span> <%= t '.progress' %></div>
<!-- a href='#' class="menu-entry">Meta actual</a -->
<%= link_to t('.actions'), proposal_dashboard_index_path(proposal.to_param), class: 'menu-entry' %>
<!-- a href='#' class="menu-entry">Feed</a -->
<!-- a href='#' class="menu-entry">Ruta</a -->
<div class="menu-title"><span class="icon-user"></span> <%= t '.resources' %></div>
<% proposed_actions.resources.each do |resource| %>
<span data-tooltip title="<%= resource.description %>">
<% if resource.request_to_administrators? %>
<%= link_to resource.title,
new_request_proposal_dashboard_path(proposal, resource),
class: 'menu-entry' %>
<% else %>
<%= link_to resource.title,
resource.link,
target: '_blank',
class: 'menu-entry' %>
<% end %>
</span>
<% end %>
<!--
<div class="menu-title"><span class="icon-user"></span> Comunidad</div>
<a href='#' class="menu-entry">Equipo impulsor</a>
<a href='#' class="menu-entry">Mensajes</a>
<a href='#' class="menu-entry">Temas</a>
-->
</div>
</div>
<div class="right-column">
<!--
<div class="progress-info">
<div class="cell-data">
<div class="caption">Apoyos</div>
<div class="value">5.300</div>
</div>
<div class="cell-data">
<div class="caption">Acciones realizadas</div>
<div class="value">3/4</div>
</div>
<div class="cell-data">
<div class="caption">Seguidores</div>
<div class="value">3.403</div>
</div>
<div class="cell-data">
<div class="caption">Meta actual</div>
<div class="value">10.000</div>
</div>
<div class="cell-data">
<div class="caption">Recursos activos</div>
<div class="value">5/10</div>
</div>
<div class="cell-data">
<div class="caption">Notificaciones</div>
<div class="value">3</div>
</div>
</div>
-->
<div class="body">
<table>
<caption><%= t('.actions') %></caption> <caption><%= t('.actions') %></caption>
<% proposed_actions.each do |action| %> <% proposed_actions.each do |action| %>
<%= render partial: 'proposed_action', locals: { action: action } %> <%= render partial: 'proposed_action', locals: { action: action } %>
<% end %> <% end %>
</table> </table>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,20 @@
<div class="small-12 column">
<div class="button-group">
<%= link_to t('.group_by_year'), stats_proposal_dashboard_index_path(proposal, group_by: 'year'), class: 'button' %>
<%= link_to t('.group_by_month'), stats_proposal_dashboard_index_path(proposal, group_by: 'month'), class: 'button' %>
<%= link_to t('.group_by_week'), stats_proposal_dashboard_index_path(proposal, group_by: 'week'), class: 'button' %>
<%= link_to t('.group_by_date'), stats_proposal_dashboard_index_path(proposal), class: 'button' %>
</div>
</div>
<div class="small-12 column">
<div id="proposal-graph"
data-proposal-graph-url="<%= supports_proposal_dashboard_index_path(proposal, format: :json) %>"
data-proposal-graph-group-by="<%= params[:group_by] %>"
data-proposal-graph-progress-label="<%= t '.progress' %>"
data-proposal-graph-supports-label="<%= t '.supports' %>"
class="c3"
style="max-height: 320px; position: relative;"></div>
</div>
<%= javascript_include_tag 'dashboard_graphs', 'data-turbolinks-track' => true %>

View File

@@ -12,6 +12,7 @@ Rails.application.config.assets.version = '1.0'
Rails.application.config.assets.precompile += %w( ckeditor/config.js ) Rails.application.config.assets.precompile += %w( ckeditor/config.js )
Rails.application.config.assets.precompile += %w( ie_lt9.js ) Rails.application.config.assets.precompile += %w( ie_lt9.js )
Rails.application.config.assets.precompile += %w( stat_graphs.js ) Rails.application.config.assets.precompile += %w( stat_graphs.js )
Rails.application.config.assets.precompile += %w( dashboard_graphs.js )
Rails.application.config.assets.precompile += %w( print.css ) Rails.application.config.assets.precompile += %w( print.css )
Rails.application.config.assets.precompile += %w( ie.css ) Rails.application.config.assets.precompile += %w( ie.css )

View File

@@ -202,6 +202,8 @@ en:
firefox: Firefox firefox: Firefox
ie: We have detected that you are browsing with Internet Explorer. For an enhanced experience, we recommend using %{firefox} or %{chrome}. ie: We have detected that you are browsing with Internet Explorer. For an enhanced experience, we recommend using %{firefox} or %{chrome}.
ie_title: This website is not optimised for your browser ie_title: This website is not optimised for your browser
proposals_dashboard:
title: Proposal dashboard
footer: footer:
accessibility: Accessibility accessibility: Accessibility
conditions: Terms and conditions of use conditions: Terms and conditions of use
@@ -490,9 +492,7 @@ en:
form: form:
submit_button: Save changes submit_button: Save changes
proposals_dashboard: proposals_dashboard:
index: menu:
draft: Draft
published: Published
general: General general: General
publish: Publish publish: Publish
edit_proposal_link: Edit edit_proposal_link: Edit
@@ -501,12 +501,20 @@ en:
progress: Progress progress: Progress
resources: Resources resources: Resources
actions: Actions actions: Actions
graphic: Graphic
proposed_action: proposed_action:
execute: Execute execute: Execute
form: form:
request: Request request: Request
create_request: create_request:
success: The request for the administrator has been successfully sent. success: The request for the administrator has been successfully sent.
stats:
group_by_year: Group by year
group_by_month: Group by month
group_by_week: Group by week
group_by_date: Group by date
progress: Acumulated progress
supports: Supports
polls: polls:
all: "All" all: "All"
no_dates: "no date assigned" no_dates: "no date assigned"

View File

@@ -202,6 +202,8 @@ es:
firefox: Firefox firefox: Firefox
ie: Hemos detectado que estás navegando desde Internet Explorer. Para una mejor experiencia te recomendamos utilizar %{firefox} o %{chrome}. ie: Hemos detectado que estás navegando desde Internet Explorer. Para una mejor experiencia te recomendamos utilizar %{firefox} o %{chrome}.
ie_title: Esta web no está optimizada para tu navegador ie_title: Esta web no está optimizada para tu navegador
proposals_dashboard:
title: Dashboard de propuesta
footer: footer:
accessibility: Accesibilidad accessibility: Accesibilidad
conditions: Condiciones de uso conditions: Condiciones de uso
@@ -490,9 +492,7 @@ es:
form: form:
submit_button: Guardar cambios submit_button: Guardar cambios
proposals_dashboard: proposals_dashboard:
index: menu:
draft: Borrador
published: Publicada
general: General general: General
publish: Publicar publish: Publicar
edit_proposal_link: Editar propuesta edit_proposal_link: Editar propuesta
@@ -501,12 +501,20 @@ es:
progress: Progreso progress: Progreso
resources: Recursos resources: Recursos
actions: Acciones actions: Acciones
graphic: Gráfico
proposed_action: proposed_action:
execute: Ejecutar execute: Ejecutar
form: form:
request: Solicitar request: Solicitar
create_request: create_request:
success: La petición ha sido correctamente enviada al administrador. success: La petición ha sido correctamente enviada al administrador.
stats:
group_by_year: Agrupar por año
group_by_month: Agrupar por meses
group_by_week: Agrupar por semanas
group_by_date: Agrupar por fechas
progress: Progreso acumulado
supports: Apoyos
polls: polls:
all: "Todas" all: "Todas"
no_dates: "sin fecha asignada" no_dates: "sin fecha asignada"

View File

@@ -2,6 +2,8 @@ resources :proposals do
resources :proposals_dashboard, as: :dashboard, path: :dashboard, only: %i[index] do resources :proposals_dashboard, as: :dashboard, path: :dashboard, only: %i[index] do
collection do collection do
patch :publish patch :publish
get :supports
get :stats
end end
member do member do