oversee 0.2.0 → 0.3.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/oversee_manifest.js +2 -0
  3. data/app/components/oversee/dashboard/filters.rb +23 -19
  4. data/app/components/oversee/dashboard/header.rb +34 -18
  5. data/app/components/oversee/dashboard/index.rb +23 -11
  6. data/app/components/oversee/dashboard/javascript.rb +4 -4
  7. data/app/components/oversee/dashboard/pagination.rb +1 -1
  8. data/app/components/oversee/dashboard/sidebar.rb +38 -1
  9. data/app/components/oversee/dashboard/tailwind.rb +30 -1
  10. data/app/components/oversee/field/display.rb +19 -10
  11. data/app/components/oversee/field/form.rb +4 -23
  12. data/app/components/oversee/field/input/belongs_to.rb +22 -0
  13. data/app/components/oversee/field/input/boolean.rb +1 -11
  14. data/app/components/oversee/field/input/datetime.rb +1 -11
  15. data/app/components/oversee/field/input/integer.rb +1 -11
  16. data/app/components/oversee/field/input/rich_text.rb +18 -0
  17. data/app/components/oversee/field/input/string.rb +1 -11
  18. data/app/components/oversee/field/input.rb +13 -5
  19. data/app/components/oversee/field/label.rb +3 -2
  20. data/app/components/oversee/field/value/belongs_to.rb +21 -0
  21. data/app/components/oversee/field/value/datetime.rb +1 -1
  22. data/app/components/oversee/field/value/rich_text.rb +9 -0
  23. data/app/components/oversee/field/value.rb +11 -5
  24. data/app/components/oversee/layout/application.rb +46 -0
  25. data/app/components/oversee/resources/index.rb +21 -2
  26. data/app/components/oversee/resources/new.rb +7 -3
  27. data/app/components/oversee/resources/show.rb +150 -69
  28. data/app/components/oversee/resources/table.rb +7 -1
  29. data/app/controllers/oversee/dashboard_controller.rb +1 -1
  30. data/app/controllers/oversee/resources/fields_controller.rb +20 -36
  31. data/app/controllers/oversee/resources_controller.rb +22 -22
  32. data/app/javascript/oversee/application.js +3 -0
  33. data/app/javascript/oversee/controllers/index.js +8 -0
  34. data/app/javascript/oversee/controllers/reveal_controller.js +7 -0
  35. data/app/javascript/oversee/controllers/sidebar/state_controller.js +21 -0
  36. data/app/models/oversee/resource.rb +43 -17
  37. data/app/{oversee → service/oversee}/filter.rb +2 -2
  38. data/app/{oversee → service/oversee}/search.rb +1 -1
  39. data/app/views/oversee/base.rb +5 -0
  40. data/config/importmap.rb +14 -0
  41. data/config/routes.rb +16 -10
  42. data/lib/generators/oversee/install_generator.rb +7 -0
  43. data/lib/oversee/engine.rb +19 -0
  44. data/lib/oversee/version.rb +1 -1
  45. data/lib/oversee.rb +12 -0
  46. data/lib/tasks/oversee_tasks.rake +6 -4
  47. metadata +31 -8
  48. data/app/jobs/oversee/application_job.rb +0 -4
  49. data/app/oversee/cards.rb +0 -2
  50. data/app/oversee/resource.rb +0 -10
  51. data/app/views/layouts/oversee/application.html.erb +0 -26
@@ -1,13 +1,19 @@
1
1
  class Oversee::Field::Value < Oversee::Base
2
2
  MAP = {
3
3
  string: Oversee::Field::Value::String,
4
+ belongs_to: Oversee::Field::Value::BelongsTo,
4
5
  boolean: Oversee::Field::Value::Boolean,
5
- integer: Oversee::Field::Value::Integer,
6
6
  datetime: Oversee::Field::Value::Datetime,
7
+ enum: Oversee::Field::Value::Enum,
8
+ integer: Oversee::Field::Value::Integer,
9
+ rich_text: Oversee::Field::Value::RichText,
7
10
  text: Oversee::Field::Value::Text,
8
- enum: Oversee::Field::Value::Enum
9
11
  }
