databasium 0.1.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 +7 -0
- data/CHANGELOG.md +32 -0
- data/MIT-LICENSE +20 -0
- data/README.md +109 -0
- data/Rakefile +6 -0
- data/app/assets/builds/application.js +9045 -0
- data/app/assets/builds/application.js.map +7 -0
- data/app/assets/builds/databasium.css +2 -0
- data/app/assets/config/databasium_manifest.js +1 -0
- data/app/assets/javascript/databasium/application.js +2 -0
- data/app/assets/javascript/databasium/controllers/attribute_controller.js +27 -0
- data/app/assets/javascript/databasium/controllers/collapse_controller.js +18 -0
- data/app/assets/javascript/databasium/controllers/error_controller.js +15 -0
- data/app/assets/javascript/databasium/controllers/filter_controller.js +224 -0
- data/app/assets/javascript/databasium/controllers/flash_controller.js +18 -0
- data/app/assets/javascript/databasium/controllers/graph_controller.js +193 -0
- data/app/assets/javascript/databasium/controllers/index.js +7 -0
- data/app/assets/javascript/databasium/controllers/layout_controller.js +13 -0
- data/app/assets/javascript/databasium/controllers/model_controller.js +32 -0
- data/app/assets/javascript/databasium/controllers/new_migration_controller.js +107 -0
- data/app/assets/javascript/databasium/controllers/relation_controller.js +10 -0
- data/app/assets/javascript/databasium/controllers/search_controller.js +23 -0
- data/app/assets/javascript/databasium/controllers/table_controller.js +283 -0
- data/app/assets/javascript/databasium/controllers/table_select_controller.js +19 -0
- data/app/assets/javascript/databasium/controllers/toggle_controller.js +28 -0
- data/app/assets/javascript/databasium/controllers/validation_controller.js +78 -0
- data/app/assets/javascript/databasium/shapes/erd_table_shape.js +54 -0
- data/app/assets/stylesheets/databasium/application.css +15 -0
- data/app/assets/stylesheets/databasium/colors.css +55 -0
- data/app/assets/stylesheets/databasium/custom.css +36 -0
- data/app/assets/stylesheets/databasium/databasium_engine.css +6 -0
- data/app/assets/stylesheets/databasium/pagy-tailwind.css +66 -0
- data/app/components/base.rb +50 -0
- data/app/components/databasium/collapsable.rb +62 -0
- data/app/components/databasium/forms/model.rb +147 -0
- data/app/components/databasium/forms/search.rb +31 -0
- data/app/components/databasium/global/error.rb +60 -0
- data/app/components/databasium/global/flash.rb +73 -0
- data/app/components/databasium/global/header_actions.rb +36 -0
- data/app/components/databasium/global/sidebar.rb +45 -0
- data/app/components/databasium/global/suggestion.rb +25 -0
- data/app/components/databasium/migrations/action.rb +39 -0
- data/app/components/databasium/migrations/file.rb +58 -0
- data/app/components/databasium/migrations/form.rb +222 -0
- data/app/components/databasium/migrations/header_actions.rb +87 -0
- data/app/components/databasium/migrations/migration_status.rb +22 -0
- data/app/components/databasium/migrations/preview.rb +29 -0
- data/app/components/databasium/migrations/show_turbo_stream.rb +19 -0
- data/app/components/databasium/migrations/sidebar.rb +28 -0
- data/app/components/databasium/models/attributes.rb +49 -0
- data/app/components/databasium/models/form.rb +100 -0
- data/app/components/databasium/models/header_actions.rb +51 -0
- data/app/components/databasium/models/model_preview.rb +31 -0
- data/app/components/databasium/models/sidebar.rb +25 -0
- data/app/components/databasium/models/templates/attribute.rb +99 -0
- data/app/components/databasium/models/templates/base.rb +6 -0
- data/app/components/databasium/models/templates/relation.rb +56 -0
- data/app/components/databasium/models/templates/validation.rb +285 -0
- data/app/components/databasium/navigation/base_icon.rb +32 -0
- data/app/components/databasium/navigation/frontend_icon.rb +17 -0
- data/app/components/databasium/navigation/get_icon.rb +26 -0
- data/app/components/databasium/navigation/icon.rb +28 -0
- data/app/components/databasium/navigation/icon_panel.rb +26 -0
- data/app/components/databasium/navigation/post_icon.rb +25 -0
- data/app/components/databasium/navigation/put_icon.rb +18 -0
- data/app/components/databasium/records/filter.rb +73 -0
- data/app/components/databasium/records/foreign_records.rb +84 -0
- data/app/components/databasium/records/header_actions.rb +110 -0
- data/app/components/databasium/records/show_turbo_stream.rb +75 -0
- data/app/components/databasium/records/sidebar.rb +23 -0
- data/app/components/databasium/records/table/record_panel.rb +60 -0
- data/app/components/databasium/records/table/row.rb +104 -0
- data/app/components/databasium/records/table.rb +125 -0
- data/app/components/databasium/records/table_turbo_frame.rb +37 -0
- data/app/components/databasium/records/utilities.rb +25 -0
- data/app/components/databasium/schemas/header_actions.rb +99 -0
- data/app/components/databasium/schemas/sidebar.rb +25 -0
- data/app/components/databasium/search_results/migrations.rb +37 -0
- data/app/components/databasium/search_results/models.rb +36 -0
- data/app/components/databasium/search_results/schema_models.rb +37 -0
- data/app/components/databasium/search_results/tables.rb +31 -0
- data/app/components/databasium/type_select.rb +35 -0
- data/app/controllers/databasium/application_controller.rb +68 -0
- data/app/controllers/databasium/homepage_controller.rb +5 -0
- data/app/controllers/databasium/migrations_controller.rb +186 -0
- data/app/controllers/databasium/models_controller.rb +105 -0
- data/app/controllers/databasium/records_controller.rb +156 -0
- data/app/controllers/databasium/schemas_controller.rb +52 -0
- data/app/helpers/databasium/application_helper.rb +4 -0
- data/app/helpers/databasium/heroicon_helper.rb +21 -0
- data/app/helpers/databasium/models_helper.rb +4 -0
- data/app/jobs/databasium/application_job.rb +4 -0
- data/app/mailers/databasium/application_mailer.rb +6 -0
- data/app/models/databasium/application_record.rb +5 -0
- data/app/models/model.json +0 -0
- data/app/services/databasium/migration.rb +176 -0
- data/app/services/databasium/model.rb +182 -0
- data/app/services/databasium/record.rb +65 -0
- data/app/services/databasium/schema.rb +146 -0
- data/app/views/base.rb +13 -0
- data/app/views/databasium/errors/non_development.rb +21 -0
- data/app/views/databasium/homepage/index.rb +29 -0
- data/app/views/databasium/migrations/index.rb +33 -0
- data/app/views/databasium/migrations/new.rb +29 -0
- data/app/views/databasium/models/index.rb +31 -0
- data/app/views/databasium/models/new.rb +37 -0
- data/app/views/databasium/records/index.rb +24 -0
- data/app/views/databasium/schemas/index.rb +39 -0
- data/app/views/layouts/databasium/application.rb +56 -0
- data/config/importmap.rb +12 -0
- data/config/initializers/heroicon.rb +12 -0
- data/config/initializers/pagy.rb +48 -0
- data/config/initializers/phlex.rb +19 -0
- data/config/routes.rb +31 -0
- data/config/tailwind.config.js +10 -0
- data/lib/databasium/engine.rb +57 -0
- data/lib/databasium/engine_mount.rb +37 -0
- data/lib/databasium/middleware/conditional_check_pending.rb +27 -0
- data/lib/databasium/templates/create_table_migration.rb.tt +29 -0
- data/lib/databasium/templates/migration.rb.tt +48 -0
- data/lib/databasium/templates/model.rb.tt +23 -0
- data/lib/databasium/version.rb +3 -0
- data/lib/databasium.rb +11 -0
- data/lib/tasks/databasium_tasks.rake +4 -0
- metadata +272 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Models::ModelPreview < Components::Base
|
|
4
|
+
def initialize(content:)
|
|
5
|
+
@content = content
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def view_template
|
|
9
|
+
div(id: "model_preview") do
|
|
10
|
+
div(class: "bg-panel border-1 border-border rounded-xl p-4 min-h-full flex-1") do
|
|
11
|
+
if @content
|
|
12
|
+
h1(class: "text-xl font-semibold mb-3 border-b-2 border-border pb-3") do
|
|
13
|
+
"Preview for Model"
|
|
14
|
+
end
|
|
15
|
+
pre(class: "bg-panel border-1 border-border rounded-xl p-4") { @content }
|
|
16
|
+
button(
|
|
17
|
+
type: "submit",
|
|
18
|
+
form: "model_form",
|
|
19
|
+
name: "commit",
|
|
20
|
+
value: "Create model file",
|
|
21
|
+
class: "bg-accent shadow-accent rounded-xl p-1 px-4 py-2 mt-2"
|
|
22
|
+
) { "Create model file" }
|
|
23
|
+
else
|
|
24
|
+
h1(class: "text-xl font-semibold") { "Please fill out the form to see the preview" }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Components
|
|
4
|
+
module Databasium
|
|
5
|
+
class Models::Sidebar < Components::Base
|
|
6
|
+
include Phlex::Rails::Helpers::TurboFrameTag
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def view_template
|
|
12
|
+
div(class: "flex flex-col gap-2", data: { controller: "search" }) do
|
|
13
|
+
render Components::Databasium::Forms::Search.new(
|
|
14
|
+
url: databasium.sidebar_models_path,
|
|
15
|
+
turbo_frame: "results",
|
|
16
|
+
placeholder: "Search for a model"
|
|
17
|
+
)
|
|
18
|
+
turbo_frame_tag("results", src: databasium.sidebar_models_path) do
|
|
19
|
+
p(class: "mt-2 animate-pulse") { "Loading models..." }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Models::Templates::Attribute < Models::Templates::Base
|
|
4
|
+
def initialize(name: nil, params: nil)
|
|
5
|
+
@name = name
|
|
6
|
+
@params = params
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def view_template
|
|
10
|
+
div(data: { controller: "attribute" }) { render_attribute_fields }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def render_attribute_fields
|
|
16
|
+
render_collapsable(
|
|
17
|
+
name: @name || "Attribute",
|
|
18
|
+
form: nil,
|
|
19
|
+
name_params: {
|
|
20
|
+
data: {
|
|
21
|
+
attribute_target: "name"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
class_name: ""
|
|
25
|
+
) do
|
|
26
|
+
div(class: "flex flex-col gap-2 bg-background p-3") do
|
|
27
|
+
div(class: "flex items-center gap-2") do
|
|
28
|
+
input(
|
|
29
|
+
type: "text",
|
|
30
|
+
name: "model[attributes][][name]",
|
|
31
|
+
value: @name,
|
|
32
|
+
data: {
|
|
33
|
+
action: "input->attribute#updateName",
|
|
34
|
+
attribute_target: "nameInput"
|
|
35
|
+
},
|
|
36
|
+
placeholder: "Attribute Name (e.g. email)",
|
|
37
|
+
class:
|
|
38
|
+
"border-2 rounded-xl px-2 py-1 border-border w-full h-full bg-background focus:outline-none"
|
|
39
|
+
)
|
|
40
|
+
render Components::Databasium::TypeSelect.new(
|
|
41
|
+
name: "model[attributes][][type]",
|
|
42
|
+
value: @params&.fetch(:type, nil)
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
attr_validations = @params&.fetch(:validations, nil)
|
|
46
|
+
render_validations(validations: attr_validations)
|
|
47
|
+
render_remove_button
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def render_remove_button
|
|
53
|
+
button(
|
|
54
|
+
type: "button",
|
|
55
|
+
class: "text-red-500",
|
|
56
|
+
data: {
|
|
57
|
+
action: "click->attribute#remove"
|
|
58
|
+
}
|
|
59
|
+
) { span { "Remove" } }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def render_validations(validations: nil)
|
|
63
|
+
render_collapsable(
|
|
64
|
+
name: "Validations",
|
|
65
|
+
form: nil,
|
|
66
|
+
data_targets: {
|
|
67
|
+
data: {
|
|
68
|
+
attribute_target: "validations"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
class_name: "border-collapse border-1 border-border py-2 rounded-xl"
|
|
72
|
+
) do
|
|
73
|
+
div(class: "flex items-center gap-2 py-1 px-3") do
|
|
74
|
+
span(class: "font-semibold") { "Add new Validation" }
|
|
75
|
+
button(
|
|
76
|
+
data: {
|
|
77
|
+
action: "click->model#add click->attribute#updateValidationName",
|
|
78
|
+
model_target_param: "validation",
|
|
79
|
+
model_container_param: "validationsContainer"
|
|
80
|
+
},
|
|
81
|
+
type: "button",
|
|
82
|
+
class: "text-blue-500"
|
|
83
|
+
) { heroicon "plus-circle", variant: :outline, options: { class: "w-8 h-8" } }
|
|
84
|
+
end
|
|
85
|
+
div(
|
|
86
|
+
class: "flex flex-col gap-2 divide-y divide-border",
|
|
87
|
+
data: {
|
|
88
|
+
model_target: "validationsContainer"
|
|
89
|
+
}
|
|
90
|
+
) do
|
|
91
|
+
validations&.each do |validation|
|
|
92
|
+
render Models::Templates::Validation.new(validation: validation, name: @name)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# </template>
|
|
2
|
+
|
|
3
|
+
module Components
|
|
4
|
+
module Databasium
|
|
5
|
+
class Models::Templates::Relation < Models::Templates::Base
|
|
6
|
+
def initialize(relation: nil, models: nil)
|
|
7
|
+
@relation = relation
|
|
8
|
+
@models = models
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def view_template
|
|
12
|
+
selected_relation = @relation&.fetch(:name, nil)
|
|
13
|
+
selected_model = @relation&.fetch(:type, nil)&.classify
|
|
14
|
+
div(class: "flex gap-2") do
|
|
15
|
+
select(
|
|
16
|
+
name: "model[relations][][type]",
|
|
17
|
+
class: "border-2 rounded-xl p-1 border-border w-full bg-background focus:outline-none"
|
|
18
|
+
) do
|
|
19
|
+
[
|
|
20
|
+
[ "belongs_to", "Belongs To" ],
|
|
21
|
+
[ "has_many", "Has Many" ],
|
|
22
|
+
[ "has_one", "Has One" ],
|
|
23
|
+
[ "has_and_belongs_to_many", "Has And Belongs To Many" ]
|
|
24
|
+
].each do |value, label|
|
|
25
|
+
option(value: value, selected: selected_relation == value) { label }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
input(
|
|
29
|
+
type: "search",
|
|
30
|
+
name: "model[relations][][table_name]",
|
|
31
|
+
placeholder: "Search or select model",
|
|
32
|
+
class: "border-2 rounded-xl p-1 border-border w-full bg-background focus:outline-none",
|
|
33
|
+
value: selected_model,
|
|
34
|
+
list: "models_datalist"
|
|
35
|
+
) { }
|
|
36
|
+
button(
|
|
37
|
+
type: "button",
|
|
38
|
+
class: "text-red-500",
|
|
39
|
+
data: {
|
|
40
|
+
action: "click->relation#removeRelation"
|
|
41
|
+
}
|
|
42
|
+
) { heroicon "x-mark", variant: :solid, options: { class: "w-8 h-8" } }
|
|
43
|
+
end
|
|
44
|
+
render_models_datalist
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def render_models_datalist
|
|
50
|
+
datalist(id: "models_datalist") do
|
|
51
|
+
@models&.each { |model| option(value: model.classify) { model } }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Components
|
|
4
|
+
module Databasium
|
|
5
|
+
class Models::Templates::Validation < Models::Templates::Base
|
|
6
|
+
TYPES = {
|
|
7
|
+
presence: "Presence",
|
|
8
|
+
uniqueness: "Uniqueness",
|
|
9
|
+
inclusion: "Inclusion",
|
|
10
|
+
exclusion: "Exclusion",
|
|
11
|
+
validates_associated: "Validates Associated",
|
|
12
|
+
numericality: "Numericality",
|
|
13
|
+
length: "Length",
|
|
14
|
+
acceptance: "Acceptance",
|
|
15
|
+
absence: "Absence",
|
|
16
|
+
confirmation: "Confirmation",
|
|
17
|
+
comparison: "Comparison",
|
|
18
|
+
format: "Format"
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
def initialize(validation: nil, name: nil)
|
|
22
|
+
@validation = validation
|
|
23
|
+
@name = name
|
|
24
|
+
@selected_validation = @validation&.fetch(:type, nil)
|
|
25
|
+
@validation_value = @validation&.fetch(:value, nil)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def view_template
|
|
29
|
+
div(
|
|
30
|
+
class: "p-2",
|
|
31
|
+
data: {
|
|
32
|
+
controller: "validation",
|
|
33
|
+
validation_selected_type_value: @selected_validation
|
|
34
|
+
}
|
|
35
|
+
) do
|
|
36
|
+
div(class: "flex gap-2") do
|
|
37
|
+
render_validation_name_input
|
|
38
|
+
div(class: "relative") do
|
|
39
|
+
render_validation_type_select
|
|
40
|
+
div(
|
|
41
|
+
class: "absolute -top-1.5 -right-[0.5rem]",
|
|
42
|
+
data: {
|
|
43
|
+
action:
|
|
44
|
+
"mouseenter->validation#showBasicInfo mouseleave->validation#hideBasicInfo"
|
|
45
|
+
}
|
|
46
|
+
) do
|
|
47
|
+
heroicon "information-circle", variant: :solid, options: { class: "w-5 h-5" }
|
|
48
|
+
render_basic_info
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
render_acceptance_suggestions
|
|
52
|
+
render_length_suggestions
|
|
53
|
+
render_uniqueness_suggestions
|
|
54
|
+
render_absence_suggestions
|
|
55
|
+
render_confirmation_suggestions
|
|
56
|
+
render_comparison_suggestions
|
|
57
|
+
render_format_suggestions
|
|
58
|
+
render_inclusion_suggestions
|
|
59
|
+
render_exclusion_suggestions
|
|
60
|
+
render_numericality_suggestions
|
|
61
|
+
render_validates_associated_suggestions
|
|
62
|
+
render_presence_suggestions
|
|
63
|
+
render_validation_value_input
|
|
64
|
+
render_x_button(action: "click->validation#remove")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def render_basic_info
|
|
72
|
+
div(
|
|
73
|
+
data: {
|
|
74
|
+
validation_target: "basicInfo"
|
|
75
|
+
},
|
|
76
|
+
class:
|
|
77
|
+
"hidden absolute z-20 w-64 p-4 mt-2 text-sm text-text bg-background border border-border rounded-xl shadow-xl bottom-full left-1/2 -translate-x-1/2"
|
|
78
|
+
) do
|
|
79
|
+
div(class: "relative") do
|
|
80
|
+
p(class: "font-semibold") { "Basic use case" }
|
|
81
|
+
p(class: "text-text", data: { validation_target: "basicInfoText" }) { "" }
|
|
82
|
+
div(
|
|
83
|
+
class:
|
|
84
|
+
"absolute -bottom-5.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-background border-b border-r border-border rotate-45"
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def render_validation_value_input
|
|
91
|
+
div(class: "flex gap-2 px-2 mt-1 relative w-full") do
|
|
92
|
+
input(
|
|
93
|
+
type: "search",
|
|
94
|
+
list: "acceptance-options",
|
|
95
|
+
name: "model[attributes][][validations][][value]",
|
|
96
|
+
class: "border-1 p-1 border-border w-full bg-background focus:outline-none",
|
|
97
|
+
placeholder: "Value (e.g. true)",
|
|
98
|
+
value: @validation_value,
|
|
99
|
+
data: {
|
|
100
|
+
validation_target: "valueInput"
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
div(class: "absolute -top-4 right-0 flex gap-1") do
|
|
104
|
+
render_add_additional_options_button(action: "allowNil", text: "Allow nil")
|
|
105
|
+
render_add_additional_options_button(action: "allowBlank", text: "Allow blank")
|
|
106
|
+
render_add_additional_options_button(action: "onAction", text: "On Action")
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def render_validation_type_select
|
|
112
|
+
select(
|
|
113
|
+
name: "model[attributes][][validations][][type]",
|
|
114
|
+
class: "border-2 rounded-xl p-1 border-border w-fill bg-background focus:outline-none",
|
|
115
|
+
data: {
|
|
116
|
+
action: "change->validation#updateType"
|
|
117
|
+
}
|
|
118
|
+
) do
|
|
119
|
+
TYPES.each do |value, label|
|
|
120
|
+
option(value: value.to_s, selected: @selected_validation == value.to_s) { label }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def render_validation_name_input
|
|
126
|
+
input(
|
|
127
|
+
type: "text",
|
|
128
|
+
name: "model[attributes][][validations][][name]",
|
|
129
|
+
value: @name,
|
|
130
|
+
data: {
|
|
131
|
+
attribute_target: "nameValidationInput"
|
|
132
|
+
},
|
|
133
|
+
class: "hidden"
|
|
134
|
+
)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def render_absence_suggestions
|
|
138
|
+
datalist(id: "absence-options") { render_base_boolean_values }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def render_acceptance_suggestions
|
|
142
|
+
datalist(id: "acceptance-options") do
|
|
143
|
+
render_base_boolean_values
|
|
144
|
+
option(value: '{ message: "must be agreed to" }') { "With message" }
|
|
145
|
+
option(value: '{ accept: "yes" }') { "Accept" }
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def render_confirmation_suggestions
|
|
150
|
+
datalist(id: "confirmation-options") do
|
|
151
|
+
render_base_boolean_values
|
|
152
|
+
option(value: "{ case_sensitive: false }") { "Case insensitive" }
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def render_comparison_suggestions
|
|
157
|
+
datalist(id: "comparison-options") do
|
|
158
|
+
option(value: "{ greater_than: 10 }") { "Greater than" }
|
|
159
|
+
option(value: "{ greater_than_or_equal_to: 10 }") { "Greater than or equal to" }
|
|
160
|
+
option(value: "{ equal_to: 10 }") { "Equal to" }
|
|
161
|
+
option(value: "{ less_than: 10 }") { "Less than" }
|
|
162
|
+
option(value: "{ less_than_or_equal_to: 10 }") { "Less than or equal to" }
|
|
163
|
+
option(value: "{ other_than: 10 }") { "Other than" }
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def render_format_suggestions
|
|
168
|
+
datalist(id: "format-options") do
|
|
169
|
+
option(value: "{ with: /[A-Z]/ }") { "With" }
|
|
170
|
+
option(value: "{ without: /[A-Z]/ }") { "Without" }
|
|
171
|
+
option(value: "{ with: /[A-Z]/, message: 'must be uppercase' }") { "With and message" }
|
|
172
|
+
option(value: "{ without: /[A-Z]/, message: 'must be lowercase' }") do
|
|
173
|
+
"Without and message"
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def render_inclusion_suggestions
|
|
179
|
+
datalist(id: "inclusion-options") do
|
|
180
|
+
option(value: "{ in: %w[a b c] }") { "Inclusion" }
|
|
181
|
+
option(value: "{ in: ->(i) { i.method } }") { "Inclusion with proc" }
|
|
182
|
+
option(value: "{ in: %w[a b c], message: 'must be a, b, or c' }") do
|
|
183
|
+
"Inclusion and message"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def render_exclusion_suggestions
|
|
189
|
+
datalist(id: "exclusion-options") do
|
|
190
|
+
option(value: "{ in: %w[a b c] }") { "Exclusion" }
|
|
191
|
+
option(value: "{ in: ->(i) { i.method } }") { "Exclusion with proc" }
|
|
192
|
+
option(value: "{ in: %w[a b c], message: 'must be a, b, or c' }") do
|
|
193
|
+
"Exclusion and message"
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def render_length_suggestions
|
|
199
|
+
datalist(id: "length-options") do
|
|
200
|
+
option(value: "{ minimum: 2 }") { "Minimum" }
|
|
201
|
+
option(value: "{ maximum: 10 }") { "Maximum" }
|
|
202
|
+
option(value: "{ in: 2..10 }") { "Minimum and maximum" }
|
|
203
|
+
option(value: "{ is: 10 }") { "Exact length" }
|
|
204
|
+
option(value: "{ in: 2..10, too_short: 'is too short', too_long: 'is too long' }") do
|
|
205
|
+
"Minimum and maximum with messages"
|
|
206
|
+
end
|
|
207
|
+
option(value: "{ in: 2..10, wrong_length: 'is the wrong length' }") do
|
|
208
|
+
"Minimum and maximum with generic message"
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def render_numericality_suggestions
|
|
214
|
+
datalist(id: "numericality-options") do
|
|
215
|
+
render_base_boolean_values
|
|
216
|
+
option(value: "{ only_integer: true }") { "Only integer" }
|
|
217
|
+
option(value: "{ greater_than: 10 }") { "Greater than" }
|
|
218
|
+
option(value: "{ greater_than_or_equal_to: 10 }") { "Greater than or equal to" }
|
|
219
|
+
option(value: "{ equal_to: 10 }") { "Equal to" }
|
|
220
|
+
option(value: "{ less_than: 10 }") { "Less than" }
|
|
221
|
+
option(value: "{ less_than_or_equal_to: 10 }") { "Less than or equal to" }
|
|
222
|
+
option(value: "{ other_than: 10 }") { "Other than" }
|
|
223
|
+
option(value: "{ in: 1..10 }") { "In range" }
|
|
224
|
+
option(value: "{ odd: true }") { "Odd" }
|
|
225
|
+
option(value: "{ even: true }") { "Even" }
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def render_presence_suggestions
|
|
230
|
+
datalist(id: "presence-options") { render_base_boolean_values }
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def render_uniqueness_suggestions
|
|
234
|
+
datalist(id: "uniqueness-options") do
|
|
235
|
+
render_base_boolean_values
|
|
236
|
+
option(value: "{ scope: :column_name }") { "Scope" }
|
|
237
|
+
option(value: "{ scope: :column_name, message: 'must be unique' }") do
|
|
238
|
+
"Scope and with message"
|
|
239
|
+
end
|
|
240
|
+
option(value: "{ case_sensitive: false }") { "Case insensitive" }
|
|
241
|
+
option(value: '{ conditions: -> { where(column: "value") } }') { "Conditions" }
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def render_validates_associated_suggestions
|
|
246
|
+
datalist(id: "validates_associated-options") do
|
|
247
|
+
option(value: ":model_name") { "Validates associated" }
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def render_base_boolean_values
|
|
252
|
+
option(value: "true") { "If you woud like to true" }
|
|
253
|
+
option(value: "false") { "False" }
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def render_add_additional_options_button(action: nil, text: nil)
|
|
257
|
+
button(
|
|
258
|
+
type: "button",
|
|
259
|
+
class:
|
|
260
|
+
"text-text text-xs p-0.5 px-2 border-1 border-border rounded-xl bg-panel hover:bg-panel-hover cursor-pointer",
|
|
261
|
+
data: {
|
|
262
|
+
action: "validation##{action}"
|
|
263
|
+
}
|
|
264
|
+
) { text }
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def render_string_value_suggestions
|
|
268
|
+
datalist(id: "string-options") do
|
|
269
|
+
option(value: "true") { "If you woud like to true" }
|
|
270
|
+
option(value: "false") { "False" }
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def render_button_suggestion(value: nil, type: nil)
|
|
275
|
+
button(
|
|
276
|
+
type: "button",
|
|
277
|
+
class: "text-text",
|
|
278
|
+
data: {
|
|
279
|
+
validation_target: "#{value}#{type&.upcase}"
|
|
280
|
+
}
|
|
281
|
+
) { value }
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Navigation::BaseIcon < Components::Base
|
|
4
|
+
include Phlex::Rails::Helpers::LinkTo
|
|
5
|
+
include ::Databasium::HeroiconHelper
|
|
6
|
+
|
|
7
|
+
attr_reader :element
|
|
8
|
+
|
|
9
|
+
def initialize(element:)
|
|
10
|
+
@element = element
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def icon_classes
|
|
16
|
+
class_names(
|
|
17
|
+
"flex justify-between items-center gap-2
|
|
18
|
+
border-1 border-border p-1 px-3 rounded-xl cursor-pointer hover:border-hover",
|
|
19
|
+
"bg-accent shadow-accent" => element[:active]
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def render_icon(icon)
|
|
24
|
+
heroicon icon, variant: :outline, options: { class: "w-6 h-6" }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def render_text(text)
|
|
28
|
+
p(class: "text-main-text text-base text-nowrap") { text }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Navigation::FrontendIcon < Navigation::BaseIcon
|
|
4
|
+
def initialize(element:, data_params: {})
|
|
5
|
+
super(element: element)
|
|
6
|
+
@data_params = data_params
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def view_template
|
|
10
|
+
div(class: icon_classes, data: @data_params) do
|
|
11
|
+
render_icon(element[:icon])
|
|
12
|
+
render_text(element[:text])
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Navigation::GetIcon < Navigation::BaseIcon
|
|
4
|
+
include Phlex::Rails::Helpers::LinkTo
|
|
5
|
+
|
|
6
|
+
def initialize(element:, turbo_frame: nil)
|
|
7
|
+
super(element: element)
|
|
8
|
+
@turbo_frame = turbo_frame
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def view_template
|
|
12
|
+
link_to(
|
|
13
|
+
element[:path],
|
|
14
|
+
class: icon_classes,
|
|
15
|
+
data: {
|
|
16
|
+
turbo_method: :get,
|
|
17
|
+
turbo_stream: true
|
|
18
|
+
}
|
|
19
|
+
) do
|
|
20
|
+
render_icon(element[:icon])
|
|
21
|
+
render_text(element[:text])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Navigation::Icon < Components::Base
|
|
4
|
+
include Phlex::Rails::Helpers::LinkTo
|
|
5
|
+
|
|
6
|
+
attr_reader :element
|
|
7
|
+
|
|
8
|
+
def initialize(element:)
|
|
9
|
+
@element = element
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template
|
|
13
|
+
case element[:method]
|
|
14
|
+
when :frontend
|
|
15
|
+
render Navigation::FrontendIcon.new(element: element, data_params: element[:data_params])
|
|
16
|
+
when :get
|
|
17
|
+
render Navigation::GetIcon.new(element: element, turbo_frame: element[:turbo_frame])
|
|
18
|
+
when :post
|
|
19
|
+
render Navigation::PostIcon.new(element: element)
|
|
20
|
+
when :put
|
|
21
|
+
render Navigation::PutIcon.new(element: element)
|
|
22
|
+
else
|
|
23
|
+
p { "Please provide method to icon component" }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Components
|
|
4
|
+
module Databasium
|
|
5
|
+
class Navigation::IconPanel < Components::Base
|
|
6
|
+
include Phlex::Rails::Helpers::LinkTo
|
|
7
|
+
|
|
8
|
+
# element format: { icon: "icon-name", text: "text", path: "path", method: :get | :post | frontend, turbo_frame: "frame_id" }
|
|
9
|
+
def initialize(icons_with_text: [])
|
|
10
|
+
@icons_with_text = icons_with_text
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def view_template(&block)
|
|
14
|
+
form(&block)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def form(&block)
|
|
20
|
+
div(class: "align-items-center justify-items-center flex gap-2") do
|
|
21
|
+
@icons_with_text.each { |element| render Navigation::Icon.new(element: element) }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Navigation::PostIcon < Navigation::BaseIcon
|
|
4
|
+
include Phlex::Rails::Helpers::LinkTo
|
|
5
|
+
|
|
6
|
+
def initialize(element:)
|
|
7
|
+
super(element: element)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template
|
|
11
|
+
link_to(
|
|
12
|
+
element[:path],
|
|
13
|
+
class: icon_classes,
|
|
14
|
+
data: {
|
|
15
|
+
turbo_method: :post,
|
|
16
|
+
turbo_frame: "_top"
|
|
17
|
+
}
|
|
18
|
+
) do
|
|
19
|
+
render_icon(element[:icon])
|
|
20
|
+
render_text(element[:text])
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Components
|
|
2
|
+
module Databasium
|
|
3
|
+
class Navigation::PutIcon < Navigation::BaseIcon
|
|
4
|
+
include Phlex::Rails::Helpers::LinkTo
|
|
5
|
+
|
|
6
|
+
def initialize(element:)
|
|
7
|
+
super(element: element)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template
|
|
11
|
+
link_to(element[:path], class: icon_classes, data: { turbo_method: :put }) do
|
|
12
|
+
render_icon(element[:icon])
|
|
13
|
+
render_text(element[:text])
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|