Merge pull request #5276 from consuldemocracy/order-cards

Allow sorting homepage cards
This commit is contained in:
Sebastia
2024-03-22 10:56:33 +01:00
committed by GitHub
23 changed files with 143 additions and 20 deletions

View File

@@ -11,7 +11,7 @@ class Admin::Widget::Cards::EditComponent < ApplicationComponent
private
def title
if card.header?
if card.header_or_sdg_header?
t("admin.homepage.edit.header_title")
else
t("admin.homepage.edit.card_title")

View File

@@ -11,7 +11,7 @@ class Admin::Widget::Cards::NewComponent < ApplicationComponent
private
def title
if card.header?
if card.header_or_sdg_header?
t("admin.homepage.new.header_title")
else
t("admin.homepage.new.card_title")

View File

@@ -9,6 +9,12 @@
<%= card.link_url %>
</td>
<% unless header_section? %>
<td>
<%= card.order %>
</td>
<% end %>
<!-- remove conditional once specs have image validations -->
<td>
<% if card.image.present? %>

View File

@@ -5,4 +5,10 @@ class Admin::Widget::Cards::RowComponent < ApplicationComponent
@card = card
@options = options
end
private
def header_section?
card.header_or_sdg_header?
end
end

View File

@@ -5,6 +5,9 @@
<th><%= attribute_name(:title) %></th>
<th class="small-4"><%= attribute_name(:description) %></th>
<th><%= attribute_name(:link_text) %> / <%= attribute_name(:link_url) %></th>
<% unless header_section? %>
<th><%= attribute_name(:order) %></th>
<% end %>
<th><%= t("admin.shared.image") %></th>
<th><%= t("admin.shared.actions") %></th>
</tr>

View File

@@ -12,4 +12,8 @@ class Admin::Widget::Cards::TableComponent < ApplicationComponent
def attribute_name(attribute)
::Widget::Card.human_attribute_name(attribute)
end
def header_section?
cards.first.header_or_sdg_header?
end
end

View File

@@ -19,7 +19,7 @@
<h2 class="title"><%= phase.title %></h2>
</header>
<%= render "shared/cards", cards: phase.cards %>
<%= render "shared/cards", cards: phase.cards.sort_by_order %>
</section>
<% end %>
</main>

View File

@@ -45,7 +45,7 @@ module Admin::Widget::CardsActions
def allowed_params
[
:link_url, :button_text, :button_url, :alignment, :header, :columns,
:link_url, :button_text, :button_url, :alignment, :header, :columns, :order,
translation_params(Widget::Card),
image_attributes: image_attributes
]

View File

@@ -8,7 +8,7 @@ class PagesController < ApplicationController
@custom_page = SiteCustomization::Page.published.find_by(slug: params[:id])
if @custom_page.present?
@cards = @custom_page.cards
@cards = @custom_page.cards.sort_by_order
render action: :custom_page
else
render action: params[:id].split(".").first

View File

@@ -10,12 +10,23 @@ class Widget::Card < ApplicationRecord
validates_translation :title, presence: true
validates :link_url, presence: true, if: -> { !header? || link_text.present? }
validates :order, numericality: { greater_than_or_equal_to: 1 }
scope :sort_by_order, -> { order(:order, :created_at) }
def self.header
where(header: true)
end
def self.body
where(header: false, cardable_id: nil).order(:created_at)
where(header: false, cardable_id: nil).sort_by_order
end
def header_or_sdg_header?
header? || sdg_header?
end
def sdg_header?
cardable == WebSection.find_by!(name: "sdg")
end
end

View File

@@ -30,13 +30,13 @@
</div>
<div class="row">
<% unless card.header? %>
<div class="column">
<%= f.label :columns %>
<p class="help-text"><%= t("admin.site_customization.pages.cards.columns_help") %></p>
<div class="small-12 medium-4 large-2">
<%= f.select :columns, (1..12), label: false %>
<% unless card.header_or_sdg_header? %>
<div class="small-12 medium-6 column">
<%= f.select :columns, (1..12), hint: t("admin.site_customization.pages.cards.columns_help") %>
</div>
<div class="small-12 medium-6 column">
<%= f.number_field :order, min: 1, hint: t("admin.site_customization.pages.cards.order_help") %>
</div>
<% end %>
</div>
@@ -50,7 +50,7 @@
</div>
<div class="column">
<%= f.submit(
t("admin.homepage.#{admin_submit_action(card)}.#{card.header? ? "submit_header" : "submit_card"}"),
t("admin.homepage.#{admin_submit_action(card)}.#{card.header_or_sdg_header? ? "submit_header" : "submit_card"}"),
class: "button success"
) %>
</div>

View File

@@ -488,6 +488,7 @@ en:
link_text: Link text
link_url: Link URL
columns: Number of columns
order: Position
widget/card/translation:
label: Label (optional)
title: Title