10
12
 
13
+ attr_reader :key
14
+ attr_reader :value
15
+ attr_reader :datatype
16
+
11
17
  def initialize(key: nil, value: nil, datatype: :string, **options)
12
18
  @key = key
13
19
  @value = value
@@ -18,14 +24,14 @@ class Oversee::Field::Value < Oversee::Base
18
24
  end
19
25
 
20
26
  def view_template
21
- return p(class: "text-gray-400 text-xs"){ "—" } if @value.nil?
22
- render component_class.new(key: @key, value: @value)
27
+ return p(class: "text-gray-400 text-xs"){ "—" } if value.nil?
28
+ render component_class.new(key:, value:, **@options)
23
29
  end
24
30
 
25
31
  private
26
32
 
27
33
  def component_class
28
- MAP[@datatype.to_sym] || Oversee::Field::Value::String
34
+ MAP[datatype.to_sym] || Oversee::Field::Value::String
29
35
  end
30
36
 
31
37
  def for_table?
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Oversee::Layout::Application < Oversee::Base
4
+ extend Phlex::Kit
5
+
6
+ include Phlex::Rails::Helpers::CSPMetaTag
7
+ include Phlex::Rails::Helpers::CSRFMetaTags
8
+ include Phlex::Rails::Helpers::StylesheetLinkTag
9
+ include Phlex::Rails::Helpers::JavascriptImportmapTags
10
+
11
+ def view_template
12
+ doctype
13
+ html do
14
+ # render Head
15
+ head do
16
+ csrf_meta_tags
17
+ csp_meta_tag
18
+
19
+ title { "Oversee | #{Oversee.application_name}" }
20
+
21
+ meta(name: "viewport", content: "width=device-width, initial-scale=1.0")
22
+ meta(name: "ROBOTS", content: "NOODP")
23
+
24
+ link(rel: "stylesheet", type: "text/css", href: "https://unpkg.com/trix@2.1.8/dist/trix.css")
25
+
26
+ render Oversee::Dashboard::Javascript.new
27
+ render Oversee::Dashboard::Tailwind.new
28
+ end
29
+
30
+ body(class: "min-h-screen bg-gray-100 p-4") do
31
+ # render Flash.new
32
+
33
+ div(class: "flex gap-4 w-full") do
34
+ div(class: "w-72 shrink-0") { render Oversee::Dashboard::Sidebar.new }
35
+ div(class: "w-full overflow-scroll") do
36
+ div(class: "bg-white rounded-lg overflow-clip p-4") do
37
+ yield
38
+ end
39
+ end
40
+ end
41
+
42
+
43
+ end
44
+ end
45
+ end
46
+ end
@@ -9,12 +9,31 @@ class Oversee::Resources::Index < Oversee::Base
9
9
  end
10
10
 
11
11
 
12
+ def around_template
13
+ render Oversee::Layout::Application.new { super }
14
+ end
15
+
12
16
  def view_template
13
- render Oversee::Dashboard::Header.new(title: @resource_class.to_s, subtitle: "Index") do
14
- a(href: helpers.new_resource_path(@params[:resource_class_name]), class: "inline-flex items-center justify-center size-8 rounded-full bg-emerald-100 text-emerald-500 hover:bg-emerald-200 text-sm font-medium") { render Phlex::Icons::Iconoir::Plus.new(class: "size-4 text-emerald-500") }
17
+ render Oversee::Dashboard::Header.new(title: @resource_class.to_s.pluralize) do |h|
18
+ h.left
19
+ h.right do
20
+ a(
21
+ href: helpers.new_resource_path(@params[:resource_class_name]),
22
+ target: "_top",
23
+ class: "inline-flex items-center justify-center gap-1.5 h-8 px-4 rounded-full bg-transparent text-gray-900 hover:bg-gray-100 text-sm font-medium transition group"
24
+ ) do
25
+ render Phlex::Icons::Iconoir::Plus.new(class: "size-4 text-gray-500 group-hover:text-blue-500", stroke_width: 2.5)
26
+ plain "Add new"
27
+ end
28
+ end
15
29
  end
