From 05b94156f23ee46469a3b1592944a83d44592679 Mon Sep 17 00:00:00 2001 From: Oleh Fedorenko Date: Thu, 28 Jul 2022 16:56:01 +0000 Subject: [PATCH] Refs #35274 - Add possibility to re-use columns --- .../foreman/selectable_columns/category.rb | 33 ++++++++++++++++--- .../foreman/selectable_columns/storage.rb | 20 ++++++----- .../foreman/selectable_columns/table.rb | 4 +-- .../how_to_create_a_plugin.asciidoc | 6 ++++ 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/app/registries/foreman/selectable_columns/category.rb b/app/registries/foreman/selectable_columns/category.rb index 0c508ad7c235..6a22ae6c8129 100644 --- a/app/registries/foreman/selectable_columns/category.rb +++ b/app/registries/foreman/selectable_columns/category.rb @@ -3,10 +3,12 @@ module SelectableColumns class Category < Array attr_reader :id, :label - def initialize(id, label, default: false) + def initialize(id, label, table, default: false) @id = id @label = label + @table = table @default = default + @columns_to_use = HashWithIndifferentAccess.new super(0) end @@ -14,15 +16,38 @@ def column(key, th:, td:) self << { key: key.to_s, th: th, td: td } end - # This instance is not meant to be updated after it was created by DSL - # Thus, saving once computed keys + def use_column(key, from:) + @columns_to_use[from] ||= [] + @columns_to_use[from] << key.to_s + end + + # This instance can be updated after it was created by DSL, but + # only at the initialization time. + # This method is only for actual runtime usage, + # after the Storage is fully defined/updated. + # Thus, saving once computed result. def keys - @keys ||= map { |c| c[:key] }.sort + @keys ||= columns.map { |c| c[:key] }.sort end def default? @default end + + def columns + self + foreign_columns + end + + private + + # This is meant for actual runtime usage, + # after the categories are fully defined. + # Thus, saving once computed result. + def foreign_columns + @foreign_columns ||= @columns_to_use.keys.map do |category_id| + @table.find { |cat| cat.id == category_id }.select { |col| @columns_to_use[category_id].include?(col[:key]) } + end.flatten + end end end end diff --git a/app/registries/foreman/selectable_columns/storage.rb b/app/registries/foreman/selectable_columns/storage.rb index a4d403618891..6ae9cc14bb0d 100644 --- a/app/registries/foreman/selectable_columns/storage.rb +++ b/app/registries/foreman/selectable_columns/storage.rb @@ -30,7 +30,7 @@ def defined_for(table) { id: category.id, name: category.label, - columns: category.map { |c| { id: c[:key], name: c[:th][:label] } }, + columns: category.columns.map { |c| { id: c[:key], name: c[:th][:label] } }, } end end @@ -39,13 +39,17 @@ def selected_by(user, table) return unless tables[table] selected_keys = user.table_preferences.find_by(name: table)&.columns&.sort - if selected_keys - tables[table].select { |category| (category.keys & selected_keys).any? } - .flatten - .select { |col| selected_keys.include?(col[:key]) } - else - tables[table].select { |category| category.default? }.flatten - end + result = if selected_keys + tables[table].select { |category| (category.keys & selected_keys).any? } + .map(&:columns) + .flatten + .select { |col| selected_keys.include?(col[:key]) } + else + tables[table].select { |category| category.default? } + .map(&:columns) + .flatten + end + result.uniq end end end diff --git a/app/registries/foreman/selectable_columns/table.rb b/app/registries/foreman/selectable_columns/table.rb index 31f9f03d4d93..0f0bf4e4f6ed 100644 --- a/app/registries/foreman/selectable_columns/table.rb +++ b/app/registries/foreman/selectable_columns/table.rb @@ -9,7 +9,7 @@ def initialize(name) end def category(id, label: _('General'), default: false, &block) - category = find_or_create(id.to_sym, label, default) + category = find_or_create(id.to_s, label, default) category.instance_eval(&block) end @@ -18,7 +18,7 @@ def category(id, label: _('General'), default: false, &block) def find_or_create(id, label, default) category = find { |c| c.id == id } unless category - category = Category.new(id, label, default: default) + category = Category.new(id, label, self, default: default) self << category end category diff --git a/developer_docs/how_to_create_a_plugin.asciidoc b/developer_docs/how_to_create_a_plugin.asciidoc index 073c598e8203..91c04e675153 100644 --- a/developer_docs/how_to_create_a_plugin.asciidoc +++ b/developer_docs/how_to_create_a_plugin.asciidoc @@ -468,6 +468,7 @@ selectable_columns :table do }, callback: ->(record) { record.value } } + use_column :key, from :category_id end end ---- @@ -495,6 +496,11 @@ Where for `td`: * `callback`: [Lambda] (Required) A callback that will be used to process data to be shown. * `attr_callbacks`: [Hash] (Optional) Only use if you need to process values for HTML attributes dynamically. +Where for `use_column`: + +* `key`: [Symbol] (Required) Key of the defined column to include in the current category. +* `from`: [Symbol] (Required) ID of the category defining the column to use. Category must be in the same table. + You can also define HTML attributes for `` and `` tags. Some common are listed below, but you can use your own. _Note: all except `:callback`, `:sortable`, `:default_sort`, `:attr_callbacks`