oversee 0.2.0 → 0.3.1

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -3
  3. data/app/assets/config/oversee_manifest.js +2 -0
  4. data/app/components/oversee/dashboard/actions.rb +58 -0
  5. data/app/components/oversee/dashboard/filter.rb +12 -0
  6. data/app/components/oversee/dashboard/filters.rb +5 -51
  7. data/app/components/oversee/dashboard/header.rb +34 -18
  8. data/app/components/oversee/dashboard/index.rb +23 -11
  9. data/app/components/oversee/dashboard/javascript.rb +4 -4
  10. data/app/components/oversee/dashboard/pagination.rb +1 -1
  11. data/app/components/oversee/dashboard/sidebar.rb +38 -1
  12. data/app/components/oversee/dashboard/tailwind.rb +30 -1
  13. data/app/components/oversee/field/display.rb +12 -21
  14. data/app/components/oversee/field/form.rb +5 -37
  15. data/app/components/oversee/field/input/belongs_to.rb +5 -0
  16. data/app/components/oversee/field/input/boolean.rb +3 -18
  17. data/app/components/oversee/field/input/date.rb +5 -0
  18. data/app/components/oversee/field/input/datetime.rb +2 -17
  19. data/app/components/oversee/field/input/integer.rb +2 -17
  20. data/app/components/oversee/field/input/json.rb +5 -0
  21. data/app/components/oversee/field/input/rich_text.rb +10 -0
  22. data/app/components/oversee/field/input/string.rb +2 -17
  23. data/app/components/oversee/field/input.rb +13 -11
  24. data/app/components/oversee/field/label.rb +16 -15
  25. data/app/components/oversee/field/set.rb +36 -0
  26. data/app/components/oversee/field/value/belongs_to.rb +15 -0
  27. data/app/components/oversee/field/value/boolean.rb +2 -47
  28. data/app/components/oversee/field/value/date.rb +5 -0
  29. data/app/components/oversee/field/value/datetime.rb +2 -6
  30. data/app/components/oversee/field/value/enum.rb +2 -6
  31. data/app/components/oversee/field/value/integer.rb +2 -6
  32. data/app/components/oversee/field/value/json.rb +6 -0
  33. data/app/components/oversee/field/value/rich_text.rb +5 -0
  34. data/app/components/oversee/field/value/string.rb +3 -10
  35. data/app/components/oversee/field/value/text.rb +2 -6
  36. data/app/components/oversee/field/value.rb +14 -5
  37. data/app/components/oversee/field.rb +42 -0
  38. data/app/components/oversee/flash.rb +39 -0
  39. data/app/components/oversee/layout/application.rb +46 -0
  40. data/app/components/oversee/resources/index.rb +22 -3
  41. data/app/components/oversee/resources/new.rb +7 -3
  42. data/app/components/oversee/resources/show.rb +139 -68
  43. data/app/components/oversee/resources/table.rb +8 -2
  44. data/app/controllers/oversee/dashboard_controller.rb +1 -1
  45. data/app/controllers/oversee/resources/fields_controller.rb +24 -36
  46. data/app/controllers/oversee/resources_controller.rb +29 -24
  47. data/app/javascript/oversee/application.js +3 -0
  48. data/app/javascript/oversee/controllers/clipboard_controller.js +21 -0
  49. data/app/javascript/oversee/controllers/index.js +9 -0
  50. data/app/javascript/oversee/controllers/notification_controller.js +17 -0
  51. data/app/javascript/oversee/controllers/reveal_controller.js +19 -0
  52. data/app/javascript/oversee/controllers/sidebar/state_controller.js +21 -0
  53. data/app/models/oversee/resource.rb +49 -20
  54. data/app/{oversee → service/oversee}/filter.rb +2 -2
  55. data/app/{oversee → service/oversee}/search.rb +1 -1
  56. data/app/views/oversee/base.rb +5 -0
  57. data/config/importmap.rb +14 -0
  58. data/config/routes.rb +16 -10
  59. data/lib/generators/oversee/install_generator.rb +7 -0
  60. data/lib/oversee/engine.rb +19 -0
  61. data/lib/oversee/version.rb +1 -1
  62. data/lib/oversee.rb +13 -0
  63. data/lib/tasks/oversee_tasks.rake +6 -4
  64. metadata +71 -9
  65. data/app/jobs/oversee/application_job.rb +0 -4
  66. data/app/oversee/cards.rb +0 -2
  67. data/app/oversee/resource.rb +0 -10
  68. data/app/views/layouts/oversee/application.html.erb +0 -26