30
+ hr(class: "my-4")
31
+
16
32
  render Oversee::Dashboard::Filters.new(params: @params)
33
+
34
+ hr(class: "mt-4")
17
35
  render Oversee::Resources::Table.new(resource_class: @resource_class, resources: @resources, params: @params)
36
+ hr()
18
37
  render Oversee::Dashboard::Pagination.new(pagy: @pagy, params: @params)
19
38
  end
20
39
 
@@ -7,11 +7,15 @@ class Oversee::Resources::New < Oversee::Base
7
7
  @params = params
8
8
  end
9
9
 
10
+ def around_template
11
+ render Oversee::Layout::Application.new { super }
12
+ end
13
+
10
14
  def view_template
11
15
  render Oversee::Dashboard::Header.new(title: @resource_class.to_s, subtitle: "Creating new record")
12
16
 
13
- div(class: "p-8") do
14
- render Oversee::Resources::Form.new(resource: @resource)
15
- end
17
+ hr(class: "my-4")
18
+
19
+ render Oversee::Resources::Form.new(resource: @resource)
16
20
  end
17
21
  end
@@ -4,104 +4,166 @@ class Oversee::Resources::Show < Oversee::Base
4
4
  include Phlex::Rails::Helpers::ButtonTo
5
5
  include Phlex::Rails::Helpers::TurboFrameTag
6
6
 
7
+
8
+ attr_reader :resource
9
+ attr_reader :resource_class
10
+ attr_reader :resource_associations
11
+
7
12
  def initialize(resource:, resource_class:, resource_associations:, params:)
8
13
  @resource = resource
9
14
  @resource_class = resource_class
10
15
  @resource_associations = resource_associations
11
16
  @params = params
12
- @oversee_resource = Oversee::Resource.new(resource_class: @resource_class, resource: @resource)
17
+
18
+ @oversee_resource = Oversee::Resource.new(resource_class: @resource_class, instance: @resource)
13
19
  end
14
20
 
21
+ def around_template
22
+ render Oversee::Layout::Application.new { super }
23
+ end
15
24
 
16
25
  def view_template
17
- render Oversee::Dashboard::Header.new(title: @resource_class.to_s, subtitle: "##{@resource.id}", return_path: helpers.resources_path(resource_class_name: @params[:resource_class_name])) do
18
- button_to(helpers.resource_path(resource_class_name: @params[:resource_class_name]), method: :delete, data: { turbo_confirm: "Are you sure?" }, class: "size-8 inline-flex items-center justify-center rounded-full text-rose-500 bg-rose-50 hover:bg-rose-100 text-sm font-medium transition-colors") { render Phlex::Icons::Iconoir::Trash.new(class: "size-4") }
26
+ render Oversee::Dashboard::Header.new(title: @resource_class.to_s.pluralize) do |h|
27
+ h.left do
28
+ h.separator
29
+ div(class: "inline-flex items-center gap-1 text-sm bg-gray-100 text-gray-600 h-6 px-2") do
30
+ render Phlex::Icons::Iconoir::Hashtag.new(class: "size-2.5 text-gray-500", stroke_width: 2)
31
+ span { @resource.to_param }
32
+ end
33
+ end
34
+ h.right do
35
+ details(class: "relative inline-block") do
36
+ summary(class: "cursor-pointer list-none") do
37
+ div(class: "inline-flex items-center justify-center size-8 hover:bg-indigo-50 transition") do
38
+ render Phlex::Icons::Iconoir::MoreHorizCircle.new(class: "size-4 text-gray-500")
39
+ end
40
+ end
41
+ ul(
42
+ class:
43
+ "absolute p-2 mt-2 right-0 top-full min-w-40 overflow-hidden rounded-lg bg-white border border-b-2 border-gray-200/75 divide-y text-xs text-gray-500 font-medium"
44
+ ) do
45
+ li(class: "w-full") do
46
+ button_to(helpers.resource_path(resource_class_name: @params[:resource_class_name]), method: :delete, data: { turbo_confirm: "Are you sure?" }, class: "p-1 hover:bg-gray-50 w-full flex items-center gap-2 transition duration-100") do
47
+ div(class: "inline-flex items-center justify-center size-6 bg-gray-100") do
48
+ render Phlex::Icons::Iconoir::Trash.new(class: "size-3 text-gray-500")
49
+ end
50
+ plain "Delete"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
19
56
  end
