backstage 0.1.14 → 0.1.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af33e498a31b4178f2565526576a747f3b40f79fe869d0c9f02e7b9147f250ed
4
- data.tar.gz: e4a561394fe10ec3ac30a8bcbc3492bd13285881c9e1e1cf2d16a2ef3302e259
3
+ metadata.gz: da02200425a97de115bbd7a4ff85a2cc907ab221647c3c9d22bb105ce690ff99
4
+ data.tar.gz: 4f53000b38b952e825cb5e82211162a7ce2149834e4efc671cf560595226593b
5
5
  SHA512:
6
- metadata.gz: faf0d674103b06bffd2625b114aec195037f8ab3c08ff6a5c8786abb8b8fd5c53938c6f394a934e10820459089af5c0fcafda82d86ddae9c584081918287ceef
7
- data.tar.gz: 1b2ee32beb0c16edfd8a7d2b08f86671ead990cc131272a60b9fd3a027fd8b9b1c5d37314ee7eccec221e6cd037fb9e6706d60dc8f97041dbfd1f11470e1a2ac
6
+ metadata.gz: 83f557e7644fa1e07487d3995854645f71454fee792023e9a344f24639fe222cef1d9c8a6bb130e8673dac4f7c4a942df5bb52a7ce06b0628c0a74461e3b1a59
7
+ data.tar.gz: dfd0f21995ca2a17e92016e86e6c975633b35b54c40a198e9edd8964116080a574055bd8480aceb589d5391739d87ee51cbdb65fcc600c636b3b8e1d4c31894c
data/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.15] — 2026-05-27
11
+
12
+ ### Added
13
+
14
+ - `c.nested :assoc, fields: [...]` DSL renders existing `has_many` records as an inline editable table using `accepts_nested_attributes_for`
15
+ - Nested rows include a destroy button (×) and a `_destroy` hidden field; clicking hides the row and marks it for deletion on save
16
+ - A blank add row is always rendered at the bottom of the nested table for creating new records
17
+ - `image_url` fields on index and dashboard tables now render as `<img>` tags instead of raw URLs
18
+ - `belongs_to` fields now render correctly on dashboard tables (was missing)
19
+ - Shared `backstage/shared/_cell` partial extracted for consistent field rendering across index and dashboard views
20
+
10
21
  ## [0.1.14] — 2026-05-26
11
22
 
12
23
  ### Fixed
@@ -100,7 +100,7 @@ module Backstage
100
100
  [{field.name => []}]
101
101
  elsif field.nested?
102
102
  writable = field.nested_fields - field.nested_readonly_fields
103
- [{"#{field.name}_attributes": [:id, *writable]}]
103
+ [{"#{field.name}_attributes": [:id, :_destroy, *writable]}]
104
104
  else
105
105
  [field.name]
106
106
  end
@@ -13,13 +13,7 @@
13
13
  <% @records.each do |record| %>
14
14
  <tr id="<%= @resource_config.model_name_param %>_<%= record.id %>_row">
15
15
  <% @resource_config.index_fields.each do |field| %>
16
- <td>
17
- <% if field.enum? %>
18
- <%= record.public_send(field.name).to_s.humanize %>
19
- <% else %>
20
- <%= record.public_send(field.name) %>
21
- <% end %>
22
- </td>
16
+ <td><%= render "backstage/shared/cell", field: field, record: record %></td>
23
17
  <% end %>
24
18
  <td><%= link_to "Edit", edit_resource_path(resource: @resource_config.model_name_param, id: record.id) %></td>
25
19
  </tr>
@@ -1,30 +1,39 @@
1
1
  <% records = record.public_send(field.name) %>
2
- <% if records.any? %>
3
- <table>
4
- <thead>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <% field.nested_fields.each do |col| %>
6
+ <th><%= col.to_s.humanize %></th>
7
+ <% end %>
8
+ <th></th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <%= f.fields_for field.name do |nf| %>
5
13
  <tr>
14
+ <%= nf.hidden_field :id %>
15
+ <%= nf.hidden_field :_destroy, value: "0", data: {nested_destroy_flag: true} %>
6
16
  <% field.nested_fields.each do |col| %>
7
- <th><%= col.to_s.humanize %></th>
17
+ <td>
18
+ <% if field.nested_readonly_fields.include?(col) %>
19
+ <%= nf.object.public_send(col) %>
20
+ <% else %>
21
+ <%= nf.text_field col %>
22
+ <% end %>
23
+ </td>
8
24
  <% end %>
