Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e1ce7ce
Refactored ExtraOptionConfigs to BaseConfiguration pattern with Activ…
philayres Apr 2, 2026
462badc
Added source_attribute pattern, ReferenceEntry NamedConfiguration, sp…
philayres Apr 2, 2026
b5543f3
Added source_attribute pattern for Embed and ESignConfig with configu…
philayres Apr 2, 2026
c59c446
Added NamedConfiguration to DbConfigs for column config entries - fix…
philayres Apr 2, 2026
71d791f
Added NamedConfiguration to FieldOptions for per-field options - fixe…
philayres Apr 2, 2026
24a998f
Added Configurations class for top-level _configurations options - fi…
philayres Apr 2, 2026
7caa105
Added Comments and DataDictionaryConfig classes for top-level options…
philayres Apr 2, 2026
771bff6
Added Constants class for top-level _constants options - fixes #986
philayres Apr 2, 2026
e4609a9
Fixed parsed_options_text_spec migration timeouts by reusing table - …
philayres Apr 2, 2026
0fb1de8
Added key? to BaseNamedConfiguration, fixed Constants to_h in substit…
philayres Apr 2, 2026
e58979d
Added []= to BaseNamedConfiguration for template compatibility - fixe…
philayres Apr 2, 2026
0c5daeb
Added except to BaseConfiguration for ConditionalActions compatibilit…
philayres Apr 2, 2026
df58c8f
Updated redcap spec to check Hash-like behavior instead of exact Hash…
philayres Apr 2, 2026
2844cca
Fixed extra option config compatibility regressions - fixes #986
philayres Apr 2, 2026
73dbb90
Fixed migration trigger and spec regressions - fixes #986
philayres Apr 3, 2026
af82c45
Fixed config notices enrichment, template null-safety, and save-trigg…
philayres Apr 4, 2026
1cf9d6a
Updated option config validations and schema docs - fixes #986
philayres Apr 7, 2026
ccc8fa3
Added schema docs for simple family defs, refactored spec to data-dri…
philayres Apr 7, 2026
d66d8ef
Added CaptionBefore validation for value types and contextual field n…
philayres Apr 8, 2026
dda8356
Added PatternValidation concern with shared DSL for field-keyed confi…
philayres Apr 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ def show_caption_before(key, captions, mode: nil, no_sub: nil, ignore_missing: t

mode ||= action_name == 'new' ? :new : :edit
caption = captions[key]
caption = caption[:"#{mode}_caption"] || caption[:caption] || '' if caption.is_a?(Hash)
if caption.is_a?(Hash) || caption.is_a?(OptionConfigs::BaseNamedConfiguration)
caption = caption[:"#{mode}_caption"] || caption[:caption] || ''
end
if @form_object_instance && !no_sub
caption = Formatter::Substitution.substitute(caption, data: @form_object_instance, tag_subs: nil,
ignore_missing:)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pattern 1: Always allow adding the reference
add_reference_if:
always: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pattern 2: Never allow adding the reference
add_reference_if:
never: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Pattern 3: Conditional reference addition
add_reference_if:
all:
this:
status: active
not_any:
activity_log__example_reviews:
extra_log_type: closed
46 changes: 34 additions & 12 deletions app/models/admin/defs/extra_options_caption_before_defs.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
# caption_before options
# Canonical schema
# caption_before: <Hash(caption_target_key: CaptionBeforeValue)>
#
# Key type
# caption_target_key: <valid_field_name | all_fields | submit | reference_<reference_name>>
#
# Value type
# CaptionBeforeValue: <String | Hash(
# caption: String,
# show_caption: String,
# edit_caption: String,
# new_caption: String,
# keep_label: Boolean
# )>
# All keys are optional.
#
# Pattern 1: Simple caption string
#!defs(extra_options_caption_before_pattern_1_simple_defs.yaml)
#
# Pattern 2: Caption hash with keep_label
#!defs(extra_options_caption_before_pattern_2_keep_label_defs.yaml)
#
# Pattern 3: View-specific captions
#!defs(extra_options_caption_before_pattern_3_view_specific_defs.yaml)
#
# Special keys
caption_before:
field_name: |
String caption to appear before field. Use markdown formatting if needed.

[Substitutions](../general/substitutions.md) of data can be performed with `\{\{data_attribute\}\}` notation.
all_fields: caption to appear before all fields
submit: caption to appear before submit button
field_to_retain_label:
keep_label: true
caption: caption to appear before label
field_with_different_views:
show_caption: caption in show mode
edit_caption: caption in edit mode
new_caption: caption in new mode
reference_with_reference_name: |
reference_<reference_name>: |
add caption above a reference action / list where
the reference is named reference_<reference name>

# Notes:
# - String values are expanded to all caption modes with text_to_html conversion.
# - new_caption defaults to edit_caption when not specified.
# - all_fields and submit are pseudo-keys excluded from field_configs merging.
# - reference_<reference_name> adds a caption above the named reference action/list.
# - <field_name> and <reference_name> must refer to valid configured items in the current definition.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Pattern 1: Simple caption string
# Specify a caption to appear before a field, hiding the field's label.
caption_before:
field_name: |
String caption to appear before field. Use markdown formatting if needed.

[Substitutions](../general/substitutions.md) of data can be performed with `\{\{data_attribute\}\}` notation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Pattern 2: Caption hash with keep_label
# Specify a field with a caption hash allowing an option to retain the label.
caption_before:
field_name:
caption: caption to appear before label
keep_label: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Pattern 3: View-specific captions
# Specify a field with captions that appear in different views.
caption_before:
field_name:
show_caption: caption in show mode
edit_caption: caption in edit mode
new_caption: caption in new mode
keep_label: true
22 changes: 21 additions & 1 deletion app/models/admin/defs/extra_options_creatable_if_defs.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,22 @@
# creatable_if options
creatable_if: 'ref: ** conditions reference **'
#
# Pattern 1: Always creatable
creatable_if:
always: true

# Pattern 2: Never creatable
creatable_if:
never: true

# Pattern 3: Creatable only when conditions are met
creatable_if:
all:
this:
status: active
not_any:
activity_log__example_reviews:
extra_log_type: closed

# Notes:
# - creatable_if must be a Hash using the standard conditional-actions syntax.
# - This commonly interacts with view_options.hide_unless_creatable and with references.creatable_if.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pattern 1: Always creatable
creatable_if:
always: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pattern 2: Never creatable
creatable_if:
never: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Pattern 3: Creatable only when conditions are met
creatable_if:
all:
this:
status: active
not_any:
activity_log__example_reviews:
extra_log_type: closed
29 changes: 26 additions & 3 deletions app/models/admin/defs/extra_options_dialog_before_defs.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
# dialog_before options
# Canonical schema
# dialog_before: <Hash(dialog_target_key: DialogBeforeValue)>
#
# Key type
# dialog_target_key: <valid_field_name | all_fields | submit>
#
# Value type
# DialogBeforeValue: <String | Hash(
# name: String (required),
# label: String,
# keep_label: Boolean
# )>
# Keys are optional unless marked (required).
#
# Pattern 1: Simple string (template name only)
#!defs(extra_options_dialog_before_pattern_1_simple_defs.yaml)
#
# Pattern 2: Hash with label
#!defs(extra_options_dialog_before_pattern_2_hash_defs.yaml)
#
# Special keys
dialog_before:
field_name:
name: message template name
label: show dialog button label
all_fields:
name: message template name
label: show dialog button label
submit:
name: message template name
label: show dialog button label

# Notes:
# - String values are expanded to { name: string }.
# - The name must reference an existing Admin::MessageTemplate.
# - all_fields and submit are pseudo-keys with the same behavior as caption_before.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pattern 1: Simple string (template name only)
dialog_before:
field_name: message template name
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pattern 2: Hash with label
dialog_before:
field_name:
name: message template name
label: show dialog button label
32 changes: 28 additions & 4 deletions app/models/admin/defs/extra_options_editable_if_defs.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
# editable_if options
editable_if: |
'ref: ** conditions reference **'
#
# Pattern 1: Explicitly always editable
editable_if:
always: true

NOTE: if not defined, the default is to only allow an item to be editable if it is the most recently created or
item in the list. If you want items to be always editable, use *always: true*
# Pattern 2: Explicitly never editable
editable_if:
never: true

# Pattern 3: Conditional editable rules using the standard conditions reference
editable_if:
all:
this:
status: draft
not_any:
activity_log__example_reviews:
extra_log_type: finalized

# Pattern 4: Merge reusable conditions with local rules
editable_if:
<<: *some_condition_anchor
all:
this:
status: draft

# Notes:
# - editable_if must be a Hash using the standard conditional-actions syntax.
# - If not defined, the default behavior is to allow editing only for the most recent item in the list.
# - Use always: true when you want to override that default and keep all matching items editable.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pattern 1: Explicitly always editable
editable_if:
always: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pattern 2: Explicitly never editable
editable_if:
never: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Pattern 3: Conditional editable rules
editable_if:
all:
this:
status: draft
not_any:
activity_log__example_reviews:
extra_log_type: finalized
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Pattern 4: Merge reusable conditions with local rules
editable_if:
<<: *some_condition_anchor
all:
this:
status: draft
45 changes: 21 additions & 24 deletions app/models/admin/defs/extra_options_embed_defs.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
# embed options
# embed can be defined in one of three styles:
embed: default_embed_resource
# Simply embeds the dynamic model matching the default_embed_resource_name for this activity
# Must include a field acting as a foreign key onto the parent `<singularized parent table name>_id`
#
# Pattern 1: Use the activity's default embedded resource
embed: default_embed_resource

embed: resource name for the item to be embedded
# Must include a field acting as a foreign key onto the parent `<singularized parent table name>_id`
# Pattern 2: Embed a specific resource by resource name string
embed: dynamic_model__resource_name

embed(form 2):
resource_name: resource name for the item to embed
resource_id: |
(optional) literal integer or a named attribute on the resource to use as an id of the embedded item
# Pattern 3: Explicit Hash form for direct embed configuration
embed:
resource_name: dynamic_model__resource_name
resource_id: 123 | attribute_name
limit: 1

When not specified, the embedded item is looked up based on the existence of a foreign key
field in the target direct embed table pointing back to the parent record. The foreign key
field is named "<singularized parent table name>_id"
limit: (optional) default 1 - although other values may be set, the aim is not really to use direct embedded items for this

# NOTE: direct embed may be configured either using this *embed:* configuration, or directly
# defining fields on the parent and optionally target tables.
# An advantage of using fields on the parent table is that the target embed resource may be specified on a
# record by record basis.
# To define an embedded item using fields alone, use one of the following field configurations:
# <parent table>: embed_resource_name, embed_resource_id - directly reference the embedded item
# <parent table>: embed_resource_name, <target embed table>: <singularized parent table name>_id - foreign key reference.
# Whichever way an embedded item is specified,
# `\{\{substitutions\}\}` may reference attributes in it item using `\{\{embedded_item.<attribute name>\}\}`
# Notes:
# - embed supports only the three patterns above.
# - In Hash form, the supported admin keys are resource_name, resource_id and limit.
# - resource_id may be a literal integer or an attribute name on the resource.
# - limit is normally 1 for direct embeds.
# - The embedded resource must still support linking back to the parent record, usually through
# <singularized parent table name>_id.
# - Direct embed may also be configured using fields alone:
# <parent table>: embed_resource_name, embed_resource_id
# <parent table>: embed_resource_name plus <target table>: <singularized parent table name>_id
# - Whichever way an embedded item is specified, {{embedded_item.<attribute name>}} substitutions are available.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Pattern 1: Default embedded resource
embed: default_embed_resource
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Pattern 2: Specific resource name
embed: dynamic_model__resource_name
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pattern 3: Explicit hash configuration
embed:
resource_name: dynamic_model__resource_name
resource_id: 123 | attribute_name
limit: 1
8 changes: 8 additions & 0 deletions app/models/admin/defs/extra_options_label_defs.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# label options
# Canonical schema
# label: <String>
#
label: main label (also used as + button label if button_label not defined)
button_label: add record button label

# Notes:
# - label must be a String; non-string values produce a warning and default to empty string.
# - If not specified, defaults to the humanized option type name.
# - button_label is a separate top-level key, not nested under label.
7 changes: 7 additions & 0 deletions app/models/admin/defs/extra_options_labels_defs.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# labels options
# Canonical schema
# labels: <Hash(valid_field_name: String)>
#
labels:
field_name: label to show

# Notes:
# - Each key must be a valid field name on the current model.
# - Values are plain strings used as display labels for the corresponding field.
Loading