Class: LcpRuby::Metadata::PageDefinition
- Inherits:
-
Object
- Object
- LcpRuby::Metadata::PageDefinition
- Defined in:
- lib/lcp_ruby/metadata/page_definition.rb
Constant Summary collapse
- VALID_LAYOUTS =
%i[semantic grid].freeze
Instance Attribute Summary collapse
-
#auto_generated ⇒ Object
readonly
Returns the value of attribute auto_generated.
-
#auto_submit ⇒ Object
readonly
Returns the value of attribute auto_submit.
-
#dialog_config ⇒ Object
readonly
Returns the value of attribute dialog_config.
-
#filter_form_definition ⇒ Object
readonly
Returns the value of attribute filter_form_definition.
-
#index_presenter ⇒ Object
readonly
Returns the value of attribute index_presenter.
-
#layout ⇒ Object
readonly
Returns the value of attribute layout.
-
#model ⇒ Object
readonly
Returns the value of attribute model.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#raw_hash ⇒ Object
readonly
Returns the value of attribute raw_hash.
-
#scope_filter_definitions ⇒ Object
readonly
Returns the value of attribute scope_filter_definitions.
-
#slug ⇒ Object
readonly
Returns the value of attribute slug.
-
#source_path ⇒ Object
Returns the value of attribute source_path.
-
#source_type ⇒ Object
Returns the value of attribute source_type.
-
#title_key ⇒ Object
readonly
Returns the value of attribute title_key.
-
#visible_when ⇒ Object
readonly
Returns the value of attribute visible_when.
-
#zones ⇒ Object
readonly
Returns the value of attribute zones.
Class Method Summary collapse
-
.from_hash(hash) ⇒ Object
Note: signature stays single-positional.
Instance Method Summary collapse
-
#any_zone_gated? ⇒ Boolean
True when at least one zone has a parseable ‘visible_when:` — i.e.
- #auto_generated? ⇒ Boolean
- #composite? ⇒ Boolean
- #dialog_closable? ⇒ Boolean
- #dialog_only? ⇒ Boolean
- #dialog_size ⇒ Object
- #dialog_title_key ⇒ Object
- #form_zone ⇒ Object
- #grid? ⇒ Boolean
- #grid_template_columns ⇒ Object
- #has_below? ⇒ Boolean
- #has_selection? ⇒ Boolean
- #has_sidebar? ⇒ Boolean
- #has_tabs? ⇒ Boolean
- #index_composite? ⇒ Boolean
-
#initialize(attrs = {}) ⇒ PageDefinition
constructor
A new instance of PageDefinition.
- #main_presenter_name ⇒ Object
- #main_zone ⇒ Object
- #master_detail? ⇒ Boolean
- #routable? ⇒ Boolean
- #selection_zone ⇒ Object
- #semantic? ⇒ Boolean
- #standalone? ⇒ Boolean
- #tab_zones ⇒ Object
- #title ⇒ Object
- #zones_for_area(area) ⇒ Object
Constructor Details
#initialize(attrs = {}) ⇒ PageDefinition
Returns a new instance of PageDefinition.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 12 def initialize(attrs = {}) @name = attrs[:name].to_s @model = attrs[:model]&.to_s.presence @slug = attrs[:slug] @dialog_config = HashUtils.stringify_deep(attrs[:dialog_config] || {}) @zones = attrs[:zones] || [] @auto_generated = !!attrs[:auto_generated] @layout = (attrs[:layout] || :semantic).to_sym @title_literal = attrs[:title].presence @title_key = attrs[:title_key]&.to_s @index_presenter = attrs[:index_presenter]&.to_s.presence @raw_hash = attrs[:raw_hash] @filter_form_definition = attrs[:filter_form_definition] || [] @scope_filter_definitions = attrs[:scope_filter_definitions] || [] @auto_submit = attrs.key?(:auto_submit) ? attrs[:auto_submit] : "derive" # Page-level visibility gate. Reuses the same shape as # ZoneDefinition#visible_when. Validated by the boot-time # RuntimeInvariantValidator (AUTH-002/003); the runtime gate # itself ships in v3 (PageAuthorization concern). @visible_when = attrs[:visible_when].is_a?(Hash) ? HashUtils.stringify_deep(attrs[:visible_when]) : nil @source_path = attrs[:source_path] @source_type = attrs[:source_type] validate! end |
Instance Attribute Details
#auto_generated ⇒ Object (readonly)
Returns the value of attribute auto_generated.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def auto_generated @auto_generated end |
#auto_submit ⇒ Object (readonly)
Returns the value of attribute auto_submit.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def auto_submit @auto_submit end |
#dialog_config ⇒ Object (readonly)
Returns the value of attribute dialog_config.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def dialog_config @dialog_config end |
#filter_form_definition ⇒ Object (readonly)
Returns the value of attribute filter_form_definition.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def filter_form_definition @filter_form_definition end |
#index_presenter ⇒ Object (readonly)
Returns the value of attribute index_presenter.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def index_presenter @index_presenter end |
#layout ⇒ Object (readonly)
Returns the value of attribute layout.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def layout @layout end |
#model ⇒ Object (readonly)
Returns the value of attribute model.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def model @model end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def name @name end |
#raw_hash ⇒ Object (readonly)
Returns the value of attribute raw_hash.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def raw_hash @raw_hash end |
#scope_filter_definitions ⇒ Object (readonly)
Returns the value of attribute scope_filter_definitions.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def scope_filter_definitions @scope_filter_definitions end |
#slug ⇒ Object (readonly)
Returns the value of attribute slug.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def slug @slug end |
#source_path ⇒ Object
Returns the value of attribute source_path.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def source_path @source_path end |
#source_type ⇒ Object
Returns the value of attribute source_type.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def source_type @source_type end |
#title_key ⇒ Object (readonly)
Returns the value of attribute title_key.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def title_key @title_key end |
#visible_when ⇒ Object (readonly)
Returns the value of attribute visible_when.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def visible_when @visible_when end |
#zones ⇒ Object (readonly)
Returns the value of attribute zones.
6 7 8 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 6 def zones @zones end |
Class Method Details
.from_hash(hash) ⇒ Object
Note: signature stays single-positional. The loader sets ‘source_path` via `set_source!` after `from_hash` returns; adding a `source_path:` kwarg would collide with Ruby 3’s bare-hash → kwargs conversion when callers pass string-keyed hashes inline (e.g. ‘from_hash(“name” => “x”, …)`). Errors from `FilterFormValidator.validate_shape!` therefore do not embed a file path at boot — page_name is enough to locate the problem; rake `lcp_ruby:validate` and the DB-backed save path do surface source_path through their own re-validation.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 51 def self.from_hash(hash) hash = HashUtils.stringify_deep(hash) # Reject `parameters:` block + enforce filter_form/scope_filters # shape rules before constructing anything downstream. Runs at # loader time when `loader.model_definitions` may be mid-build; # model-aware rules are enforced later from ConfigurationValidator # and Pages::DefinitionValidator via `validate_against_models!`. Pages::FilterFormValidator.validate_shape!(hash, page_name: hash["name"]) zones = (hash["zones"] || []).map { |z| ZoneDefinition.from_hash(z) } new( name: hash["name"], model: hash["model"], slug: hash["slug"], dialog_config: hash["dialog"] || {}, zones: zones, auto_generated: hash["auto_generated"] || false, layout: hash["layout"] || :semantic, title: hash["title"], title_key: hash["title_key"], index_presenter: hash["index_presenter"], raw_hash: hash, filter_form_definition: hash["filter_form"] || [], scope_filter_definitions: hash["scope_filters"] || [], auto_submit: hash.key?("auto_submit") ? hash["auto_submit"] : "derive", visible_when: hash["visible_when"] ) end |
Instance Method Details
#any_zone_gated? ⇒ Boolean
True when at least one zone has a parseable ‘visible_when:` —i.e. the page delegates access control to per-zone gates. Memoized because zones are immutable post-construction; called per-request by `Authorization::PageGate` and at boot by `Authorization::RuntimeInvariantValidator` (AUTH-002 check).
99 100 101 102 103 104 105 106 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 99 def any_zone_gated? return @any_zone_gated if defined?(@any_zone_gated) @any_zone_gated = @zones.any? do |z| z.respond_to?(:visible_when) && z.visible_when && Conditions::Validator.parseable?(z.visible_when) end end |
#auto_generated? ⇒ Boolean
86 87 88 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 86 def auto_generated? @auto_generated end |
#composite? ⇒ Boolean
116 117 118 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 116 def composite? !auto_generated? && zones.size > 1 && !standalone? end |
#dialog_closable? ⇒ Boolean
225 226 227 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 225 def dialog_closable? dialog_config.fetch("closable", true) end |
#dialog_only? ⇒ Boolean
160 161 162 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 160 def dialog_only? !routable? && dialog_config.any? end |
#dialog_size ⇒ Object
221 222 223 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 221 def dialog_size dialog_config["size"] || "medium" end |
#dialog_title_key ⇒ Object
229 230 231 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 229 def dialog_title_key dialog_config["title_key"] end |
#form_zone ⇒ Object
186 187 188 189 190 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 186 def form_zone return @form_zone if defined?(@form_zone) @form_zone = @zones.find(&:form_zone?) end |
#grid? ⇒ Boolean
108 109 110 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 108 def grid? @layout == :grid end |
#grid_template_columns ⇒ Object
206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 206 def grid_template_columns return @grid_template_columns if defined?(@grid_template_columns) @grid_template_columns = if main_w = zones_for_area("main").filter_map(&:width).first = zones_for_area("sidebar").filter_map(&:width).first if main_w || m = main_w || 8 s = || 4 # Master-detail: sidebar is column 1 (left), main is column 2 (right) master_detail? ? "#{s}fr #{m}fr" : "#{m}fr #{s}fr" end end end |
#has_below? ⇒ Boolean
156 157 158 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 156 def has_below? zones_for_area("below").any? end |
#has_selection? ⇒ Boolean
170 171 172 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 170 def has_selection? selection_zone.present? end |
#has_sidebar? ⇒ Boolean
152 153 154 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 152 def zones_for_area("sidebar").any? end |
#has_tabs? ⇒ Boolean
148 149 150 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 148 def has_tabs? tab_zones.any? end |
#index_composite? ⇒ Boolean
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 120 def index_composite? return @index_composite if defined?(@index_composite) # Master-detail pages are always index composites (selection zone is the index) if master_detail? @index_composite = true return @index_composite end presenter = main_zone&.presenter_zone? && LcpRuby.loader.presenter_definitions.dig(main_zone.presenter) @index_composite = composite? && !has_tabs? && presenter && presenter.index_config&.dig("table_columns").present? && !presenter.has_show_sections? end |
#main_presenter_name ⇒ Object
192 193 194 195 196 197 198 199 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 192 def main_presenter_name # For master-detail, the index presenter is the selection zone (sidebar list) if master_detail? selection_zone&.presenter else main_zone&.presenter end end |
#main_zone ⇒ Object
180 181 182 183 184 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 180 def main_zone zones.find { |z| z.presenter_zone? && z.area == "main" } || zones.find(&:presenter_zone?) || zones.first end |
#master_detail? ⇒ Boolean
174 175 176 177 178 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 174 def master_detail? return @master_detail if defined?(@master_detail) @master_detail = has_selection? && !standalone? end |
#routable? ⇒ Boolean
82 83 84 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 82 def routable? slug.present? end |
#selection_zone ⇒ Object
164 165 166 167 168 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 164 def selection_zone return @selection_zone if defined?(@selection_zone) @selection_zone = @zones.find(&:selection?) end |
#semantic? ⇒ Boolean
112 113 114 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 112 def semantic? @layout == :semantic end |
#standalone? ⇒ Boolean
90 91 92 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 90 def standalone? @model.nil? end |
#tab_zones ⇒ Object
144 145 146 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 144 def tab_zones zones_for_area("tabs") end |
#title ⇒ Object
201 202 203 204 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 201 def title I18nLabel.resolve(literal: @title_literal, key: @title_key, fallback: @name.humanize) end |
#zones_for_area(area) ⇒ Object
139 140 141 142 |
# File 'lib/lcp_ruby/metadata/page_definition.rb', line 139 def zones_for_area(area) @zones_by_area ||= zones.group_by(&:area) @zones_by_area.fetch(area.to_s, []) end |