@@ -1,21 +1,20 @@
1
- class Oversee::Field::Input < Oversee::Base
1
+ class Oversee::Field::Input < Oversee::Field
2
2
  MAP = {
3
- string: Oversee::Field::Input::String,
3
+ belongs_to: Oversee::Field::Input::BelongsTo,
4
4
  boolean: Oversee::Field::Input::Boolean,
5
- integer: Oversee::Field::Input::Integer,
5
+ date: Oversee::Field::Input::Date,
6
6
  datetime: Oversee::Field::Input::Datetime,
7
+ enum: Oversee::Field::Input::String,
8
+ integer: Oversee::Field::Input::Integer,
9
+ json: Oversee::Field::Input::Json,
10
+ jsonb: Oversee::Field::Input::Json,
11
+ rich_text: Oversee::Field::Input::RichText,
12
+ string: Oversee::Field::Input::String,
7
13
  text: Oversee::Field::Input::String,
8
- enum: Oversee::Field::Input::String
9
14
  }
10
15
 
11
- def initialize(key: nil, value: nil, datatype: :string)
12
- @key = key
13
- @value = value
14
- @datatype = datatype
15
- end
16
-
17
16
  def view_template
18
- render component_class.new(key: @key, value: @value)
17
+ render component_class.new(key:, value:, **@options)
19
18
  end
20
19
 
21
20
  private
@@ -23,4 +22,7 @@ class Oversee::Field::Input < Oversee::Base
23
22
  def component_class
24
23
  MAP[@datatype.to_sym] || Oversee::Field::Input::String
25
24
  end
25
+
26
+ private
27
+
26
28
  end
@@ -1,24 +1,25 @@
1
- class Oversee::Field::Label < Oversee::Base
1
+ class Oversee::Field::Label < Oversee::Field
2
2
  ICON_MAP = {
3
- string: Phlex::Icons::Iconoir::Text,
4
- text: Phlex::Icons::Iconoir::TextSquare,
5
- integer: Phlex::Icons::Iconoir::Number0Square,
6
- datetime: Phlex::Icons::Iconoir::Calendar,
7
3
  boolean: Phlex::Icons::Iconoir::SwitchOn,
8
4
  data: Phlex::Icons::Iconoir::Page,
5
+ date: Phlex::Icons::Iconoir::Calendar,
6
+ datetime: Phlex::Icons::Iconoir::Calendar,
7
+ integer: Phlex::Icons::Iconoir::Number0Square,
8
+ json: Phlex::Icons::Iconoir::CodeBracketsSquare,
9
+ jsonb: Phlex::Icons::Iconoir::CodeBracketsSquare,
10
+ rich_text: Phlex::Icons::Iconoir::TextSquare,
11
+ string: Phlex::Icons::Iconoir::Text,
12
+ text: Phlex::Icons::Iconoir::TextSquare,
9
13
  }
10
14
 
11
- def initialize(datatype: :string, key: nil)
12
- @datatype = datatype
13
- @key = key
14
- end
15
-
16
15
  def view_template
17
- div(class:"inline-flex items-center space-x-2") do
18
- div(class: "size-5 bg-gray-100 inline-flex items-center justify-center") do
19
- render ICON_MAP[@datatype] ? ICON_MAP[@datatype].new(class: "size-3") : ICON_MAP[:data].new(class: "size-3")
20
- end
21
- label(class: "uppercase text-xs text-gray-š00 font-medium block") { @key.to_s.humanize(keep_id_suffix: true) }
16
+ div(id: "#{key}_label", class:"inline-flex items-center space-x-2") do
17
+ div(class: "size-5 bg-gray-100 inline-flex items-center justify-center") { render icon.new(class: "size-3") }
18
+ label(class: "uppercase text-xs text-gray-700 font-medium block cursor-auto", for: key) { key.to_s.humanize(keep_id_suffix: true) }
22
19
  end
