diff --git a/Gemfile b/Gemfile
index 32e1f6f0a..9f26113fe 100644
--- a/Gemfile
+++ b/Gemfile
@@ -59,6 +59,7 @@ gem "translator-text", "~> 0.1.0"
gem "turbolinks", "~> 5.2.1"
gem "turnout", "~> 2.5.0"
gem "uglifier", "~> 4.2.0"
+gem "view_component", "~> 2.19.1", require: "view_component/engine"
gem "whenever", "~> 1.0.0", require: false
gem "wicked_pdf", "~> 2.1.0"
gem "wkhtmltopdf-binary", "~> 0.12.4"
diff --git a/Gemfile.lock b/Gemfile.lock
index 89922ea49..e44bb04ed 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -608,6 +608,8 @@ GEM
uniform_notifier (1.13.0)
user_agent_parser (2.6.0)
uuidtools (2.1.5)
+ view_component (2.19.1)
+ activesupport (>= 5.0.0, < 7.0)
warden (1.2.9)
rack (>= 2.0.9)
wasabi (3.5.0)
@@ -728,6 +730,7 @@ DEPENDENCIES
turbolinks (~> 5.2.1)
turnout (~> 2.5.0)
uglifier (~> 4.2.0)
+ view_component (~> 2.19.1)
web-console (~> 3.7.0)
webdrivers (~> 4.4.1)
whenever (~> 1.0.0)
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index 2803ccf86..fad0f439a 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -236,16 +236,8 @@ $sidebar-active: #f4fcd0;
table-layout: fixed;
}
- [type="submit"] ~ a,
- a ~ a {
- margin-left: 0;
- margin-right: 0;
- margin-top: $line-height / 2;
-
- @include breakpoint(medium) {
- margin-left: $line-height / 2;
- margin-top: 0;
- }
+ [type="submit"] ~ a {
+ margin-left: $line-height / 2;
}
}
diff --git a/app/assets/stylesheets/admin/table_actions.scss b/app/assets/stylesheets/admin/table_actions.scss
new file mode 100644
index 000000000..9d782a4be
--- /dev/null
+++ b/app/assets/stylesheets/admin/table_actions.scss
@@ -0,0 +1,12 @@
+.admin .table-actions {
+ align-items: baseline;
+ display: flex;
+
+ > :not(:first-child) {
+ margin-left: $line-height / 2;
+ }
+
+ > p {
+ align-self: flex-start;
+ }
+}
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 5158c724d..0e4d08318 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -27,3 +27,4 @@
@import "jquery-ui/sortable";
@import "leaflet";
@import "sticky_overrides";
+@import "admin/*";
diff --git a/app/components/admin/budgets/table_actions_component.html.erb b/app/components/admin/budgets/table_actions_component.html.erb
new file mode 100644
index 000000000..9540163e0
--- /dev/null
+++ b/app/components/admin/budgets/table_actions_component.html.erb
@@ -0,0 +1,11 @@
+<%= render Admin::TableActionsComponent.new(budget, actions: [:edit], edit_text: t("admin.budgets.index.edit_budget")) do %>
+ <%= link_to t("admin.budgets.index.budget_investments"),
+ admin_budget_budget_investments_path(budget_id: budget.id),
+ class: "button hollow medium" %>
+ <%= link_to t("admin.budgets.index.edit_groups"), admin_budget_groups_path(budget) %>
+ <% if budget.poll.present? %>
+ <%= link_to t("admin.budgets.index.admin_ballots"), admin_poll_booth_assignments_path(budget.poll) %>
+ <% else %>
+ <%= link_to_create_budget_poll %>
+ <% end %>
+<% end %>
diff --git a/app/components/admin/budgets/table_actions_component.rb b/app/components/admin/budgets/table_actions_component.rb
new file mode 100644
index 000000000..75dab1850
--- /dev/null
+++ b/app/components/admin/budgets/table_actions_component.rb
@@ -0,0 +1,21 @@
+class Admin::Budgets::TableActionsComponent < ApplicationComponent
+ attr_reader :budget
+
+ def initialize(budget)
+ @budget = budget
+ end
+
+ private
+
+ def link_to_create_budget_poll
+ balloting_phase = budget.phases.find_by(kind: "balloting")
+
+ link_to t("admin.budgets.index.admin_ballots"),
+ admin_polls_path(poll: {
+ name: budget.name,
+ budget_id: budget.id,
+ starts_at: balloting_phase.starts_at,
+ ends_at: balloting_phase.ends_at }),
+ method: :post
+ end
+end
diff --git a/app/components/admin/hidden_table_actions_component.html.erb b/app/components/admin/hidden_table_actions_component.html.erb
new file mode 100644
index 000000000..7cf58e888
--- /dev/null
+++ b/app/components/admin/hidden_table_actions_component.html.erb
@@ -0,0 +1,12 @@
+<%= render Admin::TableActionsComponent.new(actions: []) do %>
+ <%= link_to restore_text, restore_path,
+ method: :put,
+ data: { confirm: t("admin.actions.confirm") },
+ class: "button hollow warning" %>
+
+ <% unless record.confirmed_hide? %>
+ <%= link_to confirm_hide_text, confirm_hide_path,
+ method: :put,
+ class: "button" %>
+ <% end %>
+<% end %>
diff --git a/app/components/admin/hidden_table_actions_component.rb b/app/components/admin/hidden_table_actions_component.rb
new file mode 100644
index 000000000..68647d130
--- /dev/null
+++ b/app/components/admin/hidden_table_actions_component.rb
@@ -0,0 +1,34 @@
+class Admin::HiddenTableActionsComponent < ApplicationComponent
+ attr_reader :record
+
+ def initialize(record)
+ @record = record
+ end
+
+ private
+
+ def restore_text
+ t("admin.actions.restore")
+ end
+
+ def restore_path
+ action_path(:restore)
+ end
+
+ def confirm_hide_text
+ t("admin.actions.confirm_hide")
+ end
+
+ def confirm_hide_path
+ action_path(:confirm_hide)
+ end
+
+ def action_path(action)
+ url_for({
+ controller: "admin/hidden_#{record.model_name.plural}",
+ action: action,
+ id: record,
+ only_path: true
+ }.merge(request.query_parameters))
+ end
+end
diff --git a/app/components/admin/organizations/table_actions_component.html.erb b/app/components/admin/organizations/table_actions_component.html.erb
new file mode 100644
index 000000000..5c0b565ab
--- /dev/null
+++ b/app/components/admin/organizations/table_actions_component.html.erb
@@ -0,0 +1,13 @@
+<%= render Admin::TableActionsComponent.new(actions: []) do %>
+ <% if can_verify? %>
+ <%= link_to t("admin.organizations.index.verify"),
+ verify_admin_organization_path(organization, request.query_parameters),
+ method: :put, class: "button success small-5" %>
+ <% end %>
+
+ <% if can_reject? %>
+ <%= link_to t("admin.organizations.index.reject"),
+ reject_admin_organization_path(organization, request.query_parameters),
+ method: :put, class: "button hollow alert small-5" %>
+ <% end %>
+<% end %>
diff --git a/app/components/admin/organizations/table_actions_component.rb b/app/components/admin/organizations/table_actions_component.rb
new file mode 100644
index 000000000..d0b29708f
--- /dev/null
+++ b/app/components/admin/organizations/table_actions_component.rb
@@ -0,0 +1,18 @@
+class Admin::Organizations::TableActionsComponent < ApplicationComponent
+ delegate :can?, to: :controller
+ attr_reader :organization
+
+ def initialize(organization)
+ @organization = organization
+ end
+
+ private
+
+ def can_verify?
+ can? :verify, organization
+ end
+
+ def can_reject?
+ can? :reject, organization
+ end
+end
diff --git a/app/components/admin/poll/officers/officers_component.html.erb b/app/components/admin/poll/officers/officers_component.html.erb
new file mode 100644
index 000000000..baf93a50f
--- /dev/null
+++ b/app/components/admin/poll/officers/officers_component.html.erb
@@ -0,0 +1,36 @@
+<%= tag.table options do %>
+
+
+
+
+ <%= t("admin.poll_officers.officer.name") %>
+ <%= t("admin.poll_officers.officer.email") %>
+ <%= t("admin.actions.actions") %>
+
| <%= t("admin.poll_officers.officer.name") %> | -<%= t("admin.poll_officers.officer.email") %> | -<%= t("admin.actions.actions") %> | -
|---|---|---|
| - <%= officer.name %> - | -- <%= officer.email %> - | -- <% if officer.persisted? %> - <%= link_to t("admin.poll_officers.officer.delete"), - admin_officer_path(officer), - method: :delete, - class: "button hollow alert expanded" %> - <% else %> - <%= link_to t("admin.poll_officers.officer.add"), { controller: "admin/poll/officers", action: :create, user_id: officer.user_id }, - method: :post, - class: "button success expanded" %> - <% end %> - | -
| <%= t("admin.poll_officers.officer.name") %> | -<%= t("admin.poll_officers.officer.email") %> | -<%= t("admin.actions.actions") %> | -
|---|---|---|
| - <%= officer.name %> - | -- <%= officer.email %> - | -- <% if officer.persisted? %> - <%= link_to t("admin.poll_officers.officer.delete"), - admin_officer_path(officer), - method: :delete, - class: "button hollow alert expanded" - %> - <% else %> - <%= link_to t("admin.poll_officers.officer.add"), - { controller: "admin/poll/officers", action: :create, - user_id: officer.user_id }, - method: :post, - class: "button success expanded" %> - <% end %> - | -
| <%= t("admin.questions.show.answers.document_title") %> | -<%= t("admin.questions.show.answers.document_actions") %> | +<%= t("admin.questions.show.answers.document_actions") %> | <%= link_to document.title, document.attachment.url %> | -- <%= link_to t("documents.buttons.download_document"), - document.attachment.url, - target: "_blank", - rel: "nofollow", - class: "button hollow" %> + | + <%= render Admin::TableActionsComponent.new(document, + actions: [:destroy], + destroy_path: document_path(document) + ) do |actions| %> + <%= actions.link_to t("documents.buttons.download_document"), + document.attachment.url, + target: "_blank", + rel: "nofollow", + class: "button hollow" %> - <%= link_to t("admin.shared.delete"), - document_path(document), - method: :delete, - class: "button hollow alert", - data: { confirm: t("admin.actions.confirm") } %> + <% end %> | <% end %> diff --git a/app/views/admin/poll/questions/answers/videos/index.html.erb b/app/views/admin/poll/questions/answers/videos/index.html.erb index 0ea64c570..e2995d0e2 100644 --- a/app/views/admin/poll/questions/answers/videos/index.html.erb +++ b/app/views/admin/poll/questions/answers/videos/index.html.erb @@ -17,9 +17,7 @@
|---|---|---|---|
| <%= t("admin.answers.videos.index.video_title") %> | <%= t("admin.answers.videos.index.video_url") %> | -- <%= t("admin.actions.actions") %> - | +<%= t("admin.actions.actions") %> |
| <%= video.title %> | <%= link_to "#{video.url}", video.url %> | -- - <%= link_to t("shared.edit"), - edit_admin_video_path(video), - class: "button hollow" %> - - <%= link_to t("shared.delete"), - admin_video_path(video), - class: "button hollow alert", - method: :delete %> + | + <%= render Admin::TableActionsComponent.new(video) %> |
| <%= t("admin.poll_shifts.new.table_name") %> | <%= t("admin.poll_shifts.new.table_email") %> | -- <%= t("admin.poll_shifts.new.table_shift") %> - | +<%= t("admin.poll_shifts.new.table_shift") %> | <%= user.email %> | -- <%= link_to t("admin.poll_shifts.new.edit_shifts"), - new_admin_booth_shift_path(officer_id: user.poll_officer.id), - class: "button hollow" %> + | + <%= render Admin::TableActionsComponent.new( + actions: [:edit], + edit_text: t("admin.poll_shifts.new.edit_shifts"), + edit_path: new_admin_booth_shift_path(officer_id: user.poll_officer.id) + ) %> | <% end %> diff --git a/app/views/admin/poll/shifts/_shifts.html.erb b/app/views/admin/poll/shifts/_shifts.html.erb index 140ae43c9..af3c0e662 100644 --- a/app/views/admin/poll/shifts/_shifts.html.erb +++ b/app/views/admin/poll/shifts/_shifts.html.erb @@ -6,7 +6,7 @@<%= t("admin.poll_shifts.new.officer") %> | <%= t("admin.poll_shifts.new.table_email") %> | <%= Poll::Shift.human_attribute_name(:task) %> | -<%= t("admin.poll_shifts.new.shift") %> | +<%= t("admin.poll_shifts.new.shift") %> | @@ -17,10 +17,10 @@<%= shift.officer_email %> | <%= t("admin.poll_shifts.#{shift.task}") %> | - <%= link_to t("admin.poll_shifts.new.remove_shift"), - admin_booth_shift_path(@booth, shift), - method: :delete, - class: "button hollow alert expanded" %> + <%= render Admin::TableActionsComponent.new(shift, + actions: [:destroy], + destroy_text: t("admin.poll_shifts.new.remove_shift") + ) %> | <% end %> diff --git a/app/views/admin/progress_bars/_progress_bars.html.erb b/app/views/admin/progress_bars/_progress_bars.html.erb index 1ac03e331..3615342b9 100644 --- a/app/views/admin/progress_bars/_progress_bars.html.erb +++ b/app/views/admin/progress_bars/_progress_bars.html.erb @@ -36,14 +36,7 @@ <%= number_to_percentage(progress_bar.percentage, strip_insignificant_zeros: true) %>- <%= link_to t("admin.actions.edit"), - admin_polymorphic_path(progress_bar, action: :edit), - class: "button hollow" %> - - <%= link_to t("admin.actions.delete"), - admin_polymorphic_path(progress_bar), - method: :delete, - class: "button hollow alert" %> + <%= render Admin::TableActionsComponent.new(progress_bar) %> | <% end %> diff --git a/app/views/admin/site_customization/cards/_card.html.erb b/app/views/admin/site_customization/cards/_card.html.erb index 44a49f989..578b3c01a 100644 --- a/app/views/admin/site_customization/cards/_card.html.erb +++ b/app/views/admin/site_customization/cards/_card.html.erb @@ -17,14 +17,8 @@ <% end %>- <%= link_to t("admin.actions.edit"), - edit_admin_widget_card_path(card, page_id: params[:page_id]), - class: "button hollow" %> - - <%= link_to t("admin.actions.delete"), - admin_widget_card_path(card, page_id: params[:page_id]), - method: :delete, - data: { confirm: t("admin.actions.confirm") }, - class: "button hollow alert" %> + <%= render Admin::TableActionsComponent.new(card, + edit_path: edit_admin_widget_card_path(card, page_id: params[:page_id]) + ) %> | diff --git a/app/views/admin/site_customization/content_blocks/index.html.erb b/app/views/admin/site_customization/content_blocks/index.html.erb index 17328f8a2..ef069e448 100644 --- a/app/views/admin/site_customization/content_blocks/index.html.erb +++ b/app/views/admin/site_customization/content_blocks/index.html.erb @@ -34,9 +34,10 @@<%= link_to "#{content_block.name} (#{content_block.locale})", edit_admin_site_customization_content_block_path(content_block) %> | <%= raw content_block.body %> | - <%= link_to t("admin.site_customization.content_blocks.index.delete"), - admin_site_customization_content_block_path(content_block), - method: :delete, class: "button hollow alert" %> + <%= render Admin::TableActionsComponent.new(content_block, + actions: [:destroy], + destroy_text: t("admin.site_customization.content_blocks.index.delete") + ) %> | <% end %> @@ -45,9 +46,11 @@<%= link_to "#{content_block.heading.name} (#{content_block.locale})", admin_site_customization_edit_heading_content_block_path(content_block) %> | <%= raw content_block.body %> | - <%= link_to t("admin.site_customization.content_blocks.index.delete"), - admin_site_customization_delete_heading_content_block_path(content_block.id), - method: :delete, class: "button hollow alert" %> + <%= render Admin::TableActionsComponent.new( + actions: [:destroy], + destroy_text: t("admin.site_customization.content_blocks.index.delete"), + destroy_path: admin_site_customization_delete_heading_content_block_path(content_block) + ) %> | <% end %> diff --git a/app/views/admin/site_customization/documents/index.html.erb b/app/views/admin/site_customization/documents/index.html.erb index a4bc3de65..c92462cb9 100644 --- a/app/views/admin/site_customization/documents/index.html.erb +++ b/app/views/admin/site_customization/documents/index.html.erb @@ -26,11 +26,10 @@<%= link_to document.title, document.attachment.url, target: :blank %> |
- <%= link_to t("admin.shared.delete"),
- admin_site_customization_document_path(document),
- method: :delete,
- class: "button hollow alert",
- data: { confirm: t("admin.actions.confirm") } %>
+ <%= render Admin::TableActionsComponent.new(
+ actions: [:destroy],
+ destroy_path: admin_site_customization_document_path(document)
+ ) %>
|
diff --git a/app/views/admin/site_customization/pages/index.html.erb b/app/views/admin/site_customization/pages/index.html.erb
index d902086fc..359ba932f 100644
--- a/app/views/admin/site_customization/pages/index.html.erb
+++ b/app/views/admin/site_customization/pages/index.html.erb
@@ -35,20 +35,17 @@
<%= I18n.l page.created_at, format: :short %> | <%= t("admin.site_customization.pages.page.status_#{page.status}") %> |
-
+ <%= render Admin::TableActionsComponent.new(page,
+ actions: [:destroy],
+ destroy_text: t("admin.site_customization.pages.index.delete")
+ ) do |actions| %>
<% if page.status == "published" %>
- <%= link_to t("admin.site_customization.pages.index.see_page"),
- page.url,
- target: "_blank",
- class: "button hollow expanded" %>
+ <%= actions.link_to t("admin.site_customization.pages.index.see_page"),
+ page.url,
+ target: "_blank",
+ class: "button hollow" %>
<% end %>
-
-
- <%= link_to t("admin.site_customization.pages.index.delete"),
- admin_site_customization_page_path(page),
- method: :delete,
- class: "button hollow alert expanded" %>
-
+ <% end %>
|
<% end %>
diff --git a/app/views/admin/system_emails/index.html.erb b/app/views/admin/system_emails/index.html.erb
index 3e8cabc3b..c70793954 100644
--- a/app/views/admin/system_emails/index.html.erb
+++ b/app/views/admin/system_emails/index.html.erb
@@ -18,32 +18,29 @@
<%= t("admin.system_emails.#{system_email_title}.description") %>
- <% if system_email_actions.include?("view") %>
-
- <%= link_to t("admin.shared.view"), admin_system_email_view_path(system_email_title),
- class: "button hollow expanded" %>
-
- <% end %>
- <% if system_email_actions.include?("preview_pending") %>
-
- <%= link_to t("admin.system_emails.preview_pending.action"),
- admin_system_email_preview_pending_path(system_email_title),
- class: "button expanded" %>
-
-
- <%= link_to t("admin.system_emails.preview_pending.send_pending"),
- admin_system_email_send_pending_path(system_email_title),
- class: "button success expanded",
- method: :put %>
-
- <% end %>
- <% if system_email_actions.include?("edit_info") %>
-
+ <%= render Admin::TableActionsComponent.new(actions: []) do |actions| %>
+ <% if system_email_actions.include?("view") %>
+ <%= actions.link_to t("admin.shared.view"),
+ admin_system_email_view_path(system_email_title),
+ class: "button hollow" %>
+ <% end %>
+
+ <% if system_email_actions.include?("preview_pending") %>
+ <%= actions.link_to t("admin.system_emails.preview_pending.action"),
+ admin_system_email_preview_pending_path(system_email_title),
+ class: "button" %>
+ <%= actions.link_to t("admin.system_emails.preview_pending.send_pending"),
+ admin_system_email_send_pending_path(system_email_title),
+ class: "button success",
+ method: :put %>
+ <% end %>
+
+ <% if system_email_actions.include?("edit_info") %>
+ <% end %>
<% end %>
<%= t("admin.system_emails.edit_info") %> |
diff --git a/app/views/admin/tags/index.html.erb b/app/views/admin/tags/index.html.erb
index 26e58e040..d50d4283b 100644
--- a/app/views/admin/tags/index.html.erb
+++ b/app/views/admin/tags/index.html.erb
@@ -30,7 +30,7 @@
<% end %>
- <%= link_to t("admin.tags.destroy"), admin_tag_path(tag), method: :delete, class: "button hollow alert" %> + <%= render Admin::TableActionsComponent.new(tag, actions: [:destroy], destroy_text: t("admin.tags.destroy")) %> | <% end %> diff --git a/app/views/admin/valuator_groups/_group.html.erb b/app/views/admin/valuator_groups/_group.html.erb index ea69515f7..4de3e2e03 100644 --- a/app/views/admin/valuator_groups/_group.html.erb +++ b/app/views/admin/valuator_groups/_group.html.erb @@ -6,12 +6,6 @@ <%= group.valuators.count %>- <%= link_to t("admin.actions.delete"), - admin_valuator_group_path(group), - method: :delete, class: "button hollow alert" %> - - <%= link_to t("admin.actions.edit"), - edit_admin_valuator_group_path(group), - class: "button hollow" %> + <%= render Admin::TableActionsComponent.new(group) %> | diff --git a/app/views/admin/valuators/_valuator_row.html.erb b/app/views/admin/valuators/_valuator_row.html.erb index a09e9fd51..a93d492d7 100644 --- a/app/views/admin/valuators/_valuator_row.html.erb +++ b/app/views/admin/valuators/_valuator_row.html.erb @@ -19,12 +19,6 @@ <%= valuator_abilities(valuator) %>- <%= link_to t("admin.actions.edit"), - edit_admin_valuator_path(valuator), - class: "button hollow" %> - <%= link_to t("admin.valuators.valuator.delete"), - admin_valuator_path(valuator), - method: :delete, - class: "button hollow alert" %> + <%= render Admin::TableActionsComponent.new(valuator) %> | diff --git a/config/application.rb b/config/application.rb index 819918788..935dffa93 100644 --- a/config/application.rb +++ b/config/application.rb @@ -112,6 +112,7 @@ module Consul # * English: https://github.com/consul/consul/blob/master/CUSTOMIZE_EN.md # * Spanish: https://github.com/consul/consul/blob/master/CUSTOMIZE_ES.md # + config.autoload_paths << "#{Rails.root}/app/components/custom" config.autoload_paths << "#{Rails.root}/app/controllers/custom" config.autoload_paths << "#{Rails.root}/app/models/custom" config.paths["app/views"].unshift(Rails.root.join("app", "views", "custom")) diff --git a/config/initializers/routes_hierarchy.rb b/config/initializers/routes_hierarchy.rb index 54addcc95..fd096a64a 100644 --- a/config/initializers/routes_hierarchy.rb +++ b/config/initializers/routes_hierarchy.rb @@ -16,8 +16,8 @@ module ActionDispatch::Routing::UrlFor end def admin_polymorphic_path(resource, options = {}) - if %w[Budget::Group Budget::Heading Poll::Booth Poll::Officer - Poll::Question Poll::Question::Answer::Video].include?(resource.class.name) + if %w[Budget::Group Budget::Heading Poll::Booth Poll::BoothAssignment Poll::Officer + Poll::Question Poll::Question::Answer::Video Poll::Shift].include?(resource.class.name) resolve = resolve_for(resource) resolve_options = resolve.pop diff --git a/config/initializers/wicked_pdf.rb b/config/initializers/wicked_pdf.rb index 824095dc3..37820d285 100644 --- a/config/initializers/wicked_pdf.rb +++ b/config/initializers/wicked_pdf.rb @@ -1,3 +1,27 @@ +class WickedPdf + # Wicked Pdf magic breaks ViewComponent + # https://github.com/mileszs/wicked_pdf/pull/925 + module PdfHelper + def render(*args) + options = args.first + if options.is_a?(Hash) && options.key?(:pdf) + render_with_wicked_pdf(options) + else + super + end + end + + def render_to_string(*args) + options = args.first + if options.is_a?(Hash) && options.key?(:pdf) + render_to_string_with_wicked_pdf(options) + else + super + end + end + end +end + # WickedPDF Global Configuration # # Use this to set up shared configuration options for your entire application. diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 2ec0222ef..a7960eee4 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -72,10 +72,6 @@ en: budget_investments: Manage projects table_name: Name table_phase: Phase - table_investments: Investments - table_edit_groups: Headings groups - table_edit_budget: Edit - table_admin_ballots: Ballots edit_groups: Edit headings groups edit_budget: Edit budget admin_ballots: Admin ballots @@ -117,7 +113,6 @@ en: budget_groups: name: "Name" headings_name: "Headings" - headings_edit: "Edit Headings" headings_manage: "Manage headings" no_groups: "There are no groups." amount: @@ -297,8 +292,6 @@ en: table_name: Name table_description: Description table_actions: Actions - delete: Delete - edit: Edit edit: title: Edit milestone status update: @@ -361,8 +354,6 @@ en: index: description: "When users create proposals they can access a dashboard of their proposal, where you can propose resources and recommendations to get support for their idea." create: Create resource or action - edit: Edit - delete: Delete active: 'Yes' inactive: 'No' title: Resources and actions @@ -497,7 +488,6 @@ en: banner_title: Header colors index: create: New process - delete: Delete title: Collaborative legislation filters: active: Active @@ -629,7 +619,6 @@ en: no_managers: There are no managers. manager: add: Add - delete: Delete search: title: "Managers: User search" menu: @@ -709,7 +698,6 @@ en: no_administrators: There are no administrators. administrator: add: Add - delete: Delete restricted_removal: "Sorry, you can't remove yourself from the administrators" search: title: "Administrators: User search" @@ -724,7 +712,6 @@ en: no_moderators: There are no moderators. moderator: add: Add - delete: Delete search: title: "Moderators: User search" segment_recipient: @@ -751,8 +738,6 @@ en: sent: Sent actions: Actions draft: Draft - edit: Edit - delete: Delete preview: Preview empty_newsletters: There are no newsletters to show new: @@ -788,8 +773,6 @@ en: sent: Sent actions: Actions draft: Draft - edit: Edit - delete: Delete preview: Preview view: View empty_notifications: There are no notifications to show @@ -887,7 +870,6 @@ en: can_edit_dossier: "Can edit dossier" valuator: add: Add to valuators - delete: Delete search: title: "Valuators: User search" form: @@ -1301,7 +1283,6 @@ en: author: Author content: Content created_at: Created at - delete: Delete color_help: Hexadecimal format show_results_and_stats: "Show results and stats" results_and_stats_reminder: "Marking these checkboxes the results and/or stats will be publicly available and every user will see them." @@ -1309,8 +1290,6 @@ en: index: title: Geozone create: Create geozone - edit: Edit - delete: Delete geozone: name: Name external_code: External code diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 6323c3b74..586cc1b70 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -72,10 +72,6 @@ es: budget_investments: Gestionar proyectos de gasto table_name: Nombre table_phase: Fase - table_investments: Proyectos de gasto - table_edit_groups: Grupos de partidas - table_edit_budget: Editar - table_admin_ballots: Urnas edit_groups: Editar grupos de partidas edit_budget: Editar presupuesto admin_ballots: Gestionar urnas @@ -117,7 +113,6 @@ es: budget_groups: name: "Nombre" headings_name: "Partidas" - headings_edit: "Editar Partidas" headings_manage: "Gestionar partidas" no_groups: "No hay grupos." amount: @@ -297,8 +292,6 @@ es: table_name: Nombre table_description: Descripción table_actions: Acciones - delete: Borrar - edit: Editar edit: title: Editar estado de seguimiento update: @@ -361,8 +354,6 @@ es: index: description: "Cuando los usuarios crean propuestas pueden acceder a un panel de progreso de su propuesta, donde se le puede proponer recursos y recomendaciones para conseguir apoyos a su idea." create: Crear recurso o acción - edit: Editar - delete: Borrar active: 'Si' inactive: 'No' title: Recursos y acciones @@ -497,7 +488,6 @@ es: banner_title: Colores del encabezado index: create: Nuevo proceso - delete: Borrar title: Procesos de legislación colaborativa filters: active: Activos @@ -628,7 +618,6 @@ es: no_managers: No hay gestores. manager: add: Añadir como gestor - delete: Borrar search: title: "Gestores: Búsqueda de usuarios" menu: @@ -708,7 +697,6 @@ es: no_administrators: No hay administradores. administrator: add: Añadir como Administrador - delete: Borrar restricted_removal: "Lo sentimos, no puedes eliminarte a ti mismo de la lista" search: title: "Administradores: Búsqueda de usuarios" @@ -723,7 +711,6 @@ es: no_moderators: No hay moderadores. moderator: add: Añadir como Moderador - delete: Borrar search: title: "Moderadores: Búsqueda de usuarios" segment_recipient: @@ -750,8 +737,6 @@ es: sent: Enviado actions: Acciones draft: Borrador - edit: Editar - delete: Borrar preview: Previsualizar empty_newsletters: No hay newsletters para mostrar new: @@ -787,8 +772,6 @@ es: sent: Enviado actions: Acciones draft: Borrador - edit: Editar - delete: Borrar preview: Previsualizar view: Visualizar empty_notifications: No hay notificaciones para mostrar @@ -886,7 +869,6 @@ es: can_edit_dossier: "Puede editar informes" valuator: add: Añadir como evaluador - delete: Borrar search: title: "Evaluadores: Búsqueda de usuarios" form: @@ -1300,7 +1282,6 @@ es: author: Autor content: Contenido created_at: Fecha de creación - delete: Eliminar color_help: Formato hexadecimal show_results_and_stats: "Mostrar resultados y estadísticas" results_and_stats_reminder: "Si marcas estas casillas los resultados y/o estadísticas serán públicos y podrán verlos todos los usuarios." @@ -1308,8 +1289,6 @@ es: index: title: Zonas create: Crear una zona - edit: Editar - delete: Borrar geozone: name: Nombre external_code: Código externo diff --git a/config/routes/admin.rb b/config/routes/admin.rb index a71c32ba2..5121fec3b 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -278,6 +278,14 @@ resolve "Poll::Booth" do |booth, options| [:booth, options.merge(id: booth)] end +resolve "Poll::BoothAssignment" do |assignment, options| + [assignment.poll, :booth_assignment, options.merge(id: assignment)] +end + +resolve "Poll::Shift" do |shift, options| + [:booth, :shift, options.merge(booth_id: shift.booth, id: shift)] +end + resolve "Poll::Officer" do |officer, options| [:officer, options.merge(id: officer)] end diff --git a/spec/components/admin/budgets/table_actions_component_spec.rb b/spec/components/admin/budgets/table_actions_component_spec.rb new file mode 100644 index 000000000..05312853c --- /dev/null +++ b/spec/components/admin/budgets/table_actions_component_spec.rb @@ -0,0 +1,30 @@ +require "rails_helper" + +describe Admin::Budgets::TableActionsComponent, type: :component do + let(:budget) { create(:budget) } + let(:component) { Admin::Budgets::TableActionsComponent.new(budget) } + + it "renders links to edit budget, manage investments and edit groups and manage ballots" do + render_inline component + + expect(page).to have_css "a", count: 4 + expect(page).to have_link "Manage projects", href: /investments/ + expect(page).to have_link "Edit headings groups", href: /groups/ + expect(page).to have_link "Edit budget", href: /edit/ + expect(page).to have_link "Admin ballots" + end + + it "renders link to create new poll for budgets without polls" do + render_inline component + + expect(page).to have_css "a[href*='polls'][data-method='post']", text: "Admin ballots" + end + + it "renders link to manage ballots for budgets with polls" do + budget.poll = create(:poll, budget: budget) + + render_inline component + + expect(page).to have_link "Admin ballots", href: /booth_assignments/ + end +end diff --git a/spec/components/admin/hidden_table_actions_component_spec.rb b/spec/components/admin/hidden_table_actions_component_spec.rb new file mode 100644 index 000000000..f439cf06c --- /dev/null +++ b/spec/components/admin/hidden_table_actions_component_spec.rb @@ -0,0 +1,14 @@ +require "rails_helper" + +describe Admin::HiddenTableActionsComponent, type: :component do + let(:record) { create(:user) } + let(:component) { Admin::HiddenTableActionsComponent.new(record) } + + it "renders links to restore and confirm hide" do + render_inline component + + expect(page).to have_css "a", count: 2 + expect(page).to have_css "a[href*='restore'][data-method='put']", text: "Restore" + expect(page).to have_css "a[href*='confirm_hide'][data-method='put']", text: "Confirm moderation" + end +end diff --git a/spec/components/admin/organizations/table_actions_component_spec.rb b/spec/components/admin/organizations/table_actions_component_spec.rb new file mode 100644 index 000000000..66ab51cf2 --- /dev/null +++ b/spec/components/admin/organizations/table_actions_component_spec.rb @@ -0,0 +1,46 @@ +require "rails_helper" + +describe Admin::Organizations::TableActionsComponent, type: :component do + let(:organization) { create(:organization) } + let(:component) { Admin::Organizations::TableActionsComponent.new(organization) } + + it "renders links to verify and reject when it can" do + allow(component).to receive(:can_verify?).and_return(true) + allow(component).to receive(:can_reject?).and_return(true) + + render_inline component + + expect(page).to have_css "a", count: 2 + expect(page).to have_css "a[href*='verify'][data-method='put']", text: "Verify" + expect(page).to have_css "a[href*='reject'][data-method='put']", text: "Reject" + end + + it "renders link to verify when it cannot reject" do + allow(component).to receive(:can_verify?).and_return(true) + allow(component).to receive(:can_reject?).and_return(false) + + render_inline component + + expect(page).to have_css "a", count: 1 + expect(page).to have_link "Verify" + end + + it "renders link to reject when it cannot verify" do + allow(component).to receive(:can_verify?).and_return(false) + allow(component).to receive(:can_reject?).and_return(true) + + render_inline component + + expect(page).to have_css "a", count: 1 + expect(page).to have_link "Reject" + end + + it "does not render any actions when it cannot verify nor reject" do + allow(component).to receive(:can_verify?).and_return(false) + allow(component).to receive(:can_reject?).and_return(false) + + render_inline component + + expect(page).not_to have_css "a" + end +end diff --git a/spec/components/admin/poll/officers/officers_component_spec.rb b/spec/components/admin/poll/officers/officers_component_spec.rb new file mode 100644 index 000000000..5d8e9a79a --- /dev/null +++ b/spec/components/admin/poll/officers/officers_component_spec.rb @@ -0,0 +1,35 @@ +require "rails_helper" + +describe Admin::Poll::Officers::OfficersComponent, type: :component do + let(:existing_officer) { create(:poll_officer, name: "Old officer") } + let(:new_officer) { build(:poll_officer, name: "New officer") } + let(:officers) { [existing_officer, new_officer] } + let(:component) { Admin::Poll::Officers::OfficersComponent.new(officers) } + + it "renders as many rows as officers" do + within "tbody" do + expect(page).to have_css "tr", count: 2 + expect(page).to have_css "a", count: 2 + end + end + + it "renders link to destroy for existing officers" do + render_inline component + row = page.find("tr", text: "Old officer") + + expect(row).to have_css "a[data-method='delete']", text: "Delete" + end + + it "renders link to add for new officers" do + render_inline component + row = page.find("tr", text: "New officer") + + expect(row).to have_css "a[data-method='post']", text: "Add" + end + + it "accepts table options" do + render_inline Admin::Poll::Officers::OfficersComponent.new(officers, class: "my-officers-table") + + expect(page).to have_css "table.my-officers-table" + end +end diff --git a/spec/components/admin/roles/table_actions_component_spec.rb b/spec/components/admin/roles/table_actions_component_spec.rb new file mode 100644 index 000000000..42382cf8b --- /dev/null +++ b/spec/components/admin/roles/table_actions_component_spec.rb @@ -0,0 +1,17 @@ +require "rails_helper" + +describe Admin::Roles::TableActionsComponent, type: :component do + let(:user) { create(:user) } + + it "renders link to add the role for new records" do + render_inline Admin::Roles::TableActionsComponent.new(user.build_manager) + + expect(page).to have_css "a[data-method='post']", text: "Add" + end + + it "renders link to remove the role for existing records" do + render_inline Admin::Roles::TableActionsComponent.new(create(:manager, user: user)) + + expect(page).to have_css "a[data-method='delete']", text: "Delete" + end +end diff --git a/spec/components/admin/table_actions_component_spec.rb b/spec/components/admin/table_actions_component_spec.rb new file mode 100644 index 000000000..c4630c645 --- /dev/null +++ b/spec/components/admin/table_actions_component_spec.rb @@ -0,0 +1,68 @@ +require "rails_helper" + +describe Admin::TableActionsComponent, type: :component do + let(:record) { create(:banner) } + + it "renders links to edit and destroy a record by default" do + render_inline Admin::TableActionsComponent.new(record) + + expect(page).to have_css "a", count: 2 + expect(page).to have_css "a[href*='edit']", text: "Edit" + expect(page).to have_css "a[data-method='delete']", text: "Delete" + end + + context "actions parameter is passed" do + it "renders a link to edit a record if passed" do + render_inline Admin::TableActionsComponent.new(record, actions: [:edit]) + + expect(page).to have_link "Edit" + expect(page).not_to have_link "Delete" + end + + it "renders a link to destroy a record if passed" do + render_inline Admin::TableActionsComponent.new(record, actions: [:destroy]) + + expect(page).to have_link "Delete" + expect(page).not_to have_link "Edit" + end + end + + it "allows custom texts for actions" do + render_inline Admin::TableActionsComponent.new(record, edit_text: "change", destroy_text: "annihilate") + + expect(page).to have_link "annihilate" + expect(page).to have_link "change" + expect(page).not_to have_link "Delete" + expect(page).not_to have_link "Edit" + end + + it "allows custom URLs" do + render_inline Admin::TableActionsComponent.new(edit_path: "/myedit", destroy_path: "/mydestroy") + + expect(page).to have_link "Edit", href: "/myedit" + expect(page).to have_link "Delete", href: "/mydestroy" + end + + it "allows custom confirmation text" do + render_inline Admin::TableActionsComponent.new(record, destroy_confirmation: "Are you mad? Be careful!") + + expect(page).to have_css "a[data-confirm='Are you mad? Be careful!']" + end + + it "allows custom options" do + render_inline Admin::TableActionsComponent.new(record, edit_options: { id: "edit_me" }) + + expect(page).to have_css "a#edit_me" + end + + it "allows custom content" do + render_inline Admin::TableActionsComponent.new(record) do + "Main".html_safe + end + + expect(page).to have_css "a", count: 3 + expect(page).to have_link "Main", href: "/" + expect(page).to have_link "Edit" + expect(page).to have_link "Delete" + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c4756dd02..717007659 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -11,6 +11,11 @@ require "spec_helper" require "capybara/rails" require "capybara/rspec" require "selenium/webdriver" +require "view_component/test_helpers" + +RSpec.configure do |config| + config.include ViewComponent::TestHelpers, type: :component +end Rails.application.load_tasks if Rake::Task.tasks.empty? diff --git a/spec/routing/polymorphic_routes_spec.rb b/spec/routing/polymorphic_routes_spec.rb index 778f089c6..8ab22512b 100644 --- a/spec/routing/polymorphic_routes_spec.rb +++ b/spec/routing/polymorphic_routes_spec.rb @@ -148,6 +148,22 @@ describe "Polymorphic routes" do ) end + it "routes booth assignments" do + poll = create(:poll) + assignment = create(:poll_booth_assignment, poll: poll) + + expect(admin_polymorphic_path(assignment)).to eq( + admin_poll_booth_assignment_path(poll, assignment) + ) + end + + it "routes poll shifts" do + booth = create(:poll_booth) + shift = create(:poll_shift, booth: booth) + + expect(admin_polymorphic_path(shift)).to eq(admin_booth_shift_path(booth, shift)) + end + it "supports routes for actions like edit" do proposal = create(:proposal) milestone = create(:milestone, milestoneable: proposal) diff --git a/spec/system/admin/budget_groups_spec.rb b/spec/system/admin/budget_groups_spec.rb index 6026ea187..75c05e1b9 100644 --- a/spec/system/admin/budget_groups_spec.rb +++ b/spec/system/admin/budget_groups_spec.rb @@ -128,7 +128,7 @@ describe "Admin budget groups" do click_button "Create new group" expect(page).to have_content "Group created successfully!" - expect(page).to have_link "All City" + expect(page).to have_content "All City" end scenario "Maximum number of headings in which a user can vote is set to 1 by default" do diff --git a/spec/system/admin/budget_headings_spec.rb b/spec/system/admin/budget_headings_spec.rb index b92d4ce6e..397b39968 100644 --- a/spec/system/admin/budget_headings_spec.rb +++ b/spec/system/admin/budget_headings_spec.rb @@ -148,7 +148,7 @@ describe "Admin budget headings" do click_button "Create new heading" expect(page).to have_content "Heading created successfully!" - expect(page).to have_link "All City" + expect(page).to have_content "All City" expect(page).to have_content "€1,000" expect(page).to have_content "10000" expect(page).to have_content "Yes" diff --git a/spec/system/admin/officials_spec.rb b/spec/system/admin/officials_spec.rb index 3c5abd448..a9eaab1f5 100644 --- a/spec/system/admin/officials_spec.rb +++ b/spec/system/admin/officials_spec.rb @@ -19,7 +19,7 @@ describe "Admin officials" do scenario "Edit an official" do visit admin_officials_path - click_link official.name + click_link "Edit official" expect(page).to have_current_path(edit_admin_official_path(official)) diff --git a/spec/system/admin/poll/booth_assigments_spec.rb b/spec/system/admin/poll/booth_assigments_spec.rb index 7ee942b05..ebfb38695 100644 --- a/spec/system/admin/poll/booth_assigments_spec.rb +++ b/spec/system/admin/poll/booth_assigments_spec.rb @@ -16,7 +16,7 @@ describe "Admin booths assignments" do visit booth_assignments_admin_polls_path - expect(page).to have_link(poll.name, href: manage_admin_poll_booth_assignments_path(poll)) + expect(page).to have_link("Manage assignments", href: manage_admin_poll_booth_assignments_path(poll)) expect(page).to have_content(second_poll.name) within("#poll_#{second_poll.id}") do diff --git a/spec/system/admin/poll/polls_spec.rb b/spec/system/admin/poll/polls_spec.rb index 8703dd4e2..d7a2fbc21 100644 --- a/spec/system/admin/poll/polls_spec.rb +++ b/spec/system/admin/poll/polls_spec.rb @@ -58,7 +58,7 @@ describe "Admin polls" do poll = create(:poll) visit admin_polls_path - click_link poll.name + click_link "Configure" expect(page).to have_content poll.name end diff --git a/spec/system/admin/poll/questions_spec.rb b/spec/system/admin/poll/questions_spec.rb index dde70b676..3863cf676 100644 --- a/spec/system/admin/poll/questions_spec.rb +++ b/spec/system/admin/poll/questions_spec.rb @@ -52,7 +52,7 @@ describe "Admin poll questions" do question = create(:poll_question, poll: poll) visit admin_poll_path(poll) - click_link question.title + click_link "Edit answers" expect(page).to have_content(question.title) expect(page).to have_content(question.author.name)