class RailsAiAdmin::Forms::Plan
Presentation-only snapshots; callers supply currently authorized fields. No record, denied value, query or persistence lives in this plan.
Constants
- Entry
- MAX_BYTES
- MAX_FIELDS
- MAX_PANELS
- MAX_TABS
- MAX_VALUE_BYTES
- Panel
- Tab
Attributes
Public Class Methods
Source
# File lib/rails_ai_admin/forms/plan.rb, line 18 def initialize(fields:, values:, readonly_fields: [], readonly_values: {}, order: nil) unless values.is_a?(Hash) && readonly_values.is_a?(Hash) raise ConfigurationError, "Form values must be scalar maps" end writable = fields.reject(&:hidden?).index_by(&:name) readable = readonly_fields.reject(&:hidden?).index_by(&:name).except(*writable.keys) @bytes = 0 @entries = (Array(order) + fields + readonly_fields).uniq(&:name).filter_map do |field| next unless writable.key?(field.name) || readable.key?(field.name) editable = writable.key?(field.name) source = editable ? values : readonly_values value = source.key?(field.name.to_s) ? source[field.name.to_s] : source[field.name] Entry.new(field, editable, scalar(value, type: field.scalar_type)) end.freeze raise ConfigurationError, "Form field bound exceeded" if @entries.size > MAX_FIELDS @tabbed = @entries.any? { |entry| entry.field.options[:tab] } groups = @entries.group_by { |entry| entry.field.options[:tab] || (@tabbed ? "Details" : nil) } raise ConfigurationError, "Form tab bound exceeded" if groups.size > MAX_TABS @tabs = groups.map do |label, entries| panels = entries.group_by { |entry| entry.field.options[:panel] } raise ConfigurationError, "Form panel bound exceeded" if panels.size > MAX_PANELS Tab.new(label, panels.map { |title, items| Panel.new(title, items.freeze) }.freeze) end.freeze @tabbed &&= @tabs.size > 1 freeze end
Public Instance Methods
Source
# File lib/rails_ai_admin/forms/plan.rb, line 83 def json_text(value) JSON.pretty_generate(value) rescue JSON::GeneratorError raise ConfigurationError, "Form JSON values must be finite", cause: nil end
Source
# File lib/rails_ai_admin/forms/plan.rb, line 49 def scalar(value, type: nil) copy = case value when nil, true, false, Integer then value when String then String.new(value).encode(Encoding::UTF_8, invalid: :replace, undef: :replace) when BigDecimal raise ConfigurationError, "Form decimals must be finite" unless value.finite? value when Time, ActiveSupport::TimeWithZone, DateTime then value.to_time.getutc when Date then Date.iso8601(value.iso8601) when Fields::FileValue then value # A references field carries its target keys. when Array if type == :files raise ConfigurationError, "Form files must be file values" unless value.all? { |item| item.is_a?(Fields::FileValue) } value.dup.freeze elsif type == :references raise ConfigurationError, "Form references must be key text" unless value.all? { |item| item.is_a?(String) } value.map { |item| String.new(item).freeze }.freeze else raise ConfigurationError, "Form values require supported scalars" unless type == :json json_text(value) end # A JSON field edits its document as indented text. when Hash, Float raise ConfigurationError, "Form values require supported scalars" unless type == :json json_text(value) else raise ConfigurationError, "Form values require supported scalars" end bytes = JSON.generate(InputSchema.canonical(copy)).bytesize @bytes += bytes raise ConfigurationError, "Form value bound exceeded" if bytes > MAX_VALUE_BYTES || @bytes > MAX_BYTES copy.freeze end
Source
# File lib/rails_ai_admin/forms/plan.rb, line 45 def tabbed? = @tabbed private def scalar(value, type: nil) copy = case value when nil, true, false, Integer then value when String then String.new(value).encode(Encoding::UTF_8, invalid: :replace, undef: :replace) when BigDecimal raise ConfigurationError, "Form decimals must be finite" unless value.finite? value when Time, ActiveSupport::TimeWithZone, DateTime then value.to_time.getutc when Date then Date.iso8601(value.iso8601) when Fields::FileValue then value # A references field carries its target keys. when Array if type == :files raise ConfigurationError, "Form files must be file values" unless value.all? { |item| item.is_a?(Fields::FileValue) } value.dup.freeze elsif type == :references raise ConfigurationError, "Form references must be key text" unless value.all? { |item| item.is_a?(String) } value.map { |item| String.new(item).freeze }.freeze else raise ConfigurationError, "Form values require supported scalars" unless type == :json json_text(value) end # A JSON field edits its document as indented text. when Hash, Float raise ConfigurationError, "Form values require supported scalars" unless type == :json json_text(value) else raise ConfigurationError, "Form values require supported scalars" end bytes = JSON.generate(InputSchema.canonical(copy)).bytesize @bytes += bytes raise ConfigurationError, "Form value bound exceeded" if bytes > MAX_VALUE_BYTES || @bytes > MAX_BYTES copy.freeze end def json_text(value) JSON.pretty_generate(value) rescue JSON::GeneratorError raise ConfigurationError, "Form JSON values must be finite", cause: nil end end