20
57
 
21
- div(class: "p-8") do
22
- @resource_class.columns_hash.each do |key, metadata|
23
- div(class: "py-4") do
24
- div(class: "space-y-2") do
25
- render Oversee::Field::Label.new(key: key, datatype: metadata.sql_type_metadata.type)
26
- div(id: dom_id(@resource, :"#{key}_row"), class: "flex items-center gap-2 mt-4") do
27
- render Oversee::Field::Display.new(resource: @resource, key: key, datatype: metadata.sql_type_metadata.type)
28
- # div(id: dom_id(@resource, :"#{key}_actions")) do
29
- # div(class: "bg-white text-gray-400 size-9 aspect-square inline-flex items-center justify-center"){ render Phlex::Icons::Iconoir::Copy.new(class: "size-5", stroke_width: 1.75) }
30
- # end
58
+ hr(class: "my-4")
59
+
60
+
61
+
62
+
63
+ # COLUMNS
64
+ @resource_class.columns_hash.each do |key, metadata|
65
+ next if @oversee_resource.foreign_keys.include?(key.to_s)
66
+
67
+ div(class: "py-4") do
68
+ div(class: "space-y-2") do
69
+ render Oversee::Field::Label.new(key: key, datatype: metadata.sql_type_metadata.type)
70
+ div(id: dom_id(@resource, :"#{key}_row"), class: "flex items-center gap-2 mt-4") do
71
+ render Oversee::Field::Display.new(resource:, key:, value: @resource.send(key), datatype: metadata.sql_type_metadata.type)
72
+ # div(id: dom_id(@resource, :"#{key}_actions")) do
73
+ # button(class: "bg-gray-100 hover:bg-gray-200 text-gray-400 hover:text-blue-500 size-10 aspect-square inline-flex items-center justify-center transition-colors") { render Phlex::Icons::Iconoir::Copy.new(class: "size-4") }
74
+ # end
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ hr(class: "my-4")
81
+
82
+ # RICH TEXT Associations
83
+ if !!rich_text_associations.length
84
+ rich_text_associations.each do |association|
85
+
86
+ # Remove the "rich_text_" prefix from the association name
87
+ key = association[:name].to_s[10..].to_sym
88
+
89
+ div do
90
+ div(class: "space-y-4") do
91
+ div(class:"flex items-center gap-2") do
92
+ render Oversee::Field::Label.new(key: key.to_s.titleize, datatype: :rich_text)
93
+ a(href: helpers.resources_path(resource_class_name: association[:class_name].to_s), class: "hover:text-blue-500") { render Phlex::Icons::Iconoir::ArrowUpRight.new(class: "size-3") }
94
+ end
95
+
96
+ div(id: dom_id(@resource, :"#{key.to_s}_row"), class: "flex items-center gap-2 mt-4") do
97
+ render Oversee::Field::Display.new(resource:, key:, value: @resource.send(key).to_plain_text[..196], datatype: :rich_text)
31
98
  end
32
99
  end
33
100
  end
34
101
  end
102
+ end
35
103
 
36
- # BELONGS_TO Associations
37
- if !!belongs_to_associations.length
38
- belongs_to_associations.each do |association|
39
- div(class: "py-6") do
40
- div(class: "space-y-4") do
41
- div(class:"flex items-center gap-2") do
42
- render Oversee::Field::Label.new(key: association[:name].to_s.titleize, datatype: :data)
43
- a(href: helpers.resources_path(resource_class_name: association[:class_name].to_s), class: "hover:text-blue-500") { render Phlex::Icons::Iconoir::ArrowUpRight.new(class: "size-3") }
44
- end
104
+ # BELONGS_TO Associations
105
+ if !!belongs_to_associations.length
106
+ belongs_to_associations.each do |association|
107
+ div(class: "py-6") do
108
+ div(class: "space-y-4") do
109
+ div(class:"flex items-center gap-2") do
110
+ render Oversee::Field::Label.new(key: association[:name].to_s.titleize, datatype: :data)
111
+ a(href: helpers.resources_path(resource_class_name: association[:class_name].to_s), class: "hover:text-blue-500") { render Phlex::Icons::Iconoir::ArrowUpRight.new(class: "size-3") }
112
+ end
45
113
 
