From c9c43d502b94eced31c416f2ac24aabef95e15d7 Mon Sep 17 00:00:00 2001 From: Alan Cornthwaite Date: Thu, 6 Jun 2024 16:31:54 +0930 Subject: [PATCH] Summary table --- Gemfile.lock | 6 +- app/components/concerns/koi/tables/cells.rb | 85 +++++++++++++++++++ app/components/koi/summary_table_component.rb | 7 ++ app/components/koi/table_component.rb | 7 ++ app/components/koi/tables/table_component.rb | 80 +---------------- .../koi/controller/is_admin_controller.rb | 3 +- katalyst-koi.gemspec | 2 +- .../koi/admin_views/admin_views_generator.rb | 21 +---- .../admin_views/templates/show.html.erb.tt | 10 ++- .../tables/cells/attachment_component_spec.rb | 2 +- .../koi/tables/cells/enum_component_spec.rb | 2 +- .../koi/tables/cells/link_component_spec.rb | 2 +- .../koi/admin_views_generator_spec.rb | 12 +-- spec/views/admin/posts/index.html.erb_spec.rb | 2 +- spec/views/admin/posts/show.html.erb_spec.rb | 8 +- 15 files changed, 130 insertions(+), 119 deletions(-) create mode 100644 app/components/concerns/koi/tables/cells.rb create mode 100644 app/components/koi/summary_table_component.rb create mode 100644 app/components/koi/table_component.rb diff --git a/Gemfile.lock b/Gemfile.lock index 2f8ee88c9..d9023dd2c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - katalyst-koi (4.7.3) + katalyst-koi (4.8.0) bcrypt importmap-rails katalyst-content @@ -212,7 +212,7 @@ GEM base64 katalyst-basic-auth (0.5.0) rack - katalyst-content (2.4.0) + katalyst-content (2.4.1) active_storage_validations katalyst-html-attributes katalyst-kpop @@ -231,7 +231,7 @@ GEM katalyst-kpop katalyst-tables view_component - katalyst-tables (3.0.0) + katalyst-tables (3.1.0) katalyst-html-attributes view_component language_server-protocol (3.17.0.3) diff --git a/app/components/concerns/koi/tables/cells.rb b/app/components/concerns/koi/tables/cells.rb new file mode 100644 index 000000000..d12fa190a --- /dev/null +++ b/app/components/concerns/koi/tables/cells.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module Koi + module Tables + module Cells + # Generates a column that links to the record's show page (by default). + # + # @param column [Symbol] the column's name, called as a method on the record + # @param label [String|nil] the label to use for the column header + # @param heading [boolean] if true, data cells will use `th` tags + # @param url [Symbol|String|Proc] arguments for url_For, defaults to the record + # @param link [Hash] options to be passed to the link_to helper + # @param ** [Hash] HTML attributes to be added to column cells + # @param & [Proc] optional block to alter the cell content + # + # If a block is provided, it will be called with the link cell component as an argument. + # @yieldparam cell [Katalyst::Tables::Cells::LinkComponent] the cell component + # + # @return [void] + # + # @example Render a column containing the record's title, linked to its show page + # <% row.link :title %> # => About us + # @example Render a column containing the record's title, linked to its edit page + # <% row.link :title, url: :edit_admin_post_path do |cell| %> + # Edit <%= cell %> + # <% end %> + # # => Edit About us + def link(column, label: nil, heading: false, url: [:admin, record], link: {}, **, &) + with_cell(Tables::Cells::LinkComponent.new( + collection:, row:, column:, record:, label:, heading:, url:, link:, **, + ), &) + end + + # Generates a column from an enum value rendered as a tag. + # The target attribute must be defined as an `enum` in the model. + # + # @param column [Symbol] the column's name, called as a method on the record. + # @param label [String|nil] the label to use for the column header + # @param heading [boolean] if true, data cells will use `th` tags + # @param ** [Hash] HTML attributes to be added to column cells + # @param & [Proc] optional block to wrap the cell content + # + # When rendering an enum value, the component will check for translations + # using the key `active_record.attributes.[model]/[column].[value]`, + # e.g. `active_record.attributes.banner/status.published`. + # + # If a block is provided, it will be called with the cell component as an argument. + # @yieldparam cell [Katalyst::Tables::CellComponent] the cell component + # + # @return [void] + # + # @example Render a generic text column for any value that supports `to_s` + # <% row.enum :status %> + # <%# label => Status %> + # <%# data => Published %> + def enum(column, label: nil, heading: false, **, &) + with_cell(Tables::Cells::EnumComponent.new( + collection:, row:, column:, record:, label:, heading:, **, + ), &) + end + + # Generates a column that renders an ActiveStorage attachment as a downloadable link. + # + # @param column [Symbol] the column's name, called as a method on the record + # @param label [String|nil] the label to use for the column header + # @param heading [boolean] if true, data cells will use `th` tags + # @param variant [Symbol] the variant to use when rendering the image (default :thumb) + # @param ** [Hash] HTML attributes to be added to column cells + # @param & [Proc] optional block to alter the cell content + # + # If a block is provided, it will be called with the attachment cell component as an argument. + # @yieldparam cell [Katalyst::Tables::Cells::AttachmentComponent] the cell component + # + # @return [void] + # + # @example Render a column containing a download link to the record's background image + # <% row.attachment :background %> # => background.png + def attachment(column, label: nil, heading: false, variant: :thumb, **, &) + with_cell(Tables::Cells::AttachmentComponent.new( + collection:, row:, column:, record:, label:, heading:, variant:, **, + ), &) + end + end + end +end diff --git a/app/components/koi/summary_table_component.rb b/app/components/koi/summary_table_component.rb new file mode 100644 index 000000000..4b29b57e9 --- /dev/null +++ b/app/components/koi/summary_table_component.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Koi + class SummaryTableComponent < Katalyst::SummaryTableComponent + include Tables::Cells + end +end diff --git a/app/components/koi/table_component.rb b/app/components/koi/table_component.rb new file mode 100644 index 000000000..ceb96f9f0 --- /dev/null +++ b/app/components/koi/table_component.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Koi + class TableComponent < Katalyst::TableComponent + include Tables::Cells + end +end diff --git a/app/components/koi/tables/table_component.rb b/app/components/koi/tables/table_component.rb index e34f0c066..b3a3f8d0c 100644 --- a/app/components/koi/tables/table_component.rb +++ b/app/components/koi/tables/table_component.rb @@ -1,85 +1,9 @@ # frozen_string_literal: true +# @deprecated prefer Koi::TableComponent module Koi module Tables - class TableComponent < Katalyst::TableComponent - # Generates a column that links to the record's show page (by default). - # - # @param column [Symbol] the column's name, called as a method on the record - # @param label [String|nil] the label to use for the column header - # @param heading [boolean] if true, data cells will use `th` tags - # @param url [Symbol|String|Proc] arguments for url_For, defaults to the record - # @param link [Hash] options to be passed to the link_to helper - # @param ** [Hash] HTML attributes to be added to column cells - # @param & [Proc] optional block to alter the cell content - # - # If a block is provided, it will be called with the link cell component as an argument. - # @yieldparam cell [Katalyst::Tables::Cells::LinkComponent] the cell component - # - # @return [void] - # - # @example Render a column containing the record's title, linked to its show page - # <% row.link :title %> # => About us - # @example Render a column containing the record's title, linked to its edit page - # <% row.link :title, url: :edit_admin_post_path do |cell| %> - # Edit <%= cell %> - # <% end %> - # # => Edit About us - def link(column, label: nil, heading: false, url: [:admin, record], link: {}, **, &) - with_cell(Tables::Cells::LinkComponent.new( - collection:, row:, column:, record:, label:, heading:, url:, link:, **, - ), &) - end - - # Generates a column from an enum value rendered as a tag. - # The target attribute must be defined as an `enum` in the model. - # - # @param column [Symbol] the column's name, called as a method on the record. - # @param label [String|nil] the label to use for the column header - # @param heading [boolean] if true, data cells will use `th` tags - # @param ** [Hash] HTML attributes to be added to column cells - # @param & [Proc] optional block to wrap the cell content - # - # When rendering an enum value, the component will check for translations - # using the key `active_record.attributes.[model]/[column].[value]`, - # e.g. `active_record.attributes.banner/status.published`. - # - # If a block is provided, it will be called with the cell component as an argument. - # @yieldparam cell [Katalyst::Tables::CellComponent] the cell component - # - # @return [void] - # - # @example Render a generic text column for any value that supports `to_s` - # <% row.enum :status %> - # <%# label => Status %> - # <%# data => Published %> - def enum(column, label: nil, heading: false, **, &) - with_cell(Tables::Cells::EnumComponent.new( - collection:, row:, column:, record:, label:, heading:, **, - ), &) - end - - # Generates a column that renders an ActiveStorage attachment as a downloadable link. - # - # @param column [Symbol] the column's name, called as a method on the record - # @param label [String|nil] the label to use for the column header - # @param heading [boolean] if true, data cells will use `th` tags - # @param variant [Symbol] the variant to use when rendering the image (default :thumb) - # @param ** [Hash] HTML attributes to be added to column cells - # @param & [Proc] optional block to alter the cell content - # - # If a block is provided, it will be called with the attachment cell component as an argument. - # @yieldparam cell [Katalyst::Tables::Cells::AttachmentComponent] the cell component - # - # @return [void] - # - # @example Render a column containing a download link to the record's background image - # <% row.attachment :background %> # => background.png - def attachment(column, label: nil, heading: false, variant: :thumb, **, &) - with_cell(Tables::Cells::AttachmentComponent.new( - collection:, row:, column:, record:, label:, heading:, variant:, **, - ), &) - end + class TableComponent < ::Koi::TableComponent end end end diff --git a/app/controllers/concerns/koi/controller/is_admin_controller.rb b/app/controllers/concerns/koi/controller/is_admin_controller.rb index 023cbf79c..40a3eaf96 100644 --- a/app/controllers/concerns/koi/controller/is_admin_controller.rb +++ b/app/controllers/concerns/koi/controller/is_admin_controller.rb @@ -18,7 +18,8 @@ def authenticate_local_admins(value) include ::Pagy::Backend default_form_builder "Koi::FormBuilder" - default_table_component Koi::Tables::TableComponent + default_table_component Koi::TableComponent + default_summary_table_component Koi::SummaryTableComponent helper Katalyst::GOVUK::Formbuilder::Frontend helper Katalyst::Navigation::FrontendHelper diff --git a/katalyst-koi.gemspec b/katalyst-koi.gemspec index 4894711aa..4fb013a0d 100644 --- a/katalyst-koi.gemspec +++ b/katalyst-koi.gemspec @@ -3,7 +3,7 @@ # Describe your gem and declare its dependencies: Gem::Specification.new do |s| s.name = "katalyst-koi" - s.version = "4.7.3" + s.version = "4.8.0" s.authors = ["Katalyst Interactive"] s.email = ["developers@katalyst.com.au"] diff --git a/lib/generators/koi/admin_views/admin_views_generator.rb b/lib/generators/koi/admin_views/admin_views_generator.rb index 619329c4d..582297e79 100644 --- a/lib/generators/koi/admin_views/admin_views_generator.rb +++ b/lib/generators/koi/admin_views/admin_views_generator.rb @@ -51,25 +51,6 @@ def govuk_input_for(attribute) end end - def summary_attribute_for(attribute) - case attribute.type - when :integer - %(<% dl.number :#{attribute.name} %>) - when :boolean - %(<% dl.boolean :#{attribute.name} %>) - when :date - %(<% dl.date :#{attribute.name} %>) - when :datetime - %(<% dl.datetime :#{attribute.name} %>) - when :rich_text - %(<% dl.rich_text :#{attribute.name} %>) - when :attachment - %(<% dl.attachment :#{attribute.name} %>) - else - %(<% dl.text :#{attribute.name} %>) - end - end - def index_attribute_for(attribute) case attribute.type when :integer @@ -89,6 +70,8 @@ def index_attribute_for(attribute) end end + alias_method :summary_attribute_for, :index_attribute_for + def index_attributes attributes end diff --git a/lib/generators/koi/admin_views/templates/show.html.erb.tt b/lib/generators/koi/admin_views/templates/show.html.erb.tt index b95684ffe..7257831cb 100644 --- a/lib/generators/koi/admin_views/templates/show.html.erb.tt +++ b/lib/generators/koi/admin_views/templates/show.html.erb.tt @@ -4,10 +4,14 @@