23
20
  end
21
+
22
+ def icon
23
+ ICON_MAP[datatype&.to_sym] || ICON_MAP[:data]
24
+ end
24
25
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Oversee::Field::Set < Oversee::Field
4
+ def view_template
5
+ div(id: dom_id(resource, key), class:"flex flex-col gap-2") do
6
+ div(class:"flex items-center justify-between h-10 gap-4") do
7
+ render Oversee::Field::Label.new(key:, datatype:)
8
+ button(type: :submit, class: "bg-black text-white text-xs font-medium px-6 py-2 hover:opacity-75 transition-opacity", form: field_form_id) { "Save" } if state == :input
9
+ end
10
+ div(class: "flex items-center justify-between gap-2") { send("#{state}_state") }
11
+ end
12
+ end
13
+
14
+ def value_state
15
+ render Oversee::Field::Display.new(resource:, key:, value:, datatype:, **@options)
16
+ div(id: dom_id(@resource, :"#{key}_actions")) do
17
+ button(
18
+ 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",
19
+ data: { controller: "clipboard", action: "click->clipboard#copy", clipboard_content_value: value.to_s }
20
+ ) do
21
+ span(class: "hidden", data: { clipboard_target: "successIcon"}) { render Phlex::Icons::Iconoir::Check.new(class: "size-4 text-emerald-500", stroke_width: 1.75) }
22
+ span(data: { clipboard_target: "copyIcon"}) { render Phlex::Icons::Iconoir::Copy.new(class: "size-4", stroke_width: 1.75) }
23
+ end
24
+ end
25
+ end
26
+
27
+ def input_state
28
+ render Oversee::Field::Form.new(resource: @resource, datatype:, key:, value:)
29
+ end
30
+
31
+ private
32
+
33
+ def state
34
+ @state ||= @options[:state] || :value
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ class Oversee::Field::Value::BelongsTo < Oversee::Field::Value
2
+ def view_template
3
+ p(title: value, class:"inline-flex items-center gap-1") do
4
+ if display_key?
5
+ span { key.humanize }
6
+ span {"|"}
7
+ end
8
+ span { value }
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def display_key? = !!@options[:display_key]
15
+ end
@@ -1,50 +1,5 @@
1
- class Oversee::Field::Value::Boolean < Phlex::HTML
2
- def initialize(key: nil, value: nil, kind: :value)
3
- @value = value
4
- end
5
-
1
+ class Oversee::Field::Value::Boolean < Oversee::Field::Value
6
2
  def view_template
7
- @value ? check_icon : x_icon
8
- end
9
-
10
- private
11
-
12
- def check_icon
13
- svg(
14
- stroke_width: "2",
15
- viewbox: "0 0 24 24",
16
- fill: "none",
17
- xmlns: "http://www.w3.org/2000/svg",
18
- color: "currentColor",
19
- class: "size-4 text-emerald-500"
20
- ) do |s|
21
- s.path(
22
- d: "M5 13L9 17L19 7",
23
- stroke: "currentColor",
24
- stroke_width: "2",
25
- stroke_linecap: "round",
26
- stroke_linejoin: "round"
27
- )
28
- end
29
- end
30
-
31
- def x_icon
32
- svg(
33
- stroke_width: "1.5",
34
- viewbox: "0 0 24 24",
35
- fill: "none",
36
- xmlns: "http://www.w3.org/2000/svg",
37
- color: "currentColor",
38
- class: "size-4 text-rose-500"
39
- ) do |s|
40
- s.path(
41
- d:
42
- "M6.75827 17.2426L12.0009 12M17.2435 6.75736L12.0009 12M12.0009 12L6.75827 6.75736M12.0009 12L17.2435 17.2426",
43
- stroke: "currentColor",
44
- stroke_width: "1.5",
45
- stroke_linecap: "round",
46
- stroke_linejoin: "round"
47
- )
48
- end
3
+ render value ? Phlex::Icons::Iconoir::Check.new(class: "size-4 text-emerald-500") : Phlex::Icons::Iconoir::Xmark.new(class: "size-4 text-rose-500")
49
4
  end