46
- div(class: "flex items-center gap-2 flex-wrap") do
47
- foreign_key_value = @resource[association[:foreign_key]]
48
- path = !!foreign_key_value ? helpers.resource_path(id: foreign_key_value, resource_class_name: association[:class_name]) : helpers.resources_path(resource_class_name: association[:class_name])
49
-
50
- a(
51
- href: path,
52
- class:
53
- "inline-flex items-center gap-2 text-xs border border-transparent bg-gray-100 hover:bg-gray-200 px-3 py-1.5"
54
- ) do
55
- plain "#{association[:class_name]} | #{foreign_key_value}"
56
- span { render Phlex::Icons::Iconoir::ArrowUpRight.new(class: "size-3") }
57
- end
114
+ foreign_key = association[:foreign_key]
115
+ foreign_key_value = @resource[association[:foreign_key]]
116
+ path = !!foreign_key_value ? helpers.resource_path(id: foreign_key_value, resource_class_name: association[:class_name]) : helpers.resources_path(resource_class_name: association[:class_name])
117
+
118
+ div(id: dom_id(@resource, :"#{foreign_key}_row"), class: "flex items-center gap-2 mt-4") do
119
+ render Oversee::Field::Display.new(resource:, key: foreign_key, value: foreign_key_value, datatype: :belongs_to, display_key: true)
120
+ div(id: dom_id(@resource, :"#{foreign_key}_actions")) do
121
+ a(href: path, class: "bg-gray-100 hover:bg-gray-200 text-gray-400 hover:text-blue-500 size-10 aspect-square inline-flex items-center justify-center transition-colors"){ render Phlex::Icons::Iconoir::ArrowUpRight.new(class: "size-4") }
58
122
  end
59
123
  end
60
124
  end
61
125
  end
62
126
  end
127
+ end
128
+
129
+ hr(class: "my-4")
63
130
 
64
- # HAS_MANY Associations
65
- if !!has_many_associations.length
131
+ # HAS_MANY Associations
132
+ if !!has_many_associations.length
133
+ div(class: "flex flex-col gap-8") do
66
134
  has_many_associations.each do |association|
67
135
  associated_resources = @resource.send(association[:name])
68
136
  associated_resource_class = association[:class_name].constantize
69
137
 
70
- div(class: "py-6") do
71
- div(class: "space-y-4") do
72
- div(class:"flex items-center gap-2") do
73
- render Oversee::Field::Label.new(key: association[:name].to_s.titleize, datatype: :data)
74
- a(href: helpers.resources_path(resource_class_name: association[:class_name]), class: "hover:text-blue-500") { render Phlex::Icons::Iconoir::ArrowUpRight.new(class: "size-3") }
75
- end
138
+ div(class: "space-y-4") do
139
+ div(class:"flex items-center gap-2") do
140
+ render Oversee::Field::Label.new(key: association[:name].to_s.titleize, datatype: :data)
141
+ a(href: helpers.resources_path(resource_class_name: association[:class_name]), class: "hover:text-blue-500") { render Phlex::Icons::Iconoir::ArrowUpRight.new(class: "size-3") }
142
+ end
76
143
 