View File

@@ -1650,6 +1650,7 @@ en:
create_card: Create card
no_cards: There are no cards.
columns_help: "Width of the card in number of columns. On mobile screens it's always a width of 100%."
order_help: "You can enter the position where this card will be shown."
create:
notice: "Card created successfully!"
update:

View File

@@ -488,6 +488,7 @@ es:
link_text: Texto del enlace
link_url: URL del enlace
columns: Número de columnas
order: Posición
widget/card/translation:
label: Etiqueta (opcional)
title: Título

View File

@@ -1650,6 +1650,7 @@ es:
create_card: Crear tarjeta
no_cards: No hay tarjetas.
columns_help: "Ancho de la tarjeta en número de columnas. En pantallas móviles siempre es un ancho del 100%."
order_help: "Puedes introducir la posición en la que se mostrará esta tarjeta."
create:
notice: "¡Tarjeta creada con éxito!"
update:

View File

@@ -0,0 +1,5 @@
class AddOrderToWidgetCards < ActiveRecord::Migration[6.1]
def change
add_column :widget_cards, :order, :integer, null: false, default: 1
end
end

View File

@@ -1768,6 +1768,7 @@ ActiveRecord::Schema.define(version: 2023_10_12_141318) do
t.integer "cardable_id"
t.integer "columns", default: 4
t.string "cardable_type", default: "SiteCustomization::Page"
t.integer "order", default: 1, null: false
t.index ["cardable_id"], name: "index_widget_cards_on_cardable_id"
end

View File

@@ -35,4 +35,28 @@ describe SDG::Goals::IndexComponent do
expect(page).to have_content "Planning"
expect(page).to have_content "Monitoring"
end
describe "Cards are ordered" do
scenario "by order field" do
create(:widget_card, cardable: SDG::Phase["planning"], title: "Card One", order: 3)
create(:widget_card, cardable: SDG::Phase["planning"], title: "Card Two", order: 2)
create(:widget_card, cardable: SDG::Phase["planning"], title: "Card Three", order: 1)
render_inline component
expect("Card Three").to appear_before("Card Two")
expect("Card Two").to appear_before("Card One")
end
scenario "by created_at with cards have same order" do
create(:widget_card, cardable: SDG::Phase["planning"], title: "Card One", order: 1)
create(:widget_card, cardable: SDG::Phase["planning"], title: "Card Two", order: 1)
create(:widget_card, cardable: SDG::Phase["planning"], title: "Card Three", order: 1)
render_inline component
expect("Card One").to appear_before("Card Two")
expect("Card Two").to appear_before("Card Three")
end
end
end

View File

@@ -18,6 +18,16 @@ describe Widget::Card do
expect(build(:widget_card, title: "")).not_to be_valid
end
describe "order" do
it "is not valid without an order" do
expect(build(:widget_card, order: nil)).not_to be_valid
end
it "is not valid with an order less than 1" do
expect(build(:widget_card, order: 0)).not_to be_valid
end
end
context "regular cards" do
it "is not valid without a link_url" do
card = build(:widget_card, header: false, link_url: nil)
@@ -76,5 +86,14 @@ describe Widget::Card do
expect(Widget::Card.body).not_to include(header)
expect(Widget::Card.body).not_to include(page_card)
end
it "returns cards sorted by defined order, then by 'created_at' when order is equal" do
card1 = create(:widget_card, order: 1)
card2 = create(:widget_card, order: 3)
card3 = create(:widget_card, order: 2)
card4 = create(:widget_card, order: 3)
expect(Widget::Card.body).to eq [card1, card3, card2, card4]
end
end
end

View File

