oversee 0.3.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.
- checksums.yaml +4 -4
- data/README.md +8 -3
- data/app/components/oversee/dashboard/actions.rb +58 -0
- data/app/components/oversee/dashboard/filter.rb +12 -0
- data/app/components/oversee/dashboard/filters.rb +5 -55
- data/app/components/oversee/field/display.rb +6 -24
- data/app/components/oversee/field/form.rb +4 -17
- data/app/components/oversee/field/input/belongs_to.rb +1 -18
- data/app/components/oversee/field/input/boolean.rb +2 -7
- data/app/components/oversee/field/input/date.rb +5 -0
- data/app/components/oversee/field/input/datetime.rb +1 -6
- data/app/components/oversee/field/input/integer.rb +1 -6
- data/app/components/oversee/field/input/json.rb +5 -0
- data/app/components/oversee/field/input/rich_text.rb +0 -8
- data/app/components/oversee/field/input/string.rb +1 -6
- data/app/components/oversee/field/input.rb +5 -11
- data/app/components/oversee/field/label.rb +16 -16
- data/app/components/oversee/field/set.rb +36 -0
- data/app/components/oversee/field/value/belongs_to.rb +4 -10
- data/app/components/oversee/field/value/boolean.rb +2 -47
- data/app/components/oversee/field/value/date.rb +5 -0
- data/app/components/oversee/field/value/datetime.rb +2 -6
- data/app/components/oversee/field/value/enum.rb +2 -6
- data/app/components/oversee/field/value/integer.rb +2 -6
- data/app/components/oversee/field/value/json.rb +6 -0
- data/app/components/oversee/field/value/rich_text.rb +2 -6
- data/app/components/oversee/field/value/string.rb +3 -10
- data/app/components/oversee/field/value/text.rb +2 -6
- data/app/components/oversee/field/value.rb +3 -0
- data/app/components/oversee/field.rb +42 -0
- data/app/components/oversee/flash.rb +39 -0
- data/app/components/oversee/layout/application.rb +1 -1
- data/app/components/oversee/resources/index.rb +1 -1
- data/app/components/oversee/resources/show.rb +7 -17
- data/app/components/oversee/resources/table.rb +1 -1
- data/app/controllers/oversee/resources/fields_controller.rb +19 -15
- data/app/controllers/oversee/resources_controller.rb +7 -2
- data/app/javascript/oversee/controllers/clipboard_controller.js +21 -0
- data/app/javascript/oversee/controllers/index.js +1 -0
- data/app/javascript/oversee/controllers/notification_controller.js +17 -0
- data/app/javascript/oversee/controllers/reveal_controller.js +13 -1
- data/app/models/oversee/resource.rb +10 -7
- data/lib/oversee/version.rb +1 -1
- data/lib/oversee.rb +1 -0
- metadata +42 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82a5bb3d0823ed6874fe8b7bb09934ed3b72b7b9a2964da6c6d8cdd7b82ac28a
|
4
|
+
data.tar.gz: 5ddf616584c7319a2ef611227fb4f5e0cf876c1dc20b1228c47330411715054c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16cf0583966c0f07deae2be76299544a4fb5678efc5345a292acc0ad628d263a979b44e2d60f8749cc87bbfd5471eb85cfe5619fdc58af5bedb8b9e5a0efe755
|
7
|
+
data.tar.gz: f0d8ae31255ca03aecb010393356d55a9ac63b99699b50b8c9b6bae8d6c11c8f1d3b876dcd6fe9c9118e19c6015989f45f3e7ed74eadb259e885007eb215e764
|
data/README.md
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
|
2
1
|
# Oversee
|
3
2
|
|
4
|
-
Plug & play
|
3
|
+
Plug & play content management system (CMS) for Rails applications. Some may call it an admin dashboard too.
|
5
4
|
|
5
|
+
<a href="https://rubygems.org/gems/oversee">
|
6
|
+
<img alt="Oversee GEM Version" src="https://img.shields.io/gem/v/oversee?color=10b981&include_prereleases&logo=ruby&logoColor=f43f5e">
|
7
|
+
</a>
|
6
8
|
|
7
|
-
|
9
|
+
<a href="https://rubygems.org/gems/oversee">
|
10
|
+
<img alt="Oversee GEM Version" src="https://img.shields.io/gem/dt/oversee?color=10b981&include_prereleases&logo=ruby&logoColor=f43f5e">
|
11
|
+
</a>
|
8
12
|
|
9
13
|
---
|
10
14
|
|
@@ -35,6 +39,7 @@ $ bundle add oversee
|
|
35
39
|
|
36
40
|
> [!TIP]
|
37
41
|
> Currently, we don't release new gem versions too often due to the fragile nature of the gem. However, you can use the edge version of the gem by pointing directly to the git repository.
|
42
|
+
>
|
38
43
|
> ```ruby
|
39
44
|
> gem "oversee", git: "https://github.com/primevise/oversee", branch: :main
|
40
45
|
> ```
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class Oversee::Dashboard::Actions < Oversee::Base
|
2
|
+
def initialize(params: nil)
|
3
|
+
@params = params
|
4
|
+
end
|
5
|
+
|
6
|
+
def view_template(&)
|
7
|
+
div(class: "flex items-center justify-between") do
|
8
|
+
div(class: "flex items-center gap-2") do
|
9
|
+
if show_action_section?
|
10
|
+
button(
|
11
|
+
class:"rounded-full bg-gray-100 inline-flex gap-2 items-center text-xs px-4 py-2 font-medium hover:bg-gray-200",
|
12
|
+
data: { controller: "reveal", action: "reveal#toggle", reveal_revealable_id_value: "oversee-filters" }
|
13
|
+
) do
|
14
|
+
render Phlex::Icons::Iconoir::FilterAlt.new(class: "size-3")
|
15
|
+
plain "Filters"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
if false
|
19
|
+
a(class:"rounded-full bg-gray-100 inline-flex gap-2 items-center text-xs px-4 py-2 font-medium hover:bg-gray-200") do
|
20
|
+
render Phlex::Icons::Iconoir::XMark.new(class: "size-4 text-gray-500")
|
21
|
+
plain "Clear sorting"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
div(class: "flex items-center gap-4") do
|
26
|
+
form(action: "", class: "flex items-center gap-2") do
|
27
|
+
input(
|
28
|
+
type: :search,
|
29
|
+
name: :query,
|
30
|
+
value: @params[:query],
|
31
|
+
placeholder: search_placeholder,
|
32
|
+
class: "flex bg-gray-100 min-w-64 w-64 focus:w-96 transition-all h-10 items-center pl-4 py-2 placeholder:text-gray-500 rounded-sm text-sm"
|
33
|
+
)
|
34
|
+
button(class: "size-10 inline-flex items-center justify-center bg-gray-100 hover:bg-gray-200 transition-colors") { render Phlex::Icons::Iconoir::Search.new(class: "size-4 text-gray-600") }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
render Oversee::Dashboard::Filters.new if show_action_section?
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def show_action_section?
|
44
|
+
Rails.env.development? || @params[:experimental] == "true"
|
45
|
+
end
|
46
|
+
|
47
|
+
def sortless_path
|
48
|
+
sortless_query_params = @params.except(:sort_attribute, :sort_direction, :controller, :action)
|
49
|
+
# helpers.resources_path(sortless_query_params)
|
50
|
+
end
|
51
|
+
|
52
|
+
def search_placeholder
|
53
|
+
context = Oversee::Search.new(collection: nil, resource_class: @params[:resource_class_name].constantize)
|
54
|
+
attr = context.default_searchable_attribute
|
55
|
+
|
56
|
+
"Search by #{attr}"
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Oversee::Dashboard::Filter < Oversee::Base
|
3
|
+
def view_template
|
4
|
+
div(class: "flex items-center gap-2") do
|
5
|
+
render Phlex::Icons::Iconoir::LongArrowDownRight.new(class: "size-4 text-gray-500")
|
6
|
+
form(action: "", class: "flex items-center gap-2") do
|
7
|
+
input(type: :text, placeholder: "Title [EQ]", name: "filters[title][eq][]", class: "bg-gray-100 px-4 py-2 text-xs")
|
8
|
+
button(type: :submit, class: "button", class: "bg-gray-900 text-white px-4 py-2 text-xs font-medium") { plain "Apply" }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -1,58 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class Oversee::Dashboard::Filters < Oversee::Base
|
2
|
-
def
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
puts "params: #{params}"
|
7
|
-
puts "sortless_path: #{sortless_path}"
|
8
|
-
end
|
9
|
-
|
10
|
-
def view_template(&)
|
11
|
-
div(class: "flex items-center justify-between") do
|
12
|
-
div(class: "flex items-center gap-2") do
|
13
|
-
if show_action_section?
|
14
|
-
button(class:"rounded-full bg-gray-100 inline-flex gap-2 items-center text-xs px-4 py-2 font-medium hover:bg-gray-200") do
|
15
|
-
render Phlex::Icons::Iconoir::FilterAlt.new(class: "size-3")
|
16
|
-
plain "Filters"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
if false
|
20
|
-
a(class:"rounded-full bg-gray-100 inline-flex gap-2 items-center text-xs px-4 py-2 font-medium hover:bg-gray-200") do
|
21
|
-
render Phlex::Icons::Iconoir::XMark.new(class: "size-4 text-gray-500")
|
22
|
-
plain "Clear sorting"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
div(class: "flex items-center gap-4") do
|
27
|
-
form(action: "", class: "flex items-center gap-2") do
|
28
|
-
input(
|
29
|
-
type: :search,
|
30
|
-
name: :query,
|
31
|
-
value: @params[:query],
|
32
|
-
placeholder: search_placeholder,
|
33
|
-
class: "flex bg-gray-100 min-w-64 w-64 focus:w-96 transition-all h-10 items-center pl-4 py-2 placeholder:text-gray-500 rounded-sm text-sm"
|
34
|
-
)
|
35
|
-
button(class: "size-10 inline-flex items-center justify-center bg-gray-100 hover:bg-gray-200 transition-colors") { render Phlex::Icons::Iconoir::Search.new(class: "size-4 text-gray-600") }
|
36
|
-
end
|
37
|
-
end
|
3
|
+
def view_template
|
4
|
+
div(id: :oversee_filters, class: "hidden pt-4 mt-4 border-t flex flex-col gap-2") do
|
5
|
+
render Oversee::Dashboard::Filter.new
|
38
6
|
end
|
39
7
|
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def show_action_section?
|
44
|
-
Rails.env.development? || @params[:experimental] == "true"
|
45
|
-
end
|
46
|
-
|
47
|
-
def sortless_path
|
48
|
-
sortless_query_params = @params.except(:sort_attribute, :sort_direction, :controller, :action)
|
49
|
-
# helpers.resources_path(sortless_query_params)
|
50
|
-
end
|
51
|
-
|
52
|
-
def search_placeholder
|
53
|
-
context = Oversee::Search.new(collection: nil, resource_class: @params[:resource_class_name].constantize)
|
54
|
-
attr = context.default_searchable_attribute
|
55
|
-
|
56
|
-
"Search by #{attr}"
|
57
|
-
end
|
58
|
-
end
|
8
|
+
end
|
@@ -1,38 +1,20 @@
|
|
1
|
-
class Oversee::Field::Display < Oversee::
|
2
|
-
|
3
|
-
attr_reader :resource
|
4
|
-
attr_reader :key
|
5
|
-
attr_reader :value
|
6
|
-
attr_reader :datatype
|
7
|
-
|
8
|
-
def initialize(resource:, key: nil, value: nil, datatype: :string, **options)
|
9
|
-
@resource = resource
|
10
|
-
@key = key
|
11
|
-
@value = value
|
12
|
-
@datatype = datatype
|
13
|
-
@options = options
|
14
|
-
end
|
15
|
-
|
1
|
+
class Oversee::Field::Display < Oversee::Field
|
16
2
|
def view_template
|
17
3
|
html_tag(
|
18
4
|
id: dom_id(resource, key),
|
19
5
|
href: helpers.resource_input_path(resource_class_name:, key:, datatype:),
|
20
|
-
|
6
|
+
title: key.to_s.titleize,
|
7
|
+
class: "bg-gray-100 h-10 flex items-center justify-between px-4 py-2 hover:bg-gray-200 transition-colors w-full cursor-pointer group",
|
21
8
|
data: { turbo_stream: true }
|
22
9
|
) do
|
23
10
|
render Oversee::Field::Value.new(key:, value:, datatype:, **@options)
|
11
|
+
render Phlex::Icons::Iconoir::Edit.new(class: "text-gray-500 size-4 opacity-0 group-hover:opacity-100 transition-opacity", stroke_width: 1.75)
|
24
12
|
end
|
25
13
|
end
|
26
14
|
|
27
15
|
private
|
28
16
|
|
29
|
-
def resource_class_name
|
30
|
-
@resource_class_name ||= @resource.class.name
|
31
|
-
end
|
32
|
-
|
33
|
-
def html_tag(...)
|
34
|
-
edittable? ? a(...) : div(...)
|
35
|
-
end
|
36
|
-
|
37
17
|
def edittable? = @options[:edittable] || true
|
18
|
+
|
19
|
+
def html_tag(...) = edittable? ? a(...) : div(...)
|
38
20
|
end
|
@@ -1,30 +1,17 @@
|
|
1
|
-
class Oversee::Field::Form < Oversee::
|
1
|
+
class Oversee::Field::Form < Oversee::Field
|
2
2
|
include Phlex::Rails::Helpers::FormWith
|
3
3
|
|
4
|
-
def initialize(resource:, key: nil, value: nil, datatype: :string, method: :patch, **options)
|
5
|
-
@resource = resource
|
6
|
-
@key = key
|
7
|
-
@value = value
|
8
|
-
@datatype = datatype
|
9
|
-
@method = method
|
10
|
-
@options = options
|
11
|
-
end
|
12
|
-
|
13
4
|
def view_template
|
14
|
-
form_with(id:
|
5
|
+
form_with(id: field_form_id, model: resource, url: helpers.update_resource_path(resource_class_name: resource_class_name, id: @resource.id), method: @method, class: "flex items-center w-full gap-4") do |form|
|
15
6
|
input type: :hidden, id: "oversee_key", name: "oversee_key", value: @key.to_s
|
16
7
|
input type: :hidden, id: "oversee_datatype", name: "oversee_datatype", value: @datatype
|
17
8
|
render Oversee::Field::Input.new(key: @key, value: @value, datatype: @datatype, **@options)
|
18
|
-
button(class:"h-9 bg-gray-900 hover:bg-gray-700 text-white inline-flex items-center cursor-pointer gap-2 px-4 rounded-full text-xs font-medium") {
|
19
|
-
render Phlex::Icons::Iconoir::Check.new(class: "size-4")
|
20
|
-
plain "Save"
|
21
|
-
}
|
22
9
|
end
|
23
10
|
end
|
24
11
|
|
25
12
|
private
|
26
13
|
|
27
|
-
def
|
28
|
-
@
|
14
|
+
def method
|
15
|
+
@method ||= @options[:method] || :patch
|
29
16
|
end
|
30
17
|
end
|
@@ -1,22 +1,5 @@
|
|
1
1
|
class Oversee::Field::Input::BelongsTo < Oversee::Field::Input
|
2
|
-
def initialize(key:, value:, **options)
|
3
|
-
@key = key
|
4
|
-
@value = value
|
5
|
-
end
|
6
|
-
|
7
2
|
def view_template
|
8
|
-
input
|
9
|
-
|
10
|
-
# select(id: field_id, name: field_name, class: "flex w-full border rounded-sm px-4 py-2 text-sm") do
|
11
|
-
|
12
|
-
# option(value: 1, selected: @value) { "True" }
|
13
|
-
# option(value: 0, selected: !@value) { "False" }
|
14
|
-
# end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def select_values
|
20
|
-
|
3
|
+
input(type: "text", id: field_id, name: field_name, value:, class: "flex border px-4 py-2 text-sm w-full rounded-sm")
|
21
4
|
end
|
22
5
|
end
|
@@ -1,13 +1,8 @@
|
|
1
1
|
class Oversee::Field::Input::Boolean < Oversee::Field::Input
|
2
|
-
def initialize(key:, value:)
|
3
|
-
@key = key
|
4
|
-
@value = value
|
5
|
-
end
|
6
|
-
|
7
2
|
def view_template
|
8
3
|
select(id: field_id, name: field_name, class: "flex w-full border rounded-sm px-4 py-2 text-sm") do
|
9
|
-
option(value: 1, selected:
|
10
|
-
option(value: 0, selected:
|
4
|
+
option(value: 1, selected: value) { "True" }
|
5
|
+
option(value: 0, selected: !value) { "False" }
|
11
6
|
end
|
12
7
|
end
|
13
8
|
end
|
@@ -1,10 +1,5 @@
|
|
1
1
|
class Oversee::Field::Input::Datetime < Oversee::Field::Input
|
2
|
-
def initialize(key:, value:)
|
3
|
-
@key = key
|
4
|
-
@value = value
|
5
|
-
end
|
6
|
-
|
7
2
|
def view_template
|
8
|
-
input
|
3
|
+
input(type: "datetime-local", id: field_id, name: field_name, value: value&.strftime("%Y-%m-%dT%T"), class: "flex w-full border rounded-sm px-4 py-2 text-sm")
|
9
4
|
end
|
10
5
|
end
|
@@ -1,10 +1,5 @@
|
|
1
1
|
class Oversee::Field::Input::Integer < Oversee::Field::Input
|
2
|
-
def initialize(key:, value:)
|
3
|
-
@key = key
|
4
|
-
@value = value
|
5
|
-
end
|
6
|
-
|
7
2
|
def view_template
|
8
|
-
input
|
3
|
+
input(type: "number", id: field_id, name: field_name, value:, class: "flex w-full border rounded-sm px-4 py-2 text-sm")
|
9
4
|
end
|
10
5
|
end
|
@@ -1,14 +1,6 @@
|
|
1
1
|
class Oversee::Field::Input::RichText < Oversee::Field::Input
|
2
2
|
register_element :trix_editor
|
3
3
|
|
4
|
-
attr_reader :key
|
5
|
-
attr_reader :value
|
6
|
-
|
7
|
-
def initialize(key:, value:)
|
8
|
-
@key = key
|
9
|
-
@value = value
|
10
|
-
end
|
11
|
-
|
12
4
|
def view_template
|
13
5
|
div do
|
14
6
|
input(type: "hidden", id: field_id, name: field_name, value:)
|
@@ -1,10 +1,5 @@
|
|
1
1
|
class Oversee::Field::Input::String < Oversee::Field::Input
|
2
|
-
def initialize(key:, value:)
|
3
|
-
@key = key
|
4
|
-
@value = value
|
5
|
-
end
|
6
|
-
|
7
2
|
def view_template
|
8
|
-
input
|
3
|
+
input(type: "text", id: field_id, name: field_name, value:, class: "flex border px-4 py-2 text-sm w-full rounded-sm")
|
9
4
|
end
|
10
5
|
end
|
@@ -1,24 +1,20 @@
|
|
1
|
-
class Oversee::Field::Input < Oversee::
|
1
|
+
class Oversee::Field::Input < Oversee::Field
|
2
2
|
MAP = {
|
3
3
|
belongs_to: Oversee::Field::Input::BelongsTo,
|
4
4
|
boolean: Oversee::Field::Input::Boolean,
|
5
|
+
date: Oversee::Field::Input::Date,
|
5
6
|
datetime: Oversee::Field::Input::Datetime,
|
6
7
|
enum: Oversee::Field::Input::String,
|
7
8
|
integer: Oversee::Field::Input::Integer,
|
9
|
+
json: Oversee::Field::Input::Json,
|
10
|
+
jsonb: Oversee::Field::Input::Json,
|
8
11
|
rich_text: Oversee::Field::Input::RichText,
|
9
12
|
string: Oversee::Field::Input::String,
|
10
13
|
text: Oversee::Field::Input::String,
|
11
14
|
}
|
12
15
|
|
13
|
-
def initialize(key: nil, value: nil, datatype: :string, **options)
|
14
|
-
@key = key
|
15
|
-
@value = value
|
16
|
-
@datatype = datatype
|
17
|
-
@options = options
|
18
|
-
end
|
19
|
-
|
20
16
|
def view_template
|
21
|
-
render component_class.new(key
|
17
|
+
render component_class.new(key:, value:, **@options)
|
22
18
|
end
|
23
19
|
|
24
20
|
private
|
@@ -29,6 +25,4 @@ class Oversee::Field::Input < Oversee::Base
|
|
29
25
|
|
30
26
|
private
|
31
27
|
|
32
|
-
def field_id = "resource_#{@key.to_s}"
|
33
|
-
def field_name = "resource[#{@key.to_s}]"
|
34
28
|
end
|
@@ -1,25 +1,25 @@
|
|
1
|
-
class Oversee::Field::Label < Oversee::
|
1
|
+
class Oversee::Field::Label < Oversee::Field
|
2
2
|
ICON_MAP = {
|
3
|
-
string: Phlex::Icons::Iconoir::Text,
|
4
|
-
text: Phlex::Icons::Iconoir::TextSquare,
|
5
|
-
rich_text: Phlex::Icons::Iconoir::TextSquare,
|
6
|
-
integer: Phlex::Icons::Iconoir::Number0Square,
|
7
|
-
datetime: Phlex::Icons::Iconoir::Calendar,
|
8
3
|
boolean: Phlex::Icons::Iconoir::SwitchOn,
|
9
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,
|
10
13
|
}
|
11
14
|
|
12
|
-
def initialize(datatype: :string, key: nil)
|
13
|
-
@datatype = datatype
|
14
|
-
@key = key
|
15
|
-
end
|
16
|
-
|
17
15
|
def view_template
|
18
|
-
div(id: "#{
|
19
|
-
div(class: "size-5 bg-gray-100 inline-flex items-center justify-center")
|
20
|
-
|
21
|
-
end
|
22
|
-
label(class: "uppercase text-xs text-gray-700 font-medium block cursor-auto") { @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) }
|
23
19
|
end
|
24
20
|
end
|
21
|
+
|
22
|
+
def icon
|
23
|
+
ICON_MAP[datatype&.to_sym] || ICON_MAP[:data]
|
24
|
+
end
|
25
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
|
@@ -1,17 +1,11 @@
|
|
1
|
-
class Oversee::Field::Value::BelongsTo <
|
2
|
-
def initialize(key: nil, value: nil, **options)
|
3
|
-
@key = key
|
4
|
-
@value = value
|
5
|
-
@options = options
|
6
|
-
end
|
7
|
-
|
1
|
+
class Oversee::Field::Value::BelongsTo < Oversee::Field::Value
|
8
2
|
def view_template
|
9
|
-
p(title:
|
3
|
+
p(title: value, class:"inline-flex items-center gap-1") do
|
10
4
|
if display_key?
|
11
|
-
span {
|
5
|
+
span { key.humanize }
|
12
6
|
span {"|"}
|
13
7
|
end
|
14
|
-
span {
|
8
|
+
span { value }
|
15
9
|
end
|
16
10
|
end
|
17
11
|
|
@@ -1,50 +1,5 @@
|
|
1
|
-
class Oversee::Field::Value::Boolean <
|
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
|
-
|
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
|
@@ -1,9 +1,5 @@
|
|
1
|
-
class Oversee::Field::Value::Datetime <
|
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:
|
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 <
|
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") {
|
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::RichText <
|
2
|
-
def initialize(datatype: :string, key: nil, value: nil, kind: :value)
|
3
|
-
@value = value
|
4
|
-
end
|
5
|
-
|
1
|
+
class Oversee::Field::Value::RichText < Oversee::Field::Value
|
6
2
|
def view_template
|
7
|
-
p(class: "truncate") {
|
3
|
+
p(class: "truncate") { value }
|
8
4
|
end
|
9
5
|
end
|
@@ -1,20 +1,13 @@
|
|
1
|
-
class Oversee::Field::Value::String <
|
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
|
-
|
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 <
|
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") {
|
3
|
+
p(class: "truncate") { value }
|
8
4
|
end
|
9
5
|
end
|
@@ -3,9 +3,12 @@ class Oversee::Field::Value < Oversee::Base
|
|
3
3
|
string: Oversee::Field::Value::String,
|
4
4
|
belongs_to: Oversee::Field::Value::BelongsTo,
|
5
5
|
boolean: Oversee::Field::Value::Boolean,
|
6
|
+
date: Oversee::Field::Value::Date,
|
6
7
|
datetime: Oversee::Field::Value::Datetime,
|
7
8
|
enum: Oversee::Field::Value::Enum,
|
8
9
|
integer: Oversee::Field::Value::Integer,
|
10
|
+
json: Oversee::Field::Value::Json,
|
11
|
+
jsonb: Oversee::Field::Value::Json,
|
9
12
|
rich_text: Oversee::Field::Value::RichText,
|
10
13
|
text: Oversee::Field::Value::Text,
|
11
14
|
}
|
@@ -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
|
@@ -28,7 +28,7 @@ class Oversee::Layout::Application < Oversee::Base
|
|
28
28
|
end
|
29
29
|
|
30
30
|
body(class: "min-h-screen bg-gray-100 p-4") do
|
31
|
-
|
31
|
+
render Oversee::Flash.new
|
32
32
|
|
33
33
|
div(class: "flex gap-4 w-full") do
|
34
34
|
div(class: "w-72 shrink-0") { render Oversee::Dashboard::Sidebar.new }
|
@@ -29,7 +29,7 @@ class Oversee::Resources::Index < Oversee::Base
|
|
29
29
|
end
|
30
30
|
hr(class: "my-4")
|
31
31
|
|
32
|
-
render Oversee::Dashboard::
|
32
|
+
render Oversee::Dashboard::Actions.new(params: @params)
|
33
33
|
|
34
34
|
hr(class: "mt-4")
|
35
35
|
render Oversee::Resources::Table.new(resource_class: @resource_class, resources: @resources, params: @params)
|
@@ -57,30 +57,20 @@ class Oversee::Resources::Show < Oversee::Base
|
|
57
57
|
|
58
58
|
hr(class: "my-4")
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
60
|
# COLUMNS
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
61
|
+
div(class: "flex flex-col gap-4") do
|
62
|
+
@resource_class.columns_hash.each do |key, metadata|
|
63
|
+
next if @oversee_resource.foreign_keys.include?(key.to_s)
|
64
|
+
value = @resource.send(key)
|
65
|
+
datatype = metadata.sql_type_metadata.type
|
66
|
+
render Oversee::Field::Set.new(resource:, key:, value:, datatype:)
|
77
67
|
end
|
78
68
|
end
|
79
69
|
|
80
|
-
hr(class: "my-4")
|
81
70
|
|
82
71
|
# RICH TEXT Associations
|
83
72
|
if !!rich_text_associations.length
|
73
|
+
hr(class: "my-4")
|
84
74
|
rich_text_associations.each do |association|
|
85
75
|
|
86
76
|
# Remove the "rich_text_" prefix from the association name
|
@@ -78,7 +78,7 @@ class Oversee::Resources::Table < Oversee::Base
|
|
78
78
|
next if @oversee_resource.foreign_keys.include?(key.to_s)
|
79
79
|
row.data do
|
80
80
|
div(class: "max-w-96") do
|
81
|
-
render Oversee::Field::Value.new(datatype: metadata.sql_type_metadata.type, value: resource.send(key),
|
81
|
+
render Oversee::Field::Value.new(key:, datatype: metadata.sql_type_metadata.type, value: resource.send(key), for_table: true)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
@@ -1,29 +1,33 @@
|
|
1
1
|
class Oversee::Resources::FieldsController < Oversee::ResourcesController
|
2
|
+
before_action :set_resource, only: %i[input]
|
3
|
+
|
2
4
|
# Renders the display field for a resource
|
3
5
|
def show
|
4
6
|
end
|
5
7
|
|
6
8
|
# Renders the input field for a resource
|
7
9
|
def input
|
8
|
-
|
9
|
-
|
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
|
13
|
-
|
14
|
-
# puts "---" * 30
|
15
|
-
# puts "key: #{key}"
|
16
|
-
# puts "value: #{value}"
|
17
|
-
# puts "datatype: #{datatype}"
|
18
|
-
# puts "---" * 30
|
19
|
-
|
20
|
-
field_dom_id = dom_id(@resource, key)
|
21
|
-
field = Oversee::Field::Form.new(resource: @resource, datatype:, key:, value:)
|
10
|
+
component_dom_id = dom_id(@resource, key)
|
11
|
+
component = Oversee::Field::Set.new(resource: @resource, datatype:, key:, value:, state: :input)
|
22
12
|
|
23
13
|
respond_to do |format|
|
24
14
|
format.turbo_stream do
|
25
|
-
render turbo_stream: turbo_stream.replace(
|
15
|
+
render turbo_stream: turbo_stream.replace(component_dom_id, component)
|
26
16
|
end
|
27
17
|
end
|
28
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def key
|
23
|
+
params[:key].to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
def value
|
27
|
+
params[:value] || @resource.send(key)
|
28
|
+
end
|
29
|
+
|
30
|
+
def datatype
|
31
|
+
params[:datatype] || @resource.class.columns_hash[key.to_s].type
|
32
|
+
end
|
29
33
|
end
|
@@ -31,6 +31,7 @@ module Oversee
|
|
31
31
|
|
32
32
|
respond_to do |format|
|
33
33
|
if @resource.update(resource_params)
|
34
|
+
flash.now[:notice] = "Resource was successfully created."
|
34
35
|
format.html { redirect_to resource_path(@resource.id, resource_class_name: @resource_class) }
|
35
36
|
format.turbo_stream { redirect_to resource_path(@resource.id, resource_class_name: @resource_class), status: :see_other }
|
36
37
|
else
|
@@ -58,10 +59,14 @@ module Oversee
|
|
58
59
|
|
59
60
|
respond_to do |format|
|
60
61
|
if @resource.update(resource_params)
|
62
|
+
flash.now[:notice] = "#{@resource.class.to_s.titleize.capitalize.gsub("::"," ")} was successfully updated!"
|
61
63
|
format.html { redirect_to resource_path(@resource.id, resource: @resource_class) }
|
62
64
|
format.turbo_stream do
|
63
|
-
component = Oversee::Field::
|
64
|
-
render turbo_stream:
|
65
|
+
component = Oversee::Field::Set.new(resource: @resource, datatype:, key:, value: @resource.send(key))
|
66
|
+
render turbo_stream: [
|
67
|
+
turbo_stream.replace(dom_id(@resource, key), component),
|
68
|
+
turbo_stream.replace(:flash, Oversee::Flash)
|
69
|
+
]
|
65
70
|
end
|
66
71
|
else
|
67
72
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = ["copyIcon", "successIcon"];
|
5
|
+
static values = { content: String };
|
6
|
+
|
7
|
+
async copy() {
|
8
|
+
try {
|
9
|
+
await navigator.clipboard.writeText(this.contentValue);
|
10
|
+
this.toggleIcons(true);
|
11
|
+
setTimeout(() => this.toggleIcons(false), 1500);
|
12
|
+
} catch (error) {
|
13
|
+
console.error(error.message);
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
toggleIcons(isCopied) {
|
18
|
+
this.copyIconTarget.classList.toggle("hidden", isCopied);
|
19
|
+
this.successIconTarget.classList.toggle("hidden", !isCopied);
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
connect() {
|
5
|
+
setTimeout(() => {
|
6
|
+
this.element.classList.remove("opacity-0");
|
7
|
+
}, 100);
|
8
|
+
|
9
|
+
setTimeout(() => {
|
10
|
+
this.element.classList.remove("opacity-100");
|
11
|
+
this.element.classList.add("opacity-0");
|
12
|
+
}, 2500);
|
13
|
+
setTimeout(() => {
|
14
|
+
this.element.outerHTML = "";
|
15
|
+
}, 3000);
|
16
|
+
}
|
17
|
+
}
|
@@ -1,7 +1,19 @@
|
|
1
1
|
import { Controller } from "@hotwired/stimulus";
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
|
+
static targets = ["revealable"];
|
5
|
+
static values = { revealableId: String };
|
6
|
+
|
4
7
|
connect() {
|
5
|
-
|
8
|
+
if (this.hasRevealableIdValue)
|
9
|
+
this.target = document.getElementById(this.revealableIdValue);
|
10
|
+
|
11
|
+
if (!this.target && this.hasRevealableTarget)
|
12
|
+
this.target = this.revealableTarget;
|
13
|
+
}
|
14
|
+
|
15
|
+
toggle() {
|
16
|
+
if (!this.target) return;
|
17
|
+
this.target.classList.toggle("hidden");
|
6
18
|
}
|
7
19
|
}
|
@@ -2,22 +2,21 @@ class Oversee::Resource
|
|
2
2
|
attr_reader :resource_class
|
3
3
|
attr_reader :resource_class_name
|
4
4
|
attr_reader :instance
|
5
|
-
attr_reader :
|
6
|
-
|
7
|
-
attr_accessor :associations
|
5
|
+
attr_reader :associations
|
8
6
|
|
9
7
|
def initialize(resource_class:, instance: nil)
|
10
8
|
@resource_class = resource_class
|
11
|
-
@resource_class_name = resource_class.to_s
|
12
9
|
@instance = instance
|
13
10
|
end
|
14
11
|
|
15
12
|
# Route helpers
|
16
|
-
def
|
17
|
-
|
13
|
+
def index_path
|
14
|
+
"/resources/#{resource_class_name}"
|
18
15
|
end
|
19
16
|
|
20
|
-
def
|
17
|
+
def show_path
|
18
|
+
# Rails.application.routes.url_helpers.resource_path(instance || object, resource_class_name:)
|
19
|
+
"/resources/#{resource_class_name}/#{instance.to_param}"
|
21
20
|
end
|
22
21
|
|
23
22
|
# Columns
|
@@ -59,4 +58,8 @@ class Oversee::Resource
|
|
59
58
|
def rich_text_associations
|
60
59
|
@rich_text_associations ||= associations[:has_one].select { |association| association[:rich_text] }
|
61
60
|
end
|
61
|
+
|
62
|
+
def resource_class_name
|
63
|
+
@resource_class_name ||= resource_class.to_s
|
64
|
+
end
|
62
65
|
end
|
data/lib/oversee/version.rb
CHANGED
data/lib/oversee.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oversee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elvinas Predkelis
|
@@ -9,10 +9,38 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-12-
|
12
|
+
date: 2024-12-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 7.0.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 7.0.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activesupport
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 7.0.0
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 7.0.0
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: activestorage
|
16
44
|
requirement: !ruby/object:Gem::Requirement
|
17
45
|
requirements:
|
18
46
|
- - ">="
|
@@ -122,6 +150,8 @@ files:
|
|
122
150
|
- app/assets/config/oversee_manifest.js
|
123
151
|
- app/components/oversee/base.rb
|
124
152
|
- app/components/oversee/card.rb
|
153
|
+
- app/components/oversee/dashboard/actions.rb
|
154
|
+
- app/components/oversee/dashboard/filter.rb
|
125
155
|
- app/components/oversee/dashboard/filters.rb
|
126
156
|
- app/components/oversee/dashboard/header.rb
|
127
157
|
- app/components/oversee/dashboard/index.rb
|
@@ -129,25 +159,32 @@ files:
|
|
129
159
|
- app/components/oversee/dashboard/pagination.rb
|
130
160
|
- app/components/oversee/dashboard/sidebar.rb
|
131
161
|
- app/components/oversee/dashboard/tailwind.rb
|
162
|
+
- app/components/oversee/field.rb
|
132
163
|
- app/components/oversee/field/display.rb
|
133
164
|
- app/components/oversee/field/form.rb
|
134
165
|
- app/components/oversee/field/input.rb
|
135
166
|
- app/components/oversee/field/input/belongs_to.rb
|
136
167
|
- app/components/oversee/field/input/boolean.rb
|
168
|
+
- app/components/oversee/field/input/date.rb
|
137
169
|
- app/components/oversee/field/input/datetime.rb
|
138
170
|
- app/components/oversee/field/input/integer.rb
|
171
|
+
- app/components/oversee/field/input/json.rb
|
139
172
|
- app/components/oversee/field/input/rich_text.rb
|
140
173
|
- app/components/oversee/field/input/string.rb
|
141
174
|
- app/components/oversee/field/label.rb
|
175
|
+
- app/components/oversee/field/set.rb
|
142
176
|
- app/components/oversee/field/value.rb
|
143
177
|
- app/components/oversee/field/value/belongs_to.rb
|
144
178
|
- app/components/oversee/field/value/boolean.rb
|
179
|
+
- app/components/oversee/field/value/date.rb
|
145
180
|
- app/components/oversee/field/value/datetime.rb
|
146
181
|
- app/components/oversee/field/value/enum.rb
|
147
182
|
- app/components/oversee/field/value/integer.rb
|
183
|
+
- app/components/oversee/field/value/json.rb
|
148
184
|
- app/components/oversee/field/value/rich_text.rb
|
149
185
|
- app/components/oversee/field/value/string.rb
|
150
186
|
- app/components/oversee/field/value/text.rb
|
187
|
+
- app/components/oversee/flash.rb
|
151
188
|
- app/components/oversee/layout/application.rb
|
152
189
|
- app/components/oversee/resources/base.rb
|
153
190
|
- app/components/oversee/resources/errors.rb
|
@@ -167,7 +204,9 @@ files:
|
|
167
204
|
- app/controllers/oversee/resources/fields_controller.rb
|
168
205
|
- app/controllers/oversee/resources_controller.rb
|
169
206
|
- app/javascript/oversee/application.js
|
207
|
+
- app/javascript/oversee/controllers/clipboard_controller.js
|
170
208
|
- app/javascript/oversee/controllers/index.js
|
209
|
+
- app/javascript/oversee/controllers/notification_controller.js
|
171
210
|
- app/javascript/oversee/controllers/reveal_controller.js
|
172
211
|
- app/javascript/oversee/controllers/sidebar/state_controller.js
|
173
212
|
- app/models/oversee/application_record.rb
|