backstage 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/app/controllers/backstage/resources_controller.rb +14 -3
- data/app/views/backstage/fields/_row.html.erb +8 -0
- data/app/views/backstage/fields/_section.html.erb +13 -0
- data/app/views/backstage/resources/edit.html.erb +7 -3
- data/lib/backstage/field.rb +24 -0
- data/lib/backstage/resource_config.rb +23 -2
- data/lib/backstage/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e1dc01f215a31bcb5c84237cdfb95a7622ab7c8298e3b822eb476a9363e2f35c
|
|
4
|
+
data.tar.gz: 2a83eb127cfe5da24e409bf9f1ef69019a4d11be122402b5ca712f66ddfd1b3d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 46f7f8d377fa8c1fa57f3113b224df3428cdc99d21282ea1812a3e4d6b5f617c1f051adcc303217df1da8f4c2edfa1c800fa32dc3ae91b4f77aca0f3deb90a82
|
|
7
|
+
data.tar.gz: 3600c7c9e27c410a887fa6e63458eee543eb2d23271ee24adb99d1a8785272c7e3625498a86ae6ee54f0d68da3b6a6ed826c858a764394dcaea0b30536195d81
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.12] — 2026-05-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `c.row :field1, :field2` groups fields horizontally in a Pico CSS grid on the edit page
|
|
15
|
+
- `c.section "Label" [, collapsed: true]` wraps fields in a native `<details>`/`<summary>` collapsible block (no JavaScript required); rows and individual fields can be nested inside sections
|
|
16
|
+
- `c.field` called inside a `section` block moves an existing auto-discovered field into the section rather than leaving it at the top level
|
|
17
|
+
|
|
10
18
|
## [0.1.11] — 2026-05-25
|
|
11
19
|
|
|
12
20
|
### Fixed
|
|
@@ -85,10 +85,21 @@ module Backstage
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
def record_params
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
params
|
|
89
|
+
.require(@resource_config.model_class.model_name.param_key)
|
|
90
|
+
.permit(permitted_field_names(@resource_config.edit_fields))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def permitted_field_names(fields)
|
|
94
|
+
fields.reject(&:readonly?).flat_map do |field|
|
|
95
|
+
if field.container?
|
|
96
|
+
permitted_field_names(field.sub_fields)
|
|
97
|
+
elsif field.has_many?
|
|
98
|
+
[{field.name => []}]
|
|
99
|
+
else
|
|
100
|
+
[field.name]
|
|
101
|
+
end
|
|
90
102
|
end
|
|
91
|
-
params.require(@resource_config.model_class.model_name.param_key).permit(permitted)
|
|
92
103
|
end
|
|
93
104
|
end
|
|
94
105
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<details <%= "open" unless field.collapsed? %>>
|
|
2
|
+
<summary><strong><%= field.heading %></strong></summary>
|
|
3
|
+
<% field.sub_fields.each do |sub| %>
|
|
4
|
+
<% if sub.container? %>
|
|
5
|
+
<%= render partial: sub.partial_path, locals: { f: f, field: sub, record: @record } %>
|
|
6
|
+
<% else %>
|
|
7
|
+
<div>
|
|
8
|
+
<%= f.label sub.name %>
|
|
9
|
+
<%= render partial: sub.partial_path, locals: { f: f, field: sub, record: @record } %>
|
|
10
|
+
</div>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
</details>
|
|
@@ -5,10 +5,14 @@
|
|
|
5
5
|
<div>
|
|
6
6
|
<%= form_with model: @record, url: resource_path(resource: params[:resource], id: @record.id), method: :patch do |f| %>
|
|
7
7
|
<% @resource_config.edit_fields.each do |field| %>
|
|
8
|
-
|
|
9
|
-
<%= f.label field.name %>
|
|
8
|
+
<% if field.container? %>
|
|
10
9
|
<%= render partial: field.partial_path, locals: { f: f, field: field, record: @record } %>
|
|
11
|
-
|
|
10
|
+
<% else %>
|
|
11
|
+
<div>
|
|
12
|
+
<%= f.label field.name %>
|
|
13
|
+
<%= render partial: field.partial_path, locals: { f: f, field: field, record: @record } %>
|
|
14
|
+
</div>
|
|
15
|
+
<% end %>
|
|
12
16
|
<% end %>
|
|
13
17
|
<%= f.submit "Save" %>
|
|
14
18
|
<% end %>
|
data/lib/backstage/field.rb
CHANGED
|
@@ -32,6 +32,30 @@ module Backstage
|
|
|
32
32
|
type == :has_many
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def row?
|
|
36
|
+
type == :row
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def section?
|
|
40
|
+
type == :section
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def container?
|
|
44
|
+
row? || section?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def sub_fields
|
|
48
|
+
options[:sub_fields] || []
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def heading
|
|
52
|
+
options[:heading]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def collapsed?
|
|
56
|
+
options.fetch(:collapsed, false)
|
|
57
|
+
end
|
|
58
|
+
|
|
35
59
|
def association
|
|
36
60
|
options[:association]
|
|
37
61
|
end
|
|
@@ -74,13 +74,34 @@ module Backstage
|
|
|
74
74
|
if existing
|
|
75
75
|
existing.options.merge!(opts)
|
|
76
76
|
existing.instance_variable_set(:@type, type.to_sym) if type
|
|
77
|
+
if @current_target
|
|
78
|
+
@edit_fields.reject! { |f| f.name == sym }
|
|
79
|
+
@current_target << existing
|
|
80
|
+
end
|
|
77
81
|
else
|
|
78
82
|
new_field = Field.new(sym, type || :string, opts)
|
|
79
|
-
@edit_fields << new_field
|
|
80
|
-
@index_fields << new_field unless @index_fields_explicit
|
|
83
|
+
(@current_target || @edit_fields) << new_field
|
|
84
|
+
@index_fields << new_field unless @index_fields_explicit || @current_target
|
|
81
85
|
end
|
|
82
86
|
end
|
|
83
87
|
|
|
88
|
+
def row(*names)
|
|
89
|
+
syms = names.map(&:to_sym)
|
|
90
|
+
sub = syms.map { |n| find_field(n) || Field.new(n, :string) }
|
|
91
|
+
@edit_fields.reject! { |f| syms.include?(f.name) }
|
|
92
|
+
row_field = Field.new(:"row_#{names.first}", :row, sub_fields: sub)
|
|
93
|
+
(@current_target || @edit_fields) << row_field
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def section(heading, **opts)
|
|
97
|
+
section_field = Field.new(:"section_#{heading.parameterize}", :section,
|
|
98
|
+
heading: heading, sub_fields: [], **opts)
|
|
99
|
+
@current_target = section_field.sub_fields
|
|
100
|
+
yield if block_given?
|
|
101
|
+
@current_target = nil
|
|
102
|
+
@edit_fields << section_field
|
|
103
|
+
end
|
|
104
|
+
|
|
84
105
|
private
|
|
85
106
|
|
|
86
107
|
def find_field(name)
|
data/lib/backstage/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: backstage
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gareth James
|
|
@@ -51,6 +51,8 @@ files:
|
|
|
51
51
|
- app/views/backstage/fields/_has_many.html.erb
|
|
52
52
|
- app/views/backstage/fields/_image_url.html.erb
|
|
53
53
|
- app/views/backstage/fields/_integer.html.erb
|
|
54
|
+
- app/views/backstage/fields/_row.html.erb
|
|
55
|
+
- app/views/backstage/fields/_section.html.erb
|
|
54
56
|
- app/views/backstage/fields/_string.html.erb
|
|
55
57
|
- app/views/backstage/fields/_text.html.erb
|
|
56
58
|
- app/views/backstage/fields/_thumbnails.html.erb
|