Merge pull request #3439 from LextrendIT/feature/add_admin_investments_column_chooser

Add columns selector JS component and change Rails view to use it
This commit is contained in:
Raimond Garcia
2019-06-11 17:17:52 +02:00
committed by GitHub
25 changed files with 346 additions and 55 deletions

View File

@@ -83,6 +83,8 @@
//= require globalize
//= require send_admin_notification_alert
//= require settings
//= require cookies
//= require columns_selector
var initialize_modules = function() {
App.Answers.initialize();
@@ -131,6 +133,9 @@ var initialize_modules = function() {
App.Globalize.initialize();
App.SendAdminNotificationAlert.initialize();
App.Settings.initialize();
App.Cookies.initialize();
if ( $('#js-columns-selector').length )
App.ColumnsSelector.initialize();
};
$(function(){

View File

@@ -0,0 +1,81 @@
App.ColumnsSelector =
initColums: (name) ->
App.ColumnsSelector.hideAll()
c_value = App.ColumnsSelector.currentValue()
if c_value.length == 0
c_value = $("#js-columns-selector").data("default")
App.Cookies.saveCookie($("#js-columns-selector").data("cookie"), c_value, 30)
columns = c_value.split(",")
for column in columns
do ->
$("[data-field=" + column + "]").removeClass("hidden")
$("#column_selector_" + column).prop("checked", true)
initChecks: () ->
fields = $(".column-selecteable th[data-field]")
columns = []
$(".column-selecteable th[data-field]").each ->
field = $(this).data("field")
text = $.trim($(this).text())
item = $("#column_selector_item_template").clone()
item.prop("id", "column_selector_item_" + field)
input = item.find("input")
input.prop("name", "column-selector[" + field + "]")
input.prop("id", "column_selector_" + field)
input.data("column", field)
label = item.find("label")
label.prop("for", "column_selector_" + field)
label.text(text)
item.removeClass("hidden")
$("#js-columns-selector-wrapper").append(item)
toggleOptions: (event) ->
event.preventDefault()
$("#js-columns-selector").toggleClass("hollow")
$("#js-columns-selector-wrapper").toggleClass("hidden")
hideAll: () ->
$("[data-field]").addClass("hidden")
$(".column-selector-item input").prop("checked", false)
toggleColumn: (event) ->
column = $(event.target).data("column")
App.ColumnsSelector.displayColumn(column)
displayColumn: (column) ->
item = $("#column_selector_" + column)
if item.prop("checked")
$("[data-field=" + column + "]").removeClass("hidden")
else
$("[data-field=" + column + "]").addClass("hidden")
value = App.ColumnsSelector.updateItem(column)
App.Cookies.saveCookie($("#js-columns-selector").data("cookie"), value, 30)
updateItem: (value) ->
values = App.ColumnsSelector.currentValue().split(",")
index = values.indexOf(value)
if index >= 0
values.splice index, 1
else
values.push value
values.join ","
currentValue: () ->
App.Cookies.getCookie($("#js-columns-selector").data("cookie"))
initialize: ->
App.ColumnsSelector.initChecks()
columns = App.ColumnsSelector.initColums($("#js-columns-selector").data("cookie"))
$("#js-columns-selector").on
click: (event) ->
App.ColumnsSelector.toggleOptions(event)
$(".column-selector-item input").on
click: (event) ->
App.ColumnsSelector.toggleColumn(event)

View File

@@ -0,0 +1,29 @@
App.Cookies =
removeCookie: (name) ->
document.cookie("name", null, { path: '/' })
saveCookie: (name, value, days) ->
expires = undefined
if days
date = new Date
date.setTime date.getTime() + days * 24 * 60 * 60 * 1000
expires = '; expires=' + date.toGMTString()
else
expires = ''
document.cookie = name + '=' + value + expires + '; path=/'
return
getCookie: (name) ->
if document.cookie.length > 0
c_start = document.cookie.indexOf(name + '=')
if c_start != -1
c_start = c_start + name.length + 1
c_end = document.cookie.indexOf(';', c_start)
if c_end == -1
c_end = document.cookie.length
return unescape(document.cookie.substring(c_start, c_end))
''
initialize: ->
''

View File

@@ -1258,6 +1258,44 @@ table {
}
}
.columns-selector {
span[class^="icon-"] {
vertical-align: middle;
}
}
.columns-selector-wrapper {
background: $light-gray;
padding: 2rem;
border-radius: 10px;
margin-bottom: 1rem;
&.hidden {
display: none;
}
.column-selector-item {
display: inline-block;
&.hidden {
display: none;
}
label {
font-size: 17px;
line-height: 1.5rem;
}
}
}
.column-selecteable {
.hidden {
display: none;
}
}
// 11. Newsletters
// -----------------

View File

@@ -20,29 +20,39 @@
<% end %>
<% if @investments.any? %>
<h3 class="inline-block"><%= page_entries_info @investments %></h3><br>
<h3 class="inline-block"><%= page_entries_info @investments %></h3>
<%= render partial: "admin/shared/columns_selector",
locals: { cookie: "investments-columns", default: %w[id title supports admin valuator geozone feasibility price valuation_finished visible_to_valuators selected incompatible] } %>
<br>
<%= render "filters_description", i18n_namespace: "admin.budget_investments.index" %>
<table class="table-for-mobile">
<table class="table-for-mobile column-selecteable">
<thead>
<tr>
<th><%= link_to_investments_sorted_by :id %></th>
<th class="small-3"><%= link_to_investments_sorted_by :title %></th>
<th><%= link_to_investments_sorted_by :supports %></th>
<th><%= t("admin.budget_investments.index.list.admin") %></th>
<th>
<%= t("admin.budget_investments.index.list.valuation_group") %>
<th data-field="title"><%= link_to_investments_sorted_by :title %></th>
<th data-field="supports"><%= link_to_investments_sorted_by :supports %></th>
<th data-field="admin"><%= t("admin.budget_investments.index.list.admin") %></th>
<th data-field="author">
<%= t("admin.budget_investments.index.list.author") %>
</th>
<th data-field="valuator">
<%= t("admin.budget_investments.index.list.valuation_group") %> /
<%= t("admin.budget_investments.index.list.valuator") %>
</th>
<th><%= t("admin.budget_investments.index.list.geozone") %></th>
<th><%= t("admin.budget_investments.index.list.feasibility") %></th>
<th><%= t("admin.budget_investments.index.list.price") %></th>
<th class="text-center"><%= t("admin.budget_investments.index.list.valuation_finished") %></th>
<th class="text-center"><%= t("admin.budget_investments.index.list.visible_to_valuators") %></th>
<th class="text-center"><%= t("admin.budget_investments.index.list.selected") %></th>
<% if params[:filter] == "selected" %>
<th class="text-center"><%= t("admin.budget_investments.index.list.incompatible") %></th>
<th data-field="geozone"><%= t("admin.budget_investments.index.list.geozone") %></th>
<th data-field="feasibility"><%= t("admin.budget_investments.index.list.feasibility") %></th>
<th data-field="price"><%= t("admin.budget_investments.index.list.price") %></th>
<th data-field="valuation_finished">
<%= t("admin.budget_investments.index.list.valuation_finished") %>
</th>
<th data-field="visible_to_valuators">
<%= t("admin.budget_investments.index.list.visible_to_valuators") %>
</th>
<th data-field="selected"><%= t("admin.budget_investments.index.list.selected") %></th>
<% if params[:advanced_filters]&.include?("selected") %>
<th data-field="incompatible"><%= t("admin.budget_investments.index.list.incompatible") %></th>
<% end %>
</tr>
</thead>

View File

@@ -1,45 +1,56 @@
<td class="text-right">
<td class="text-right" data-field="id">
<strong><%= investment.id %></strong>
</td>
<td>
<td data-field="title">
<%= link_to investment.title,
admin_budget_budget_investment_path(budget_id: @budget.id,
id: investment.id,
params: Budget::Investment.filter_params(params).to_h),
target: "_blank" %>
</td>
<td class="text-center">
<td class="text-center" data-field="supports">
<%= investment.total_votes %>
</td>
<td class="small">
<td class="small" data-field="admin">
<% if investment.administrator.present? %>
<span title="<%= t("admin.budget_investments.index.assigned_admin") %>">
<%= investment.administrator.description_or_name %>
</span>
<% else %>
<%= t("admin.budget_investments.index.no_admin_assigned") %>
<%= t("admin.budget_investments.index.no_admin_assigned") %>
<% end %>
</td>
<td class="small">
<% no_valuation_groups = t("admin.budget_investments.index.no_valuation_groups") %>
<%= investment.assigned_valuation_groups || no_valuation_groups %>
<br>
<% no_valuators_assigned = t("admin.budget_investments.index.no_valuators_assigned") %>
<%= investment.assigned_valuators || no_valuators_assigned %>
<td class="small" data-field="author">
<%= investment.author.name %>
</td>
<td class="small">
<td class="small" data-field="valuator">
<% valuators = [investment.assigned_valuation_groups, investment.assigned_valuators].compact %>
<% no_valuators_assigned = t("admin.budget_investments.index.no_valuators_assigned") %>
<%= raw valuators.present? ? valuators.join(", ") : no_valuators_assigned %>
</td>
<td class="small" data-field="geozone">
<%= investment.heading.name %>
</td>
<td class="small">
<td class="small" data-field="feasibility">
<%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}") %>
</td>
<td class="small">
<td class="small" data-field="price">
<%= investment.formatted_price %>
</td>
<td class="small text-center">
<td class="small text-center" data-field="valuation_finished">
<%= investment.valuation_finished? ? t("shared.yes"): t("shared.no") %>
</td>
<td class="small text-center">
<td class="small text-center" data-field="visible_to_valuators">
<%= form_for [:admin, investment.budget, investment], remote: true do |f| %>
<%= f.check_box :visible_to_valuators,
label: false,
@@ -47,7 +58,8 @@
id: "budget_investment_visible_to_valuators" %>
<% end %>
</td>
<td id="selection" class="small text-center">
<td id="selection" class="small text-center" data-field="selected">
<% if investment.selected? %>
<%= link_to_unless investment.budget.finished?,
t("admin.budget_investments.index.selected"),
@@ -79,8 +91,9 @@
<% end %>
<% end %>
</td>
<% if params[:filter] == "selected" %>
<td class="small text-center">
<%= investment.incompatible? ? t("shared.yes"): t("shared.no") %>
</td>
<% if params[:advanced_filters]&.include?("selected") %>
<td class="small text-center" data-field="incompatible">
<%= investment.incompatible? ? t("shared.yes"): t("shared.no") %>
</td>
<% end %>

View File

@@ -0,0 +1,11 @@
<span class="button columns-selector hollow" id="js-columns-selector" data-cookie="<%= cookie %>" data-default="<%= default.join(",") %>">
<span class="icon-banner"> </span>
<strong>Columns</strong>
</span>
<div class="hidden columns-selector-wrapper" id="js-columns-selector-wrapper">
<div class="hidden column-selector-item" id="column_selector_item_template">
<input type="checkbox" name="column-selector[template]" id="column_selector_template" data-column="template">
<label for="column_selector_template">Template</label>
</div>
</div>

View File

@@ -217,7 +217,6 @@ ar:
assigned_admin: المدير الذي تم تعيينه
no_admin_assigned: لم يتم تعيين أي مدير
no_valuators_assigned: لم يتم تعيين مقيّمين
no_valuation_groups: لم يتم تعيين مجموعات المقيّمين
feasibility:
feasible: "مجدي (%{price})"
unfeasible: "غير مجدي"

View File

@@ -202,7 +202,6 @@ de:
assigned_admin: Zugewiesene*r Administrator*in
no_admin_assigned: Kein*e Administrator*in zugewiesen
no_valuators_assigned: Kein*e Begutacher*in zugewiesen
no_valuation_groups: Keine Begutachtungsgruppe zugewiesen
feasibility:
feasible: "Durchführbar (%{price})"
unfeasible: "Undurchführbar"

View File

@@ -208,7 +208,6 @@ en:
assigned_admin: Assigned administrator
no_admin_assigned: No admin assigned
no_valuators_assigned: No valuators assigned
no_valuation_groups: No valuation groups assigned
feasibility:
feasible: "Feasible"
unfeasible: "Unfeasible"
@@ -230,6 +229,7 @@ en:
author_username: Author username
incompatible: Incompatible
price: Price
author: Author
cannot_calculate_winners: The budget has to stay on phase "Balloting projects", "Reviewing Ballots" or "Finished budget" in order to calculate winners projects
see_results: "See results"
show:

View File

@@ -208,7 +208,6 @@ es:
assigned_admin: Administrador asignado
no_admin_assigned: Sin admin asignado
no_valuators_assigned: Sin evaluador
no_valuation_groups: Sin grupos evaluadores
feasibility:
feasible: "Viable"
unfeasible: "Inviable"
@@ -230,6 +229,7 @@ es:
author_username: Usuario autor
incompatible: Incompatible
price: Precio
author: Autor
cannot_calculate_winners: El presupuesto debe estar en las fases "Votación final", "Votación finalizada" o "Resultados" para poder calcular las propuestas ganadoras
see_results: "Ver resultados"
show:

View File

@@ -157,7 +157,6 @@ fa:
assigned_admin: سرپرست تعیین شده
no_admin_assigned: بدون تعیین مدیر
no_valuators_assigned: بدون تعیین ارزیاب
no_valuation_groups: بدون تعیین گروه ارزیاب
feasibility:
feasible: "امکان پذیر %{price}\n"
unfeasible: "غیر قابل پیش بینی"

View File

@@ -205,7 +205,6 @@ fr:
assigned_admin: Administrateur affecté
no_admin_assigned: Aucun administrateur affecté
no_valuators_assigned: Aucun évaluateur affecté
no_valuation_groups: Aucun groupe dévaluation assignés
feasibility:
feasible: "Réalisable (%{price})"
unfeasible: "Infaisable"

View File

@@ -202,7 +202,6 @@ gl:
assigned_admin: Administrador asignado
no_admin_assigned: Sen administrador asignado
no_valuators_assigned: Sen avaliador
no_valuation_groups: Grupos asignados sen valoración
feasibility:
feasible: "Viable (%{price})"
unfeasible: "Non viables"

View File

@@ -169,7 +169,6 @@ it:
assigned_admin: Amministratore assegnato
no_admin_assigned: Nessun amministratore assegnato
no_valuators_assigned: Nessun valutatore assegnato
no_valuation_groups: Nessun gruppo di stima assegnato
feasibility:
feasible: "Fattibile (%{price})"
unfeasible: "Irrealizzabile"

View File

@@ -208,7 +208,6 @@ pl:
assigned_admin: Przypisany administrator
no_admin_assigned: Nie przypisano administratora
no_valuators_assigned: Brak przypisanych wyceniających
no_valuation_groups: Nie przypisano żadnych grup wyceny
feasibility:
feasible: "Wykonalne (%{price})"
unfeasible: "Niewykonalne"

View File

@@ -165,7 +165,6 @@ pt-BR:
assigned_admin: Administrador designado
no_admin_assigned: Não há administrador designado
no_valuators_assigned: Não há avaliadores designados
no_valuation_groups: Não há grupos de avaliação atribuídos
feasibility:
feasible: "Factível (%{price})"
unfeasible: "Inviável"

View File

@@ -209,7 +209,6 @@ ru:
assigned_admin: Назначенный администратор
no_admin_assigned: Ни один администратор не назначен
no_valuators_assigned: Ни один оценщик не назначен
no_valuation_groups: Не назначено ни одной группы оценки
feasibility:
feasible: "Приемлемая (%{price})"
unfeasible: "Неприемлемая"

View File

@@ -165,7 +165,6 @@ so:
assigned_admin: Mamulaha lamagcaabay
no_admin_assigned: Mamule lama magcabin
no_valuators_assigned: Majiraan Qimeeyayaal loo qondeyey
no_valuation_groups: Majiraan koox qimeyayala o loo qondeyey
feasibility:
feasible: "Suurto gal %{price}"
unfeasible: "An surtgak ahayn"

View File

@@ -165,7 +165,6 @@ sq:
assigned_admin: Administrator i caktuar
no_admin_assigned: Asnjë admin i caktuar
no_valuators_assigned: Asnjë vlerësues nuk është caktuar
no_valuation_groups: Asnjë grup vlerësimi nuk është caktuar
feasibility:
feasible: "I mundshëm%{price}"
unfeasible: "Parealizueshme"

View File

@@ -170,7 +170,6 @@ sv:
assigned_admin: Ansvarig administratör
no_admin_assigned: Saknar ansvarig administratör
no_valuators_assigned: Inga ansvariga bedömare
no_valuation_groups: Inga ansvariga bedömningsgrupper
feasibility:
feasible: "Genomförbart (%{price})"
unfeasible: "Ej genomförbart"

View File

@@ -202,7 +202,6 @@ val:
assigned_admin: Administrador asignat
no_admin_assigned: Sense admin assignat
no_valuators_assigned: Sense avaluador asignat
no_valuation_groups: Sense grups avaluadors
feasibility:
feasible: "Viable (%{price})"
unfeasible: "Inviable"

View File

@@ -165,7 +165,6 @@ zh-CN:
assigned_admin: 指定的管理员
no_admin_assigned: 没有指定管理员
no_valuators_assigned: 没有指定评估员
no_valuation_groups: 没有指定评估组
feasibility:
feasible: "可行 (%{price})"
unfeasible: "不可行"

View File

@@ -164,7 +164,6 @@ zh-TW:
assigned_admin: 指定的管理員
no_admin_assigned: 未分配管理員
no_valuators_assigned: 未分配評估員
no_valuation_groups: 未分配評估組
feasibility:
feasible: "可行 (%{price})"
unfeasible: "不可行"

View File

@@ -95,25 +95,26 @@ describe "Admin budget investments" do
miriam = create(:user, username: "Miriam")
valuator1 = create(:valuator, user: olga, description: "Valuator Olga")
valuator2 = create(:valuator, user: miriam, description: "Valuator Miriam")
valuator_group = create(:valuator_group, name: "Health")
admin = create(:administrator, user: create(:user, username: "Gema"))
budget_investment1.valuators << valuator1
budget_investment2.valuators << valuator1
budget_investment2.valuators << valuator2
budget_investment2.valuator_groups << valuator_group
visit admin_budget_budget_investments_path(budget_id: budget.id)
within("#budget_investment_#{budget_investment1.id}") do
expect(page).to have_content("No admin assigned")
expect(page).to have_content("Valuator Olga")
expect(page).to have_content("No valuation groups assigned")
end
within("#budget_investment_#{budget_investment2.id}") do
expect(page).to have_content("No admin assigned")
expect(page).to have_content("Valuator Olga")
expect(page).to have_content("Valuator Miriam")
expect(page).to have_content("No valuation groups assigned")
expect(page).to have_content("Health")
end
budget_investment3.update(administrator_id: admin.id)
@@ -1759,4 +1760,122 @@ describe "Admin budget investments" do
end
end
context "Columns chooser" do
let!(:investment) do
create(:budget_investment,
:winner,
budget: budget,
visible_to_valuators: true,
author: create(:user, username: "Jon Doe")
)
end
let(:default_columns) do
%w[id title supports admin valuator geozone feasibility price
valuation_finished visible_to_valuators selected]
end
let(:selectable_columns) do
%w[title supports admin author valuator geozone feasibility price
valuation_finished visible_to_valuators selected]
end
scenario "Display default columns", :js do
visit admin_budget_budget_investments_path(budget)
within("table.column-selecteable") do
default_columns.each do |default_column|
columns_header = I18n.t("admin.budget_investments.index.list.#{default_column}")
expect(page).to have_content(columns_header)
end
expect(page).to have_content(investment.title)
end
end
scenario "Display incompatible column as default if selected filter was set", :js do
visit admin_budget_budget_investments_path(budget, advanced_filters: ["selected"])
within("table.column-selecteable") do
expect(page).to have_content("Incompatible")
end
expect(page).to have_content(investment.title)
end
scenario "Set cookie with default columns value if undefined", :js do
visit admin_budget_budget_investments_path(budget)
cookies = page.driver.browser.manage.all_cookies
cookie = cookies.find{|cookie| cookie[:name] == "investments-columns"}
cookie_value = cookie[:value]
expect(cookie_value).to eq("id,title,supports,admin,valuator,geozone," +
"feasibility,price,valuation_finished,visible_to_valuators,selected,incompatible")
end
scenario "Use column selector to display visible columns", :js do
visit admin_budget_budget_investments_path(budget)
within("#js-columns-selector") do
find("strong", text: "Columns").click
end
within("#js-columns-selector-wrapper") do
selectable_columns.each do |column|
check_text = I18n.t("admin.budget_investments.index.list.#{column}")
expect(page).to have_content(check_text)
end
end
within("#js-columns-selector-wrapper") do
uncheck "Title"
uncheck "Price"
check "Author"
end
within("table.column-selecteable") do
expect(page).not_to have_content("Title")
expect(page).not_to have_content("Price")
expect(page).to have_content("Author")
expect(page).not_to have_content(investment.title)
expect(page).not_to have_content(investment.formatted_price)
expect(page).to have_content("Jon Doe")
end
end
scenario "Cookie will be updated after change columns selection", :js do
visit admin_budget_budget_investments_path(budget)
within("#js-columns-selector") do
find("strong", text: "Columns").click
end
within("#js-columns-selector-wrapper") do
uncheck "Title"
uncheck "Price"
uncheck "Valuation Group / Valuator"
check "Author"
end
cookies = page.driver.browser.manage.all_cookies
cookie = cookies.find{|cookie| cookie[:name] == "investments-columns"}
cookie_value = cookie[:value]
expect(cookie_value).to eq("id,supports,admin,geozone," +
"feasibility,valuation_finished,visible_to_valuators,selected,incompatible,author")
visit admin_budget_budget_investments_path(budget)
cookies = page.driver.browser.manage.all_cookies
cookie = cookies.find{|cookie| cookie[:name] == "investments-columns"}
cookie_value = cookie[:value]
expect(cookie_value).to eq("id,supports,admin,geozone,feasibility,valuation_finished," +
"visible_to_valuators,selected,incompatible,author")
end
end
end