backstage 0.1.15 → 0.1.17
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 +20 -0
- data/app/controllers/backstage/resources_controller.rb +5 -4
- data/app/views/backstage/fields/_nested.html.erb +22 -6
- data/app/views/backstage/resources/edit.html.erb +9 -0
- data/app/views/backstage/resources/new.html.erb +9 -0
- data/app/views/layouts/backstage/backstage.html.erb +24 -5
- data/lib/backstage/resource_config.rb +1 -1
- data/lib/backstage/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: daa88b222f8f96e18685ccb3fd5aa7df2b7123a0000e65eb75ed567e3241b4b9
|
|
4
|
+
data.tar.gz: 33a3c9b348029ccb14da21801174769d11481e332735ce923f2b1e2d15799691
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 889e54bc4ab50f29711be9c3dbf5de0afc06855affbede4bf3fd56d9f8131be3c1877dc273bb39f7448cb428ef9d9bedd15c7e00756d37094a2857396b9326cc
|
|
7
|
+
data.tar.gz: 6569763f092592c84fccb96f4bbd3bf589a97ef26a13c07fbcf1441c39ba1f32805c1ed7a2e638a814f46d68ad7a59646c0a1461ade2d28fbc33d156b71534d7
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,26 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.17] — 2026-06-04
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Flash notice is displayed after a successful create or update
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Edit and new forms now render validation error messages inline when save fails
|
|
19
|
+
- Successful update now redirects back to the edit page instead of the index
|
|
20
|
+
|
|
21
|
+
## [0.1.16] — 2026-06-02
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Nested table now uses a `<template>` element instead of a static new row, so unsaved blank rows are never submitted unintentionally
|
|
26
|
+
- New-row template includes readonly fields as plain inputs so new records can be fully populated via the Add button
|
|
27
|
+
- Readonly nested fields are now permitted in Strong Parameters, so new records with readonly fields save correctly
|
|
28
|
+
- `belongs_to :assoc, readonly: true` now propagates `readonly:` to the generated FK field
|
|
29
|
+
|
|
10
30
|
## [0.1.15] — 2026-05-27
|
|
11
31
|
|
|
12
32
|
### Added
|
|
@@ -40,7 +40,8 @@ module Backstage
|
|
|
40
40
|
def create
|
|
41
41
|
@record = @resource_config.model_class.new(record_params)
|
|
42
42
|
if @record.save
|
|
43
|
-
redirect_to edit_resource_path(resource: params[:resource], id: @record.id)
|
|
43
|
+
redirect_to edit_resource_path(resource: params[:resource], id: @record.id),
|
|
44
|
+
notice: "#{@resource_config.model_class.model_name.human} was successfully created."
|
|
44
45
|
else
|
|
45
46
|
render :new, status: :unprocessable_entity
|
|
46
47
|
end
|
|
@@ -48,7 +49,8 @@ module Backstage
|
|
|
48
49
|
|
|
49
50
|
def update
|
|
50
51
|
if @record.update(record_params)
|
|
51
|
-
redirect_to
|
|
52
|
+
redirect_to edit_resource_path(resource: params[:resource], id: @record.id),
|
|
53
|
+
notice: "#{@resource_config.model_class.model_name.human} was successfully saved."
|
|
52
54
|
else
|
|
53
55
|
render :edit, status: :unprocessable_entity
|
|
54
56
|
end
|
|
@@ -99,8 +101,7 @@ module Backstage
|
|
|
99
101
|
elsif field.has_many?
|
|
100
102
|
[{field.name => []}]
|
|
101
103
|
elsif field.nested?
|
|
102
|
-
|
|
103
|
-
[{"#{field.name}_attributes": [:id, :_destroy, *writable]}]
|
|
104
|
+
[{"#{field.name}_attributes": [:id, :_destroy, *field.nested_fields]}]
|
|
104
105
|
else
|
|
105
106
|
[field.name]
|
|
106
107
|
end
|
|
@@ -27,13 +27,29 @@
|
|
|
27
27
|
</td>
|
|
28
28
|
</tr>
|
|
29
29
|
<% end %>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
<%# Template is not part of the DOM — never submitted until the user clicks Add %>
|
|
31
|
+
<template data-nested-template data-next-index="<%= records.size %>">
|
|
32
|
+
<tr>
|
|
33
|
+
<% field.nested_fields.each do |col| %>
|
|
34
|
+
<td>
|
|
35
|
+
<input type="text"
|
|
36
|
+
name="<%= "#{f.object_name}[#{field.name}_attributes][__INDEX__][#{col}]" %>"
|
|
37
|
+
value="" />
|
|
38
|
+
</td>
|
|
34
39
|
<% end %>
|
|
35
|
-
<td
|
|
40
|
+
<td>
|
|
41
|
+
<input type="hidden"
|
|
42
|
+
name="<%= "#{f.object_name}[#{field.name}_attributes][__INDEX__][_destroy]" %>"
|
|
43
|
+
value="0"
|
|
44
|
+
data-nested-destroy-flag="true" />
|
|
45
|
+
<button type="button" data-nested-destroy aria-label="Remove">×</button>
|
|
46
|
+
</td>
|
|
36
47
|
</tr>
|
|
37
|
-
|
|
48
|
+
</template>
|
|
49
|
+
<tr>
|
|
50
|
+
<td colspan="<%= field.nested_fields.size + 1 %>">
|
|
51
|
+
<button type="button" data-nested-add>+ Add</button>
|
|
52
|
+
</td>
|
|
53
|
+
</tr>
|
|
38
54
|
</tbody>
|
|
39
55
|
</table>
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
<div<% if sidebar&.links&.any? %> class="edit-layout"<% end %>>
|
|
5
5
|
<div>
|
|
6
6
|
<%= form_with model: @record, url: resource_path(resource: params[:resource], id: @record.id), method: :patch do |f| %>
|
|
7
|
+
<% if @record.errors.any? %>
|
|
8
|
+
<div class="error-messages">
|
|
9
|
+
<ul>
|
|
10
|
+
<% @record.errors.full_messages.each do |msg| %>
|
|
11
|
+
<li><%= msg %></li>
|
|
12
|
+
<% end %>
|
|
13
|
+
</ul>
|
|
14
|
+
</div>
|
|
15
|
+
<% end %>
|
|
7
16
|
<% @resource_config.edit_fields.each do |field| %>
|
|
8
17
|
<% if field.container? %>
|
|
9
18
|
<%= render partial: field.partial_path, locals: { f: f, field: field, record: @record } %>
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
<h1>New <%= @resource_config.model_class.model_name.human %></h1>
|
|
2
2
|
|
|
3
3
|
<%= form_with model: @record, url: resources_path(resource: params[:resource]), method: :post do |f| %>
|
|
4
|
+
<% if @record.errors.any? %>
|
|
5
|
+
<div class="error-messages">
|
|
6
|
+
<ul>
|
|
7
|
+
<% @record.errors.full_messages.each do |msg| %>
|
|
8
|
+
<li><%= msg %></li>
|
|
9
|
+
<% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
4
13
|
<% @resource_config.edit_fields.each do |field| %>
|
|
5
14
|
<% if field.container? %>
|
|
6
15
|
<%= render partial: field.partial_path, locals: { f: f, field: field, record: @record } %>
|
|
@@ -26,12 +26,23 @@
|
|
|
26
26
|
})
|
|
27
27
|
})
|
|
28
28
|
})
|
|
29
|
-
document.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
row.
|
|
29
|
+
document.addEventListener("click", function(e) {
|
|
30
|
+
var destroyBtn = e.target.closest("[data-nested-destroy]")
|
|
31
|
+
if (destroyBtn) {
|
|
32
|
+
var row = destroyBtn.closest("tr")
|
|
33
|
+
var flag = row.querySelector("[data-nested-destroy-flag]")
|
|
34
|
+
if (flag) flag.value = "1"
|
|
33
35
|
row.hidden = true
|
|
34
|
-
}
|
|
36
|
+
}
|
|
37
|
+
var addBtn = e.target.closest("[data-nested-add]")
|
|
38
|
+
if (addBtn) {
|
|
39
|
+
var table = addBtn.closest("table")
|
|
40
|
+
var tmpl = table.querySelector("[data-nested-template]")
|
|
41
|
+
var index = parseInt(tmpl.dataset.nextIndex, 10)
|
|
42
|
+
tmpl.dataset.nextIndex = index + 1
|
|
43
|
+
var html = tmpl.innerHTML.replace(/__INDEX__/g, index)
|
|
44
|
+
addBtn.closest("tr").insertAdjacentHTML("beforebegin", html)
|
|
45
|
+
}
|
|
35
46
|
})
|
|
36
47
|
})
|
|
37
48
|
</script>
|
|
@@ -49,6 +60,14 @@
|
|
|
49
60
|
</ul>
|
|
50
61
|
</nav>
|
|
51
62
|
<main>
|
|
63
|
+
<div id="flash">
|
|
64
|
+
<% if flash[:notice] %>
|
|
65
|
+
<p class="notice"><%= flash[:notice] %></p>
|
|
66
|
+
<% end %>
|
|
67
|
+
<% if flash[:alert] %>
|
|
68
|
+
<p class="alert"><%= flash[:alert] %></p>
|
|
69
|
+
<% end %>
|
|
70
|
+
</div>
|
|
52
71
|
<%= yield %>
|
|
53
72
|
</main>
|
|
54
73
|
</body>
|
|
@@ -63,7 +63,7 @@ module Backstage
|
|
|
63
63
|
def belongs_to(name, **opts)
|
|
64
64
|
assoc = AssociationConfig.new(name, :belongs_to, opts)
|
|
65
65
|
@associations << assoc
|
|
66
|
-
fk_field = Field.new(assoc.foreign_key, :belongs_to, association: assoc)
|
|
66
|
+
fk_field = Field.new(assoc.foreign_key, :belongs_to, association: assoc, readonly: opts[:readonly])
|
|
67
67
|
index_field = Field.new(name.to_sym, :belongs_to, association: assoc)
|
|
68
68
|
@edit_fields.reject! { |f| f.name == fk_field.name }
|
|
69
69
|
@index_fields.reject! { |f| f.name == fk_field.name || f.name == index_field.name }
|
data/lib/backstage/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.1.17
|
|
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-
|
|
11
|
+
date: 2026-06-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|