plutonium 0.8.0 → 0.9.0
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/README.md +6 -0
- data/app/assets/js/controllers/application.js +1 -0
- data/app/assets/js/controllers/index.js +9 -0
- data/app/assets/js/controllers/resource_dismiss_controller.js +37 -0
- data/app/assets/js/controllers/resource_drop_down_controller.js +29 -0
- data/app/assets/js/turbo/index.js +1 -1
- data/app/views/application/_flash.html.erb +1 -1
- data/app/views/application/_flash_alerts.html.erb +51 -7
- data/app/views/application/_flash_toasts.html.erb +53 -23
- data/app/views/application/_resource_header.html.erb +563 -561
- data/app/views/components/form/form_builder.rb +2 -2
- data/app/views/components/form/form_component.html.erb +5 -6
- data/app/views/components/interactive_action_form/interactive_action_form_component.html.erb +1 -1
- data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.html.erb +66 -0
- data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.rb +23 -0
- data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_controller.js +64 -0
- data/app/views/components/sidebar/sidebar_component.html.erb +61 -63
- data/app/views/components/table_search_input/table_search_input_component.html.erb +1 -1
- data/app/views/layouts/resource.html copy.erb +0 -2
- data/app/views/layouts/resource.html.erb +1 -3
- data/app/views/layouts/rodauth.html.erb +0 -1
- data/app/views/resource/_interactive_resource_action_form.html.erb +1 -1
- data/exe/pug +6 -0
- data/lib/generators/pu/gen/component/component_generator.rb +1 -1
- data/lib/generators/pu/gen/pug/pug_generator.rb +1 -1
- data/lib/generators/pu/lib/plutonium_generators/cli.rb +42 -0
- data/lib/generators/pu/lib/plutonium_generators/generator.rb +1 -5
- data/lib/generators/pu/lib/plutonium_generators/model_generator.rb +1 -1
- data/lib/generators/pu/lib/plutonium_generators.rb +8 -0
- data/lib/plutonium/core/actions/collection.rb +1 -1
- data/lib/plutonium/core/controllers/authorizable.rb +4 -4
- data/lib/plutonium/core/fields/inputs/base.rb +1 -1
- data/lib/plutonium/core/fields/inputs/nested_input.rb +57 -0
- data/lib/plutonium/core/fields/inputs/noop_input.rb +1 -1
- data/lib/plutonium/core/fields/inputs/phone_input.rb +1 -1
- data/lib/plutonium/core/fields/inputs/polymorphic_belongs_to_association_input.rb +1 -1
- data/lib/plutonium/core/fields/inputs/simple_form_association_input.rb +1 -1
- data/lib/plutonium/core/fields/inputs/simple_form_input.rb +1 -1
- data/lib/plutonium/core/fields/renderers/factory.rb +1 -0
- data/lib/plutonium/core/fields/renderers/map_renderer.rb +19 -0
- data/lib/plutonium/resource/policy.rb +6 -0
- data/lib/plutonium/resource/presenter.rb +35 -0
- data/lib/plutonium/resource/record.rb +40 -7
- data/lib/plutonium/version.rb +1 -1
- data/package-lock.json +7 -0
- data/package.json +5 -4
- data/templates/base.rb +8 -0
- metadata +14 -4
- data/app/assets/js/controllers/dropdown_controller.js +0 -12
@@ -4,12 +4,12 @@ module Plutonium::Ui
|
|
4
4
|
class FormBuilder < SimpleForm::FormBuilder
|
5
5
|
def input(attribute_name, options = {}, &block)
|
6
6
|
label_class = options.dig(:label_html, :class)
|
7
|
-
if object
|
7
|
+
if object&.errors&.[](attribute_name).present?
|
8
8
|
# Don't show the hint
|
9
9
|
options.delete(:hint)
|
10
10
|
# Apply error class if there are errors
|
11
11
|
label_class = [label_class, "text-red-700 dark:text-red-500"].compact.join(" ")
|
12
|
-
elsif object
|
12
|
+
elsif object&.persisted? || !object&.errors&.empty?
|
13
13
|
# Apply success class if the object is persisted, has been validated (errors are not empty), and the field has no errors
|
14
14
|
label_class = [label_class, "block mb-2 text-sm font-medium text-green-700 dark:text-green-500"].compact.join(" ")
|
15
15
|
else
|
@@ -21,13 +21,13 @@
|
|
21
21
|
|
22
22
|
<div>
|
23
23
|
<% form.inputs.values.each do |input| %>
|
24
|
-
<%= input.render f, form.record %>
|
24
|
+
<%= input.render self, f, form.record %>
|
25
25
|
<% end %>
|
26
26
|
</div>
|
27
27
|
|
28
28
|
<div class="flex justify-end space-x-2">
|
29
29
|
<%# TODO: move this into its own component %>
|
30
|
-
<div class="flex">
|
30
|
+
<div class="flex" data-controller="resource-drop-down">
|
31
31
|
<button type="submit"
|
32
32
|
name="commit"
|
33
33
|
value="<%= preferred_action_after_submit %>"
|
@@ -40,19 +40,18 @@
|
|
40
40
|
</button>
|
41
41
|
<button type="button"
|
42
42
|
id="form-submit-options-toggle"
|
43
|
-
data-
|
43
|
+
data-resource-drop-down-target="trigger"
|
44
44
|
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white
|
45
45
|
rounded-e-md hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-primary-500
|
46
46
|
dark:border-gray-300
|
47
|
-
border-s"
|
48
|
-
>
|
47
|
+
border-s">
|
49
48
|
<svg class="w-2.5 h-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
50
49
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
51
50
|
</svg>
|
52
51
|
</button>
|
53
52
|
|
54
53
|
<!-- Dropdown menu -->
|
55
|
-
<div
|
54
|
+
<div data-resource-drop-down-target="menu"
|
56
55
|
class="z-10 hidden w-56 bg-white divide-y divide-gray-100 rounded-lg shadow dark:bg-gray-700 dark:divide-gray-600">
|
57
56
|
<ul class="p-3 space-y-3 text-sm text-gray-700 dark:text-gray-200"
|
58
57
|
aria-labelledby="form-submit-options-toggle">
|
data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.html.erb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
<div data-controller="nested-resource-form-fields"
|
2
|
+
data-nested-resource-form-fields-limit-value="<%= limit %>"
|
3
|
+
<%= render_component_attributes %>>
|
4
|
+
<h2 class="text-lg font-bold dark:text-white ">
|
5
|
+
<%= label %>
|
6
|
+
</h2>
|
7
|
+
<p class="mb-4 text-md font-normal text-gray-500 dark:text-gray-400">
|
8
|
+
<%= description %>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<template data-nested-resource-form-fields-target="template">
|
12
|
+
<% new_record = resource_class.new %>
|
13
|
+
<%= form.simple_fields_for name, new_record, child_index: 'NEW_RECORD' do |nested| %>
|
14
|
+
<fieldset class="border-t mt-4 pt-4 first:border-t-0 first:pt-0 nested-resource-form-fields" data-new-record="<%= nested.object.new_record? %>">
|
15
|
+
<% inputs.values.each do |input| %>
|
16
|
+
<%= input.render self, nested, new_record %>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<div class="text-right">
|
20
|
+
<% if nested.object.new_record? || allow_destroy %>
|
21
|
+
<label class="text-md font-medium text-red-900">
|
22
|
+
<%= "Delete" %>
|
23
|
+
<input type="checkbox" value=""
|
24
|
+
data-action="nested-resource-form-fields#remove"
|
25
|
+
class="w-4 h-4 ms-2 text-red-600 bg-red-100 border-red-300 rounded focus:ring-red-500 dark:focus:ring-red-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
26
|
+
</label>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<%= nested.hidden_field :_destroy %>
|
31
|
+
</fieldset>
|
32
|
+
<% end %>
|
33
|
+
</template>
|
34
|
+
|
35
|
+
<div>
|
36
|
+
<%= form.simple_fields_for name do |nested| %>
|
37
|
+
<fieldset class="border-t mt-4 pt-4 first:border-t-0 first:pt-0 nested-resource-form-fields" data-new-record="<%= nested.object.new_record? %>">
|
38
|
+
<% inputs.values.each do |input| %>
|
39
|
+
<%= input.render self, nested, new_record %>
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
<div>
|
43
|
+
<% if nested.object.new_record? || allow_destroy %>
|
44
|
+
<label class="flex items-center justify-end text-md font-medium text-red-900">
|
45
|
+
<%= "Delete" %>
|
46
|
+
<input type="checkbox" value=""
|
47
|
+
data-action="nested-resource-form-fields#remove"
|
48
|
+
class="w-4 h-4 ms-2 text-red-600 bg-red-100 border-red-300 rounded focus:ring-red-500 dark:focus:ring-red-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
49
|
+
</label>
|
50
|
+
<% end %>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
<%= nested.hidden_field :_destroy %>
|
54
|
+
</fieldset>
|
55
|
+
<% end %>
|
56
|
+
|
57
|
+
<div data-nested-resource-form-fields-target="target" hidden></div>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
<%=
|
61
|
+
render_component :button, label: "Add #{name.to_s.singularize.humanize}", classname: "mt-4", data: {
|
62
|
+
action: "nested-resource-form-fields#add",
|
63
|
+
"nested-resource-form-fields-target": "addButton"
|
64
|
+
}
|
65
|
+
%>
|
66
|
+
</div>
|
data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Plutonium::Ui
|
2
|
+
class NestedResourceFormFieldsComponent < Plutonium::Ui::Base
|
3
|
+
option :name
|
4
|
+
option :resource_class
|
5
|
+
option :form
|
6
|
+
option :inputs
|
7
|
+
option :label, optional: true
|
8
|
+
option :description, optional: true
|
9
|
+
option :allow_destroy, optional: true
|
10
|
+
option :update_only, optional: true
|
11
|
+
option :limit, optional: true
|
12
|
+
|
13
|
+
def base_classname
|
14
|
+
"mt-6 mb-4"
|
15
|
+
end
|
16
|
+
|
17
|
+
def label
|
18
|
+
super || name.to_s.humanize
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Plutonium::ComponentRegistry.register :nested_resource_form_fields, to: Plutonium::Ui::NestedResourceFormFieldsComponent
|
data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_controller.js
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
// Connects to data-controller="nested-resource-form-fields"
|
4
|
+
// Copied from https://github.com/stimulus-components/stimulus-rails-nested-form/blob/master/src/index.ts
|
5
|
+
export default class extends Controller {
|
6
|
+
static targets = ["target", "template", "addButton"]
|
7
|
+
|
8
|
+
static values = {
|
9
|
+
wrapperSelector: {
|
10
|
+
type: String,
|
11
|
+
default: ".nested-resource-form-fields",
|
12
|
+
},
|
13
|
+
limit: Number,
|
14
|
+
}
|
15
|
+
|
16
|
+
connect() {
|
17
|
+
this.updateState()
|
18
|
+
}
|
19
|
+
|
20
|
+
add(e) {
|
21
|
+
e.preventDefault()
|
22
|
+
|
23
|
+
const content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime().toString())
|
24
|
+
this.targetTarget.insertAdjacentHTML("beforebegin", content)
|
25
|
+
|
26
|
+
const event = new CustomEvent("nested-resource-form-fields:add", { bubbles: true })
|
27
|
+
this.element.dispatchEvent(event)
|
28
|
+
|
29
|
+
this.updateState()
|
30
|
+
}
|
31
|
+
|
32
|
+
remove(e) {
|
33
|
+
e.preventDefault()
|
34
|
+
|
35
|
+
const wrapper = e.target.closest(this.wrapperSelectorValue)
|
36
|
+
|
37
|
+
if (wrapper.dataset.newRecord === "true") {
|
38
|
+
wrapper.remove()
|
39
|
+
} else {
|
40
|
+
wrapper.style.display = "none"
|
41
|
+
|
42
|
+
const input = wrapper.querySelector("input[name*='_destroy']")
|
43
|
+
input.value = "1"
|
44
|
+
}
|
45
|
+
|
46
|
+
const event = new CustomEvent("nested-resource-form-fields:remove", { bubbles: true })
|
47
|
+
this.element.dispatchEvent(event)
|
48
|
+
|
49
|
+
this.updateState()
|
50
|
+
}
|
51
|
+
|
52
|
+
updateState() {
|
53
|
+
if (!this.hasAddButtonTarget || this.limitValue == 0) return
|
54
|
+
|
55
|
+
if (this.childCount >= this.limitValue)
|
56
|
+
this.addButtonTarget.style.display = "none"
|
57
|
+
else
|
58
|
+
this.addButtonTarget.style.display = "initial"
|
59
|
+
}
|
60
|
+
|
61
|
+
get childCount() {
|
62
|
+
return this.element.querySelectorAll(this.wrapperSelectorValue).length
|
63
|
+
}
|
64
|
+
}
|
@@ -86,69 +86,67 @@
|
|
86
86
|
updateColorMode()
|
87
87
|
</script>
|
88
88
|
|
89
|
-
|
90
|
-
<
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
</li>
|
151
|
-
</ul>
|
89
|
+
<!-- Color Modes -->
|
90
|
+
<div data-controller="resource-drop-down">
|
91
|
+
<button
|
92
|
+
type="button"
|
93
|
+
data-resource-drop-down-target="trigger"
|
94
|
+
class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:hover:text-white dark:text-gray-200 hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600">
|
95
|
+
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
|
96
|
+
<path d="M5 13.17a3.001 3.001 0 0 0 0 5.66V20a1 1 0 1 0 2 0v-1.17a3.001 3.001 0 0 0 0-5.66V4a1 1 0 0 0-2 0v9.17ZM11 20v-9.17a3.001 3.001 0 0 1 0-5.66V4a1 1 0 1 1 2 0v1.17a3.001 3.001 0 0 1 0 5.66V20a1 1 0 1 1-2 0Zm6-1.17V20a1 1 0 1 0 2 0v-1.17a3.001 3.001 0 0 0 0-5.66V4a1 1 0 1 0-2 0v9.17a3.001 3.001 0 0 0 0 5.66Z"/>
|
97
|
+
</svg>
|
98
|
+
</button>
|
99
|
+
<div
|
100
|
+
class="hidden z-50 my-4 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700"
|
101
|
+
data-resource-drop-down-target="menu">
|
102
|
+
<ul class="py-1" role="none">
|
103
|
+
<li>
|
104
|
+
<button
|
105
|
+
type="button"
|
106
|
+
class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
|
107
|
+
role="menuitem"
|
108
|
+
onclick="setLightColorMode()"
|
109
|
+
>
|
110
|
+
<div class="flex justify-start">
|
111
|
+
<svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
112
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5V3m0 18v-2M7.05 7.05 5.636 5.636m12.728 12.728L16.95 16.95M5 12H3m18 0h-2M7.05 16.95l-1.414 1.414M18.364 5.636 16.95 7.05M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"/>
|
113
|
+
</svg>
|
114
|
+
Light
|
115
|
+
</div>
|
116
|
+
</a>
|
117
|
+
</li>
|
118
|
+
<li>
|
119
|
+
<button
|
120
|
+
type="button"
|
121
|
+
class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
|
122
|
+
role="menuitem"
|
123
|
+
onclick="setDarkColorMode()"
|
124
|
+
>
|
125
|
+
<div class="flex justify-start">
|
126
|
+
<svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
127
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 21a9 9 0 0 1-.5-17.986V3c-.354.966-.5 1.911-.5 3a9 9 0 0 0 9 9c.239 0 .254.018.488 0A9.004 9.004 0 0 1 12 21Z"/>
|
128
|
+
</svg>
|
129
|
+
Dark
|
130
|
+
</div>
|
131
|
+
</a>
|
132
|
+
</li>
|
133
|
+
<li>
|
134
|
+
<button
|
135
|
+
type="button"
|
136
|
+
class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
|
137
|
+
role="menuitem"
|
138
|
+
onclick="setSystemColorMode()"
|
139
|
+
>
|
140
|
+
<div class="flex justify-start">
|
141
|
+
<svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
142
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 16H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v1M9 12H4m8 8V9h8v11h-8Zm0 0H9m8-4a1 1 0 1 0-2 0 1 1 0 0 0 2 0Z"/>
|
143
|
+
</svg>
|
144
|
+
System
|
145
|
+
</div>
|
146
|
+
</a>
|
147
|
+
</li>
|
148
|
+
</ul>
|
149
|
+
</div>
|
152
150
|
</div>
|
153
151
|
</div>
|
154
152
|
</aside>
|
@@ -7,7 +7,7 @@
|
|
7
7
|
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
|
8
8
|
</svg>
|
9
9
|
</div>
|
10
|
-
<%= search_object.search_filter.input_definitions[:search].render f, nil,
|
10
|
+
<%= search_object.search_filter.input_definitions[:search].render self, f, nil,
|
11
11
|
wrapper: false, label: false,
|
12
12
|
as: :string, # force string for search
|
13
13
|
placeholder: "search...",
|
@@ -15,8 +15,6 @@
|
|
15
15
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.css" integrity="sha512-GvqWM4KWH8mbgWIyvwdH8HgjUbyZTXrCq0sjGij9fDNiXz3vJoy3jCcAaWNekH2rJe4hXVWCJKN+bEW8V7AAEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
16
16
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.js" integrity="sha512-0E8oaoA2v32h26IycsmRDShtQ8kMgD91zWVBxdIvUCjU3xBw81PV61QBsBqNQpWkp/zYJZip8Ag3ifmzz1wCKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
17
17
|
|
18
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
|
19
|
-
|
20
18
|
<%== Plutonium::Config.stylesheet_tag.call self %>
|
21
19
|
<%== Plutonium::Config.script_tag.call self %>
|
22
20
|
<%= yield(:head) %>
|
@@ -21,8 +21,6 @@
|
|
21
21
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.css" integrity="sha512-GvqWM4KWH8mbgWIyvwdH8HgjUbyZTXrCq0sjGij9fDNiXz3vJoy3jCcAaWNekH2rJe4hXVWCJKN+bEW8V7AAEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
22
22
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.js" integrity="sha512-0E8oaoA2v32h26IycsmRDShtQ8kMgD91zWVBxdIvUCjU3xBw81PV61QBsBqNQpWkp/zYJZip8Ag3ifmzz1wCKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
23
23
|
|
24
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
|
25
|
-
|
26
24
|
<%= yield(:assets) %>
|
27
25
|
|
28
26
|
<%== Plutonium::Config.stylesheet_tag.call self %>
|
@@ -34,6 +32,7 @@
|
|
34
32
|
<%= render("resource_header") %>
|
35
33
|
<%= render("resource_sidebar") %>
|
36
34
|
<main class="p-4 lg:ml-64 h-auto pt-20">
|
35
|
+
<%= render "flash" %>
|
37
36
|
<%= yield %>
|
38
37
|
</main>
|
39
38
|
</body>
|
@@ -45,6 +44,5 @@
|
|
45
44
|
<%= modal_frame_tag do %>
|
46
45
|
<%= yield(:modal) %>
|
47
46
|
<% end %>
|
48
|
-
<%= render "flash" %>
|
49
47
|
|
50
48
|
-->
|
@@ -12,7 +12,6 @@
|
|
12
12
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
13
13
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
14
14
|
<link href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet">
|
15
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
|
16
15
|
<%== Plutonium::Config.stylesheet_tag.call self %>
|
17
16
|
<%== Plutonium::Config.script_tag.call self %>
|
18
17
|
</head>
|
data/exe/pug
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
require File.expand_path("../plutonium_generators", __dir__)
|
5
|
+
|
6
|
+
module PlutoniumGenerators
|
7
|
+
class CLI < Thor
|
8
|
+
map "i" => :install
|
9
|
+
map "g" => :generate
|
10
|
+
map "ls" => :list
|
11
|
+
map %w[--version -v] => :__print_version
|
12
|
+
|
13
|
+
# desc "install", "Install Plutonium"
|
14
|
+
# def install
|
15
|
+
# Rails::Generators.invoke("pu:install")
|
16
|
+
# end
|
17
|
+
|
18
|
+
desc "generate, g GENERATOR [options]", "Run plutonium generator"
|
19
|
+
def generate(generator, *options)
|
20
|
+
Rails::Generators.invoke("pu:#{generator}", options)
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "list, ls", "View list of available generators"
|
24
|
+
def list
|
25
|
+
generators = Rails::Generators.sorted_groups.to_h["pu"]
|
26
|
+
puts
|
27
|
+
generators.each { |gen| puts gen.sub(/^pu:/, "") }
|
28
|
+
puts
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "--version, -v", "Print gem version"
|
32
|
+
def __print_version
|
33
|
+
puts "Plutonium generators #{PlutoniumGenerators::VERSION}"
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
37
|
+
def exit_on_failure?
|
38
|
+
true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -64,12 +64,8 @@ module PlutoniumGenerators
|
|
64
64
|
@prompt ||= TTY::Prompt.new
|
65
65
|
end
|
66
66
|
|
67
|
-
def rails?
|
68
|
-
PlutoniumGenerators.rails?
|
69
|
-
end
|
70
|
-
|
71
67
|
def appname
|
72
|
-
|
68
|
+
defined?(Rails.application) ? Rails.application.class.module_parent.name : "PlutoniumGenerators"
|
73
69
|
end
|
74
70
|
|
75
71
|
def app_name
|
@@ -7,7 +7,7 @@ module PlutoniumGenerators
|
|
7
7
|
class ModelGenerator < ActiveRecord::Generators::ModelGenerator
|
8
8
|
include PlutoniumGenerators::Generator
|
9
9
|
|
10
|
-
remove_hook_for :test_framework
|
10
|
+
# remove_hook_for :test_framework
|
11
11
|
remove_task :create_migration_file
|
12
12
|
remove_task :create_model_file
|
13
13
|
remove_task :create_module_file
|
@@ -1,7 +1,15 @@
|
|
1
1
|
require "zeitwerk"
|
2
2
|
|
3
3
|
loader = Zeitwerk::Loader.for_gem # (warn_on_extra_files: false)
|
4
|
+
loader.inflector.inflect(
|
5
|
+
"cli" => "CLI"
|
6
|
+
)
|
4
7
|
loader.setup
|
5
8
|
|
6
9
|
module PlutoniumGenerators
|
10
|
+
class << self
|
11
|
+
def cli?
|
12
|
+
ENV["PU_CLI"] == "1"
|
13
|
+
end
|
14
|
+
end
|
7
15
|
end
|
@@ -9,7 +9,7 @@ module Plutonium
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def permitted_for(policy)
|
12
|
-
Collection.new(@collection.select { |name, action| policy.
|
12
|
+
Collection.new(@collection.select { |name, action| policy.send_with_report :"#{action.name}?" })
|
13
13
|
end
|
14
14
|
|
15
15
|
def collection_actions
|
@@ -42,7 +42,7 @@ module Plutonium
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def permitted_attributes
|
45
|
-
@permitted_attributes ||= current_policy.
|
45
|
+
@permitted_attributes ||= current_policy.send_with_report :"permitted_attributes_for_#{action_name}"
|
46
46
|
end
|
47
47
|
|
48
48
|
def current_policy
|
@@ -52,9 +52,9 @@ module Plutonium
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def parent_policy
|
56
|
-
|
57
|
-
end
|
55
|
+
# def parent_policy
|
56
|
+
# @parent_policy ||= policy(current_parent) if current_parent.present?
|
57
|
+
# end
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Plutonium
|
2
|
+
module Core
|
3
|
+
module Fields
|
4
|
+
module Inputs
|
5
|
+
class NestedInput < Base
|
6
|
+
include Plutonium::Core::Definers::InputDefiner
|
7
|
+
|
8
|
+
attr_reader :inputs, :resource_class
|
9
|
+
|
10
|
+
def initialize(name, inputs:, resource_class:, allow_destroy:, update_only:, limit:, **user_options)
|
11
|
+
@inputs = inputs
|
12
|
+
@resource_class = resource_class
|
13
|
+
@allow_destroy = allow_destroy
|
14
|
+
@update_only = update_only
|
15
|
+
@limit = limit
|
16
|
+
|
17
|
+
super(name, **user_options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def render(view_context, f, record, **opts)
|
21
|
+
opts = options.deep_merge opts
|
22
|
+
view_context.render_component :nested_resource_form_fields, form: f, **opts
|
23
|
+
end
|
24
|
+
|
25
|
+
def collect(params)
|
26
|
+
attributes = {}
|
27
|
+
params[param].each do |index, nested_params|
|
28
|
+
collected = defined_inputs.collect_all(nested_params)
|
29
|
+
collected[:id] = nested_params[:id] if nested_params.key?(:id) && !@update_only
|
30
|
+
collected[:_destroy] = nested_params[:_destroy] if @allow_destroy
|
31
|
+
attributes[index] = collected
|
32
|
+
end
|
33
|
+
|
34
|
+
{param => attributes}
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def param = :"#{name}_attributes"
|
40
|
+
|
41
|
+
def input_options = {
|
42
|
+
name:,
|
43
|
+
resource_class:,
|
44
|
+
allow_destroy: @allow_destroy,
|
45
|
+
update_only: @update_only,
|
46
|
+
limit: @limit,
|
47
|
+
inputs: defined_inputs
|
48
|
+
}
|
49
|
+
|
50
|
+
def defined_inputs
|
51
|
+
@defined_inputs ||= defined_inputs_for(*inputs)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|