50
5
  end
@@ -0,0 +1,5 @@
1
+ class Oversee::Field::Value::Date < Oversee::Field::Value
2
+ def view_template
3
+ time(title: value.to_s) { value&.to_fs(:long) }
4
+ end
5
+ end
@@ -1,9 +1,5 @@
1
- class Oversee::Field::Value::Datetime < Phlex::HTML
2
- def initialize(key: nil, value: nil, kind: :value)
3
- @value = value
4
- end
5
-
1
+ class Oversee::Field::Value::Datetime < Oversee::Field::Value
6
2
  def view_template
7
- time(title: @value) { @value&.to_fs(:long) || "N/A" }
3
+ time(title: value.to_s) { value&.to_fs(:long) || "N/A" }
8
4
  end
9
5
  end
@@ -1,9 +1,5 @@
1
- class Oversee::Field::Value::Enum < Phlex::HTML
2
- def initialize(key: nil, value: nil, kind: :value)
3
- @value = value
4
- end
5
-
1
+ class Oversee::Field::Value::Enum < Oversee::Field::Value
6
2
  def view_template
7
- p(class:"inline-flex px-2 py-1 text-red-500") { @value.to_s }
3
+ p(class:"inline-flex px-2 py-1 text-red-500") { value.to_s }
8
4
  end
9
5
  end
@@ -1,9 +1,5 @@
1
- class Oversee::Field::Value::Integer < Phlex::HTML
2
- def initialize(key: nil, value: nil, kind: :value)
3
- @value = value
4
- end
5
-
1
+ class Oversee::Field::Value::Integer < Oversee::Field::Value
6
2
  def view_template
7
- p { @value }
3
+ p { value }
8
4
  end
9
5
  end
@@ -0,0 +1,6 @@
1
+ class Oversee::Field::Value::Json < Oversee::Field::Value
2
+ def view_template
3
+ return p(class: "text-gray-400 text-xs uppercase") { "JSON" } if for_table?
4
+ p(class: "truncate") { value.to_s }
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class Oversee::Field::Value::RichText < Oversee::Field::Value
2
+ def view_template
3
+ p(class: "truncate") { value }
4
+ end
5
+ end
@@ -1,20 +1,13 @@
1
- class Oversee::Field::Value::String < Phlex::HTML
2
- def initialize(key: nil, value: nil, kind: :value)
3
- @key = key
4
- @value = value
5
- @kind = kind
6
- end
7
-
1
+ class Oversee::Field::Value::String < Oversee::Field::Value
8
2
  def view_template
9
3
  return p(class: "text-gray-400 text-xs uppercase") { "Empty" } if @value == ""
10
4
  return p(class: "text-gray-400 text-xs uppercase") { "Redacted" } if sensitive?
11
-
12
- p(class: "truncate") { @value }
5
+ p(class: "truncate") { value }
13
6
  end
14
7
 
15
8
  private
16
9
 
17
10
  def sensitive?
18
- @key&.downcase&.include?("password") || @key&.downcase&.include?("token")
11
+ key&.downcase&.include?("password") || key&.downcase&.include?("token")
19
12
  end
20
13
  end
@@ -1,9 +1,5 @@
1
- class Oversee::Field::Value::Text < Phlex::HTML
2
- def initialize(datatype: :string, key: nil, value: nil, kind: :value)
3
- @value = value
4
- end
5
-
1
+ class Oversee::Field::Value::Text < Oversee::Field::Value
6
2
  def view_template
7
- p(class: "truncate") { @value }
3
+ p(class: "truncate") { value }
8
4
  end
9
5
  end
@@ -1,13 +1,22 @@
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
+ date: Oversee::Field::Value::Date,
6
7
  datetime: Oversee::Field::Value::Datetime,
8
+ enum: Oversee::Field::Value::Enum,
9
+ integer: Oversee::Field::Value::Integer,
10
+ json: Oversee::Field::Value::Json,
11
+ jsonb: Oversee::Field::Value::Json,
12
+ rich_text: Oversee::Field::Value::RichText,
7
13
  text: Oversee::Field::Value::Text,