Summary

-<%%= render Koi::SummaryListComponent.new(model: <%= singular_name %>) do |dl| %> -<%- attributes.each do |attribute| -%> +<%%= summary_table_with(model: <%= singular_name %>) do |row| %> + <%- attributes.each_with_index do |attribute, index| -%> + <%- if index.zero? -%> + <%% row.link :<%= attribute.name %> %> + <%- else -%> <%= summary_attribute_for attribute %> -<%- end -%> + <%- end -%> + <%- end -%> <%% end %>
diff --git a/spec/components/koi/tables/cells/attachment_component_spec.rb b/spec/components/koi/tables/cells/attachment_component_spec.rb index 850b1694b..53e89c8ed 100644 --- a/spec/components/koi/tables/cells/attachment_component_spec.rb +++ b/spec/components/koi/tables/cells/attachment_component_spec.rb @@ -3,7 +3,7 @@ require "rails_helper" RSpec.describe Koi::Tables::Cells::AttachmentComponent do - let(:table) { Koi::Tables::TableComponent.new(collection:) } + let(:table) { Koi::TableComponent.new(collection:) } let(:collection) { create_list(:banner, 1, :with_image) } let(:rendered) { render_inline(table) { |row| row.attachment(:image) } } let(:label) { rendered.at_css("thead th") } diff --git a/spec/components/koi/tables/cells/enum_component_spec.rb b/spec/components/koi/tables/cells/enum_component_spec.rb index b436de788..63228f5ae 100644 --- a/spec/components/koi/tables/cells/enum_component_spec.rb +++ b/spec/components/koi/tables/cells/enum_component_spec.rb @@ -3,7 +3,7 @@ require "rails_helper" RSpec.describe Koi::Tables::Cells::EnumComponent do - let(:table) { Koi::Tables::TableComponent.new(collection:) } + let(:table) { Koi::TableComponent.new(collection:) } let(:collection) { create_list(:banner, 1, status: "published") } let(:rendered) { render_inline(table) { |row, _post| row.enum(:status) } } let(:label) { rendered.at_css("thead th") } diff --git a/spec/components/koi/tables/cells/link_component_spec.rb b/spec/components/koi/tables/cells/link_component_spec.rb index 8730f6bb6..be9e79000 100644 --- a/spec/components/koi/tables/cells/link_component_spec.rb +++ b/spec/components/koi/tables/cells/link_component_spec.rb @@ -3,7 +3,7 @@ require "rails_helper" RSpec.describe Koi::Tables::Cells::LinkComponent do - let(:table) { Koi::Tables::TableComponent.new(collection:) } + let(:table) { Koi::TableComponent.new(collection:) } let(:collection) { create_list(:post, 1) } let(:rendered) { render_inline(table) { |row, _post| row.link(:name) } } let(:label) { rendered.at_css("thead th") } diff --git a/spec/generators/koi/admin_views_generator_spec.rb b/spec/generators/koi/admin_views_generator_spec.rb index 662e82334..68328cb29 100644 --- a/spec/generators/koi/admin_views_generator_spec.rb +++ b/spec/generators/koi/admin_views_generator_spec.rb @@ -39,11 +39,11 @@ end it { is_expected.to contain "

Summary

" } - it { is_expected.to contain "<%= render Koi::SummaryListComponent.new(model: test) do |dl| %>" } - it { is_expected.to contain "<% dl.text :title %>" } - it { is_expected.to contain "<% dl.rich_text :description %>" } - it { is_expected.to contain "<% dl.number :ordinal %>" } - it { is_expected.to contain "<% dl.datetime :archived_at %>" } - it { is_expected.to contain "<% dl.boolean :active %>" } + it { is_expected.to contain "<%= summary_table_with(model: test) do |row| %>" } + it { is_expected.to contain "<% row.link :title %>" } + it { is_expected.to contain "<% row.rich_text :description %>" } + it { is_expected.to contain "<% row.number :ordinal %>" } + it { is_expected.to contain "<% row.datetime :archived_at %>" } + it { is_expected.to contain "<% row.boolean :active %>" } end end diff --git a/spec/views/admin/posts/index.html.erb_spec.rb b/spec/views/admin/posts/index.html.erb_spec.rb index 7f733623c..e8022b66e 100644 --- a/spec/views/admin/posts/index.html.erb_spec.rb +++ b/spec/views/admin/posts/index.html.erb_spec.rb @@ -16,7 +16,7 @@ # Workaround for https://github.com/rspec/rspec-rails/issues/2729 view.lookup_context.prefixes.prepend "admin/posts" - allow(view).to receive(:default_table_component_class).and_return(Koi::Tables::TableComponent) + allow(view).to receive(:default_table_component_class).and_return(Koi::TableComponent) render locals: { collection: } end diff --git a/spec/views/admin/posts/show.html.erb_spec.rb b/spec/views/admin/posts/show.html.erb_spec.rb index a2c98208d..8b19053c9 100644 --- a/spec/views/admin/posts/show.html.erb_spec.rb +++ b/spec/views/admin/posts/show.html.erb_spec.rb @@ -9,8 +9,8 @@ render template: "admin/posts/show", locals: { post: } end - it { expect(rendered).to have_css("dt", text: "Name") } - it { expect(rendered).to have_css("dd", text: post.name) } - it { expect(rendered).to have_css("dt", text: "Title") } - it { expect(rendered).to have_css("dd", text: post.title) } + it { expect(rendered).to have_css("th", text: "Name") } + it { expect(rendered).to have_css("td", text: post.name) } + it { expect(rendered).to have_css("th", text: "Title") } + it { expect(rendered).to have_css("td", text: post.title) } end