25
+ <td>
26
+ <button type="button" data-nested-destroy aria-label="Remove">&times;</button>
27
+ </td>
9
28
  </tr>
10
- </thead>
11
- <tbody>
12
- <%= f.fields_for field.name do |nf| %>
13
- <%= nf.hidden_field :id %>
14
- <tr>
15
- <% field.nested_fields.each do |col| %>
16
- <td>
17
- <% if field.nested_readonly_fields.include?(col) %>
18
- <%= nf.object.public_send(col) %>
19
- <% else %>
20
- <%= nf.text_field col %>
21
- <% end %>
22
- </td>
23
- <% end %>
24
- </tr>
25
- <% end %>
26
- </tbody>
27
- </table>
28
- <% else %>
29
- <em>None</em>
30
- <% end %>
29
+ <% end %>
30
+ <%= f.fields_for field.name, records.klass.new, child_index: records.size do |nf| %>
31
+ <tr data-nested-new-row>
32
+ <% field.nested_fields.reject { |col| field.nested_readonly_fields.include?(col) }.each do |col| %>
33
+ <td><%= nf.text_field col %></td>
34
+ <% end %>
35
+ <td></td>
36
+ </tr>
37
+ <% end %>
38
+ </tbody>
39
+ </table>
@@ -32,20 +32,7 @@
32
32
  <% @records.each do |record| %>
33
33
  <tr>
34
34
  <% @resource_config.index_fields.each do |field| %>
35
- <td>
36
- <% if field.enum? %>
37
- <%= record.public_send(field.name).to_s.humanize %>
38
- <% elsif field.belongs_to? %>
39
- <% related = record.public_send(field.association.name)
40
- col = field.association.display_column
41
- label = related&.public_send(col) %>
42
- <% if related %>
43
- <%= link_to label, edit_resource_path(resource: related.class.model_name.plural, id: related.id) %>
44
- <% end %>
45
- <% else %>
46
- <%= record.public_send(field.name) %>
47
- <% end %>
48
- </td>
35
+ <td><%= render "backstage/shared/cell", field: field, record: record %></td>
49
36
  <% end %>
50
37
  <td><%= link_to "Edit", edit_resource_path(resource: params[:resource], id: record.id) %></td>
51
38
  </tr>
@@ -0,0 +1,17 @@
1
+ <% if field.image_url? %>
2
+ <% url = record.public_send(field.name) %>
3
+ <% if url.present? %>
4
+ <%= image_tag url, style: "max-height:60px;" %>
5
+ <% end %>
6
+ <% elsif field.enum? %>
7
+ <%= record.public_send(field.name).to_s.humanize %>
8
+ <% elsif field.belongs_to? %>
9
+ <% related = record.public_send(field.association.name)
10
+ col = field.association.display_column
11
+ label = related&.public_send(col) %>
12
+ <% if related %>
13
+ <%= link_to label, edit_resource_path(resource: related.class.model_name.plural, id: related.id) %>
14
+ <% end %>
15
+ <% else %>
16
+ <%= record.public_send(field.name) %>
17
+ <% end %>
@@ -26,6 +26,13 @@
26
26
  })
27
27
  })
28
28
  })
29
+ document.querySelectorAll("[data-nested-destroy]").forEach(function(btn) {
30
+ btn.addEventListener("click", function() {
31
+ var row = btn.closest("tr")
32
+ row.querySelector("[data-nested-destroy-flag]").value = "1"
33
+ row.hidden = true
34
+ })
35
+ })
29
36
  })
30
37
  </script>
31
38
  </head>
@@ -36,6 +36,10 @@ module Backstage
36
36
  type == :nested
37
37
  end
38
38
 
39
+ def image_url?
40
+ type == :image_url
41
+ end
42
+
39
43
  def nested_fields
40
44
  options[:nested_fields] || []
41
45
  end
@@ -1,3 +1,3 @@
1
1
  module Backstage
2
- VERSION = "0.1.14"
2
+ VERSION = "0.1.15"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backstage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gareth James
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-26 00:00:00.000000000 Z
11
+ date: 2026-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -61,6 +61,7 @@ files:
61
61
  - app/views/backstage/resources/edit.html.erb
62
62
  - app/views/backstage/resources/index.html.erb
63
63
  - app/views/backstage/resources/new.html.erb
64
+ - app/views/backstage/shared/_cell.html.erb
64
65
  - app/views/backstage/shared/_pagination.html.erb
65
66
  - app/views/layouts/backstage/backstage.html.erb
66
67
  - config/routes.rb