8
- enum: Oversee::Field::Value::Enum
9
14
  }
10
15
 
16
+ attr_reader :key
17
+ attr_reader :value
18
+ attr_reader :datatype
19
+
11
20
  def initialize(key: nil, value: nil, datatype: :string, **options)
12
21
  @key = key
13
22
  @value = value
@@ -18,14 +27,14 @@ class Oversee::Field::Value < Oversee::Base
18
27
  end
19
28
 
20
29
  def view_template
21
- return p(class: "text-gray-400 text-xs"){ "—" } if @value.nil?
22
- render component_class.new(key: @key, value: @value)
30
+ return p(class: "text-gray-400 text-xs"){ "—" } if value.nil?
31
+ render component_class.new(key:, value:, **@options)
23
32
  end
24
33
 
25
34
  private
26
35
 
27
36
  def component_class
28
- MAP[@datatype.to_sym] || Oversee::Field::Value::String
37
+ MAP[datatype.to_sym] || Oversee::Field::Value::String
29
38
  end
30
39
 
31
40
  def for_table?
@@ -0,0 +1,42 @@
1
+ class Oversee::Field < Oversee::Base
2
+ attr_reader :resource
3
+ attr_reader :key
4
+ attr_reader :value
5
+ attr_reader :datatype
6
+
7
+ def initialize(resource: nil, key: nil, value: nil, datatype: nil, **options)
8
+ @resource = resource
9
+ @key = key
10
+ @value = value
11
+ @datatype = datatype
12
+ @options = options
13
+ end
14
+
15
+ def view_template
16
+ plain "Oversee::Field"
17
+ end
18
+
19
+ # Sub-components
20
+ def __LABEL__ = Oversee::Field::Label.new(resource:, key:, value:, datatype:, **@options)
21
+ def __VALUE__ = Oversee::Field::Value.new(resource:, key:, value:, datatype:, **@options)
22
+ def __INPUT__ = Oversee::Field::Input.new(resource:, key:, value:, datatype:, **@options)
23
+ def __FORM__ = Oversee::Field::Form.new(resource:, key:, value:, datatype:, **@options)
24
+ def __SET__ = Oversee::Field::Set.new(resource:, key:, value:, datatype:, **@options)
25
+
26
+ # Helpers & Decorators
27
+ def field_id
28
+ @field_id ||= "resource_#{key}"
29
+ end
30
+
31
+ def field_name
32
+ @field_name ||= "resource[#{key}]"
33
+ end
34
+
35
+ def field_form_id
36
+ @form_id ||= dom_id(resource, "#{key}_form")
37
+ end
38
+
39
+ def resource_class_name
40
+ @resource_class_name ||= @resource.class.name
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Oversee::Flash < Phlex::HTML
4
+ include Phlex::Rails::Helpers::Flash
5
+
6
+ def view_template
7
+ div(id: :flash, class: "fixed bottom-0 right-0 mb-8 mr-8 w-80 z-50") do
8
+ if !flash.empty?
9
+ div(
10
+ class: "flex flex-col gap-2 p-4 bg-white border border-gray-200/75 border-b-2 rounded-lg transition-all opacity-0 transform duration-300",
11
+ data: { controller: :notification }
12
+ ) do
13
+ notice if notice?
14
+ alert if alert?
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def notice?
23
+ flash[:notice].present?
24
+ end
25
+
26
+ def notice
27
+ render Phlex::Icons::Iconoir::CheckCircle.new(class: "size-5 text-emerald-500", stroke_width: 2)
28
+ p(class: "text-sm text-gray-700") { flash[:notice] }
29
+ end
30
+
31
+ def alert?
32
+ flash[:alert].present?
33
+ end
34
+
35
+ def alert
36
+ render Phlex::Icons::Iconoir::MessageAlert.new(class: "size-5 text-red-500", stroke_width: 2)
37
+ p(class: "text-sm text-gray-700") { flash[:alert] }
38
+ end
39
+ end
@@ -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 Oversee::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
16
- render Oversee::Dashboard::Filters.new(params: @params)
30
+ hr(class: "my-4")
31
+
32
+ render Oversee::Dashboard::Actions.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