77
- div(class: "bg-gray-50 p-2") do
78
- if associated_resources.present?
79
- div(class: "bg-white") do
80
- # turbo_frame_tag(
81
- # dom_id(associated_resource_class, :table),
82
- # src: helpers.resources_table_path(
83
- # resource_class_name: association[:class_name],
84
- # filters: { eq: { association[:foreign_key] => [@resource.id] } }
85
- # ),
86
- # loading: :lazy,
87
- # data: { turbo_stream: true }
88
- # ) do
89
- # div(class: "h-20 flex items-center justify-center") { render Phlex::Icons::Iconoir::DatabaseSearch.new(class: "animate-pulse size-6 text-gray-600") }
90
- # end
91
-
92
- #
93
- render Oversee::Resources::Table.new(
94
- resources: associated_resources,
95
- resource_class: associated_resource_class,
96
- params: @params
97
- )
98
- end
99
- else
100
- p(class: "bg-gray-50 p-2 pr-4 flex gap-2 items-center text-xs") {
101
- render Phlex::Icons::Iconoir::DatabaseSearch.new(class: "size-3")
102
- plain "No #{association[:name].to_s.titleize.downcase} found"
103
- }
144
+ div(class: "bg-gray-50 p-2") do
145
+ # turbo_frame_tag(
146
+ # dom_id(associated_resource_class, :table),
147
+ # src: helpers.resources_table_path(resources_table_params(association)),
148
+ # loading: :lazy,
149
+ # data: { turbo_stream: true }
150
+ # ) do
151
+ # div(class: "h-20 flex items-center justify-center") { render Phlex::Icons::Iconoir::DatabaseSearch.new(class: "animate-pulse size-6 text-gray-600") }
152
+ # end
153
+
154
+ if associated_resources.present?
155
+ div(class: "bg-white") do
156
+ render Oversee::Resources::Table.new(
157
+ resources: associated_resources,
158
+ resource_class: associated_resource_class,
159
+ params: @params
160
+ )
104
161
  end
162
+ else
163
+ p(class: "bg-gray-50 p-2 pr-4 flex gap-2 items-center text-xs") {
164
+ render Phlex::Icons::Iconoir::DatabaseSearch.new(class: "size-3")
165
+ plain "No #{association[:name].to_s.titleize.downcase} found"
166
+ }
105
167
  end
106
168
  end
107
169
  end
@@ -112,6 +174,10 @@ class Oversee::Resources::Show < Oversee::Base
112
174
 
113
175
  private
114
176
 
177
+ def rich_text_associations
178
+ @oversee_resource.rich_text_associations
179
+ end
180
+
115
181
  def belongs_to_associations
116
182
  @oversee_resource.associations[:belongs_to]
117
183
  end
@@ -123,4 +189,19 @@ class Oversee::Resources::Show < Oversee::Base
123
189
  def has_associations?
124
190
  @resource_associations.present?
125
191
  end
192
+
193
+ def resources_table_params(association)
194
+ # if association[:through].nil?
195
+ # return { association[:foreign_key] => { eq: [@resource.id] } }
196
+ # else
197
+ # keys = @resource.send(association[:through]).pluck(association[:foreign_key])
198
+ # return { @resource_class.primary_key => { eq: keys } }
199
+ # end
200
+
201
+ {
202
+ resource_class_name: association[:class_name],
203
+ association_name: association[:through],
204
+ filters: { association[:foreign_key] => { eq: [@resource.id] } }
205
+ }
206
+ end
126
207
  end
@@ -8,16 +8,19 @@ class Oversee::Resources::Table < Oversee::Base
8
8
  @resource_class = resource_class || resources.first.class
9
9
  @params = params
10
10
  @options = options
11
+
12
+ @oversee_resource = Oversee::Resource.new(resource_class: @resource_class)
11
13
  end
12
14
 
13
15
  def view_template
14
- turbo_frame_tag dom_id(@resource_class, :table), target: :_top do
16
+ turbo_frame_tag dom_id(@resource_class, :table), target: "_top" do
15
17
  render Oversee::Table.new do |table|
16
18
  table.head do |head|
17
19
  head.row do
18
20
  th(scope: "col", class: "px-4 py-3 text-left text-xs text-gray-900 uppercase")
19
21
  # Attributes
20
22
  @resource_class.columns_hash.each do |key, metadata|
23
+ next if @oversee_resource.foreign_keys.include?(key.to_s)
21
24
  th(scope: "col", class: "text-left text-xs text-gray-900 uppercase whitespace-nowrap hover:bg-gray-50 transition relative") do
22
25
  a(
23
26
  href:
@@ -29,6 +32,7 @@ class Oversee::Resources::Table < Oversee::Base
29
32
  @params[:sort_direction] == "asc" ? :desc : :asc
30
33
  )
31
34
  ),