@@ -11,7 +11,8 @@ describe "Cards", :admin do
fill_in "Title", with: "Card text"
fill_in "Description", with: "Card description"
fill_in "Link text", with: "Link text"
fill_in "widget_card_link_url", with: "consul.dev"
fill_in "Link URL", with: "consul.dev"
fill_in "Position", with: "12"
attach_image_to_card
click_button "Create card"
@@ -25,6 +26,7 @@ describe "Cards", :admin do
expect(page).to have_content "Card description"
expect(page).to have_content "Link text"
expect(page).to have_content "consul.dev"
expect(page).to have_css "td", exact_text: "12"
expect(page).to have_link "Show image", title: "clippy.jpg"
end
end
@@ -87,7 +89,8 @@ describe "Cards", :admin do
fill_in "Link text", with: "Link text updated"
end
fill_in "widget_card_link_url", with: "consul.dev updated"
fill_in "Link URL", with: "consul.dev updated"
fill_in "Position", with: "2"
click_button "Save card"
expect(page).to have_content "Card updated successfully"
@@ -101,6 +104,7 @@ describe "Cards", :admin do
expect(page).to have_content "Card description updated"
expect(page).to have_content "Link text updated"
expect(page).to have_content "consul.dev updated"
expect(page).to have_css "td", exact_text: "2"
end
end
end
@@ -125,6 +129,8 @@ describe "Cards", :admin do
visit admin_homepage_path
click_link "Create header"
expect(page).not_to have_field "Position"
fill_in "Label (optional)", with: "Header label"
fill_in "Title", with: "Header text"
fill_in "Description", with: "Header description"
@@ -136,6 +142,7 @@ describe "Cards", :admin do
within("#header") do
expect(page).to have_css(".homepage-card", count: 1)
expect(page).not_to have_css "th", exact_text: "Position"
expect(page).to have_content "Header label"
expect(page).to have_content "Header text"
expect(page).to have_content "Header description"
@@ -174,10 +181,13 @@ describe "Cards", :admin do
fill_in "Title", with: "Card for a custom page"
fill_in "Link URL", with: "/any_path"
fill_in "Position", with: "12"
click_button "Create card"
expect(page).to have_current_path admin_site_customization_page_widget_cards_path(custom_page)
expect(page).to have_content "Card for a custom page"
expect(page).to have_content "12"
expect(page).to have_css "th", exact_text: "Position"
end
scenario "Show" do
@@ -239,12 +249,14 @@ describe "Cards", :admin do
within(".translatable-fields") do
fill_in "Title", with: "Updated title"
end
fill_in "Position", with: "2"
click_button "Save card"
expect(page).to have_current_path admin_site_customization_page_widget_cards_path(custom_page)
expect(page).to have_content "Updated title"
expect(page).not_to have_content "Original title"
expect(page).to have_css "td", exact_text: "2"
end
scenario "Destroy" do

View File

@@ -143,6 +143,21 @@ describe "Home" do
expect(page).not_to have_css(".title", text: "Featured")
end
scenario "cards are first sorted by 'order' field, then by 'created_at' when order is equal" do
create(:widget_card, title: "Card one", order: 1)
create(:widget_card, title: "Card two", order: 3)
create(:widget_card, title: "Card three", order: 2)
create(:widget_card, title: "Card four", order: 3)
visit root_path
within(".cards-container") do
expect("CARD ONE").to appear_before("CARD THREE")
expect("CARD THREE").to appear_before("CARD TWO")
expect("CARD TWO").to appear_before("CARD FOUR")
end
end
describe "Header Card" do
scenario "if there is header card with link, the link content is rendered" do
create(:widget_card, :header, link_text: "Link text", link_url: "consul.dev")

View File

@@ -21,12 +21,18 @@ describe "SDG homepage configuration" do
visit sdg_management_homepage_path
click_link "Create planning card"
expect(page).to have_field "Number of columns"
expect(page).to have_field "Position"
within(".translatable-fields") { fill_in "Title", with: "My planning card" }
fill_in "Link URL", with: "/any_path"
fill_in "Position", with: "2"
click_button "Create card"
within(".planning-cards") do
expect(page).to have_content "My planning card"
expect(page).to have_css "th", exact_text: "Position"
expect(page).to have_css "td", exact_text: "2"
end
within(".sensitization-cards") do
@@ -54,13 +60,17 @@ describe "SDG homepage configuration" do
visit sdg_management_homepage_path
click_link "Create header"
expect(page).not_to have_field "Number of columns"
expect(page).not_to have_field "Position"
within(".translatable-fields") { fill_in "Title", with: "My header" }
fill_in "Link URL", with: "/any_path"
click_button "Create card"
click_button "Create header"
within(".sdg-header") do
expect(page).to have_content "My header"
expect(page).not_to have_content "Create header"
expect(page).not_to have_css "th", exact_text: "Position"
end
end
@@ -72,7 +82,7 @@ describe "SDG homepage configuration" do
end
within(".translatable-fields") { fill_in "Title", with: "My header update" }
click_button "Save card"
click_button "Save header"
expect(page).to have_content "My header update"
end

View File

@@ -94,11 +94,14 @@ describe "Custom Pages" do
scenario "Show widget cards for that page" do
custom_page = create(:site_customization_page, :published)
create(:widget_card, cardable: custom_page, title: "Card Highlights")
create(:widget_card, cardable: custom_page, title: "Medium prominent card", order: 2)
create(:widget_card, cardable: custom_page, title: "Less prominent card", order: 2)
create(:widget_card, cardable: custom_page, title: "Card Highlights", order: 1)
visit custom_page.url
expect(page).to have_content "CARD HIGHLIGHTS"
expect("CARD HIGHLIGHTS").to appear_before("MEDIUM PROMINENT CARD")
expect("MEDIUM PROMINENT CARD").to appear_before("LESS PROMINENT CARD")
end
end
end