35
+ target: "_top",
32
36
  class: "px-4 py-3 flex items-center justify-between gap-2 w-full h-full hover:text-gray-900 transition-colors"
33
37
  ) do
34
38
  render Oversee::Field::Label.new(key: key, datatype: metadata.sql_type_metadata.type)
@@ -52,6 +56,7 @@ class Oversee::Resources::Table < Oversee::Base
52
56
 
53
57
  table.body do |body|
54
58
  @resources.each do |resource|
59
+
55
60
  body.row do |row|
56
61
  td do
57
62
  div(class: "flex space-x-2 mx-4") do
@@ -70,6 +75,7 @@ class Oversee::Resources::Table < Oversee::Base
70
75
  end
71
76
 
72
77
  @resource_class.columns_hash.each do |key, metadata|
78
+ next if @oversee_resource.foreign_keys.include?(key.to_s)
73
79
  row.data do
74
80
  div(class: "max-w-96") do
75
81
  render Oversee::Field::Value.new(datatype: metadata.sql_type_metadata.type, value: resource.send(key), key: key)
@@ -1,7 +1,7 @@
1
1
  module Oversee
2
2
  class DashboardController < BaseController
3
3
  def index
4
- render Oversee::Dashboard::Index.new
4
+ render Oversee::Dashboard::Index.new, layout: false
5
5
  end
6
6
 
7
7
  def show
@@ -1,44 +1,28 @@
1
- module Oversee
2
- module Resources
3
- class FieldsController < BaseController
4
- before_action :set_resource_class
1
+ class Oversee::Resources::FieldsController < Oversee::ResourcesController
2
+ # Renders the display field for a resource
3
+ def show
4
+ end
5
5
 
6
- def update
7
- @resource_class = params[:resource_class].constantize
8
- @resource = @resource_class.find(params[:id])
9
- # @datatype = @resource_class.columns_hash[@key.to_s].type
6
+ # Renders the input field for a resource
7
+ def input
8
+ set_resource
10
9
 
11
- respond_to do |format|
12
- if @resource.update(resource_params)
13
- format.html { redirect_to resource_path(@resource, resource: @resource_class) }
14
- format.turbo_stream
15
- else
16
- end
17
- end
18
- end
19
-
20
- # Non-standard actions
21
- def edit
22
- @resource = @resource_class.find(params[:id])
23
- @key = params[:key].to_sym
24
- @value = @resource.send(@key)
25
- @datatype = @resource.class.columns_hash[@key.to_s].type
26
- puts "---"
27
- puts "key: #{@key}"
28
- puts "value: #{@value}"
29
- puts "datatype: #{@datatype}"
30
- puts "---"
10
+ key = params[:key].to_sym
11
+ value = params[:value] || @resource.send(key)
12
+ datatype = params[:datatype] || @resource.class.columns_hash[key.to_s].type
31
13
 
32
- end
14
+ # puts "---" * 30
15
+ # puts "key: #{key}"
16
+ # puts "value: #{value}"
17
+ # puts "datatype: #{datatype}"
18
+ # puts "---" * 30
33
19
 
34
- private
35
-
36
- def set_resource_class
37
- @resource_class = params[:resource_class].constantize
38
- end
20
+ field_dom_id = dom_id(@resource, key)
21
+ field = Oversee::Field::Form.new(resource: @resource, datatype:, key:, value:)
39
22
 
40
- def resource_params
41
- params.require(:resource).permit!
23
+ respond_to do |format|
24
+ format.turbo_stream do
25
+ render turbo_stream: turbo_stream.replace(field_dom_id, field)
42
26
  end
43
27
  end
44
28
  end
@@ -3,8 +3,8 @@ module Oversee
3
3
  include ActionView::RecordIdentifier
4
4
 
5
5
  before_action :set_resource_class
6
- before_action :set_resource, only: %i[show edit update destroy input_field]
7
- before_action :set_resources, only: %i[index table]
6
+ before_action :set_resource, only: %i[show edit update destroy]
7
+ before_action :set_resources, only: %i[index]
8
8
 
9
9
  def index
10
10
  @pagy, @resources = pagy(@resources, limit: params[:per_page] || Oversee.configuration.per_page)
@@ -14,7 +14,7 @@ module Oversee
14
14
  resource_class: @resource_class,
15
15
  pagy: @pagy,
16
16
  params: params
17
- )
17
+ ), layout: false
18
18
  end
19
19
 
20
20
  def new
@@ -23,7 +23,7 @@ module Oversee
23
23
  resource: @resource,
24
24
  resource_class: @resource_class,
25
25
  params: params
26
- )
26
+ ), layout: false
27
27
  end
28
28
 
29
29
  def create
@@ -46,7 +46,7 @@ module Oversee
46
46
  resource_class: @resource_class,
47
47
  resource_associations: resource_associations,
48
48
  params: params
49
- )
49
+ ), layout: false
50
50
  end
51
51
 
52
52
  def edit
@@ -73,25 +73,25 @@ module Oversee
73
73
  redirect_to resources_path(resource: @resource_class)
74
74
  end
75
75
 
76
- # Non-standard actions
77
- def input_field
78
- set_resource
79
-
80
- key = params[:key].to_sym
81
- value = @resource.send(key)
82
- datatype = @resource.class.columns_hash[key.to_s].type
83
-
84
- field_dom_id = dom_id(@resource, key)
85
- field = Oversee::Field::Form.new(resource: @resource, datatype:, key:, value:)
76
+ def association
77
+ @resources = @resource_class.find(params[:id]).send(params[:association_name])
78
+ @pagy, @resources = pagy(@resources, limit: params[:per_page] || Oversee.configuration.per_page)
86
79
 
87
- respond_to do |format|
88
- format.turbo_stream do
89
- render turbo_stream: turbo_stream.replace(field_dom_id, field)
90
- end
91
- end
80
+ render Oversee::Resources::Index.new(
81
+ resources: @resources,
82
+ resource_class: @resource_class,
83
+ pagy: @pagy,
84
+ params: params
85
+ )
92
86
  end
93
87
 
94
88
  def table
89
+ if params[:association_name].present?
90
+ @resources = @resource_class.find(params[:id]).send(params[:association_name])
91
+ else
92
+ set_resources
93
+ end
94
+
95
95
  component_id = dom_id(@resource_class, :table)
96
96
  component = Oversee::Resources::Table.new(resource_class: @resource_class, resources: @resources, params: params)
97
97
 
@@ -119,8 +119,8 @@ module Oversee
119
119
  set_sorting_rules
120
120
 
121
121
  @resources = @resource_class.order(@sort_attribute.to_sym => sort_direction)
122
- @resources = Filter.new(collection: @resources, params:).apply
123
- @resources = Search.new(collection: @resources, resource_class: @resource_class, query: params[:query]).call
122
+ @resources = Oversee::Filter.new(collection: @resources, params:).apply
123
+ @resources = Oversee::Search.new(collection: @resources, resource_class: @resource_class, query: params[:query]).call
124
124
  end
125
125
 
126
126
  def resource_associations
@@ -0,0 +1,3 @@
1
+ import "trix";
2
+ import "@rails/actiontext";
3
+ import "controllers";
@@ -0,0 +1,8 @@
1
+ import { Application } from "@hotwired/stimulus";
2
+ const application = Application.start();
3
+
4
+ application.debug = false;
5
+ window.Stimulus = application;
6
+
7
+ import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading";
8
+ eagerLoadControllersFrom("controllers", application);
@@ -0,0 +1,7 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ console.log("Hello from reveal_controller.js");
6
+ }
7
+ }
@@ -0,0 +1,21 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ const KEY_BASE = "oversee-sidebar";
4
+
5
+ export default class extends Controller {
6
+ initialize() {
7
+ this.key = `${KEY_BASE}--${this.element.id}`;
8
+ this.expanded = localStorage.getItem(this.key) === "true";
9
+ this.element.open = this.expanded;
10
+ }
11
+
12
+ toggle() {
13
+ this.expanded = !this.expanded;
14
+ this.element.open = this.expanded;
15
+ }
16
+
17
+ persist(event) {
18
+ this.expanded = event.newState === "open";
19
+ localStorage.setItem(this.key, this.expanded);
20
+ }
21
+ }