uchi 0.1.5 → 0.1.6
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/app/assets/javascripts/uchi/application.js +2655 -24
- data/app/assets/javascripts/uchi.js +11 -0
- data/app/assets/stylesheets/uchi/application.css +982 -1311
- data/app/assets/tailwind/uchi.css +4 -4
- data/app/components/uchi/field/belongs_to/edit.html.erb +1 -1
- data/app/components/uchi/field/belongs_to/index.html.erb +1 -1
- data/app/components/uchi/field/belongs_to/show.html.erb +3 -5
- data/app/components/uchi/field/belongs_to.rb +30 -7
- data/app/components/uchi/field/boolean/edit.html.erb +1 -1
- data/app/components/uchi/field/date/edit.html.erb +1 -1
- data/app/components/uchi/field/date_time/edit.html.erb +1 -1
- data/app/components/uchi/field/file/edit.html.erb +1 -1
- data/app/components/uchi/field/file/index.html.erb +2 -1
- data/app/components/uchi/field/file/show.html.erb +3 -2
- data/app/components/uchi/field/has_and_belongs_to_many/show.html.erb +5 -3
- data/app/components/uchi/field/has_many/show.html.erb +5 -3
- data/app/components/uchi/field/id/index.html.erb +1 -1
- data/app/components/uchi/field/id/show.html.erb +1 -1
- data/app/components/uchi/field/image/edit.html.erb +1 -1
- data/app/components/uchi/field/image/index.html.erb +2 -1
- data/app/components/uchi/field/image/show.html.erb +2 -1
- data/app/components/uchi/field/number/edit.html.erb +1 -1
- data/app/components/uchi/field/string/edit.html.erb +1 -1
- data/app/components/uchi/field/text/edit.html.erb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb.rb +5 -5
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_home.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/current.rb +3 -3
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/first.rb +4 -4
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item.rb +4 -4
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_separator.rb +7 -5
- data/app/components/uchi/flowbite/button/outline.rb +37 -0
- data/app/components/uchi/flowbite/button/pill.rb +40 -0
- data/app/components/uchi/flowbite/button.rb +93 -0
- data/app/components/uchi/flowbite/card/card.html.erb +7 -0
- data/app/components/uchi/flowbite/card/title.rb +37 -0
- data/app/components/uchi/flowbite/card.rb +84 -0
- data/app/components/{flowbite → uchi/flowbite}/input/checkbox.rb +7 -7
- data/app/components/{flowbite → uchi/flowbite}/input/date.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/date_time.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/email.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/field.rb +11 -10
- data/app/components/uchi/flowbite/input/file.rb +30 -0
- data/app/components/{flowbite → uchi/flowbite}/input/hint.rb +6 -5
- data/app/components/{flowbite → uchi/flowbite}/input/label.rb +8 -7
- data/app/components/{flowbite → uchi/flowbite}/input/number.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/password.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/phone.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/radio_button.rb +7 -7
- data/app/components/{flowbite → uchi/flowbite}/input/select.rb +16 -7
- data/app/components/uchi/flowbite/input/textarea.rb +42 -0
- data/app/components/{flowbite → uchi/flowbite}/input/url.rb +1 -1
- data/app/components/uchi/flowbite/input/validation_error.rb +39 -0
- data/app/components/uchi/flowbite/input_field/checkbox.html.erb +9 -0
- data/app/components/{flowbite → uchi/flowbite}/input_field/checkbox.rb +10 -6
- data/app/components/{flowbite → uchi/flowbite}/input_field/date.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/date_time.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/email.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/file.rb +2 -2
- data/app/components/uchi/flowbite/input_field/input_field.html.erb +9 -0
- data/app/components/{flowbite → uchi/flowbite}/input_field/number.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/password.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/phone.rb +2 -2
- data/app/components/uchi/flowbite/input_field/radio_button.html.erb +9 -0
- data/app/components/{flowbite → uchi/flowbite}/input_field/radio_button.rb +13 -9
- data/app/components/{flowbite → uchi/flowbite}/input_field/select.rb +7 -3
- data/app/components/{flowbite → uchi/flowbite}/input_field/text.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input_field/textarea.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/url.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field.rb +19 -5
- data/app/components/uchi/flowbite/link.rb +41 -0
- data/app/components/{flowbite → uchi/flowbite}/style.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/toast/icon.rb +1 -1
- data/app/components/uchi/flowbite/toast/toast.html.erb +40 -0
- data/app/components/{flowbite → uchi/flowbite}/toast.rb +2 -2
- data/app/components/uchi/ui/actions/dropdown/dropdown.html.erb +59 -0
- data/app/components/uchi/ui/actions/dropdown.rb +32 -0
- data/app/components/uchi/ui/breadcrumb/breadcrumb.html.erb +4 -4
- data/app/components/uchi/ui/form/input/collection_checkboxes.html.erb +2 -1
- data/app/components/uchi/ui/form/input/collection_checkboxes.rb +12 -17
- data/app/components/uchi/ui/frame/frame.html.erb +6 -1
- data/app/components/uchi/ui/index/records_table/records_table.html.erb +109 -18
- data/app/components/uchi/ui/index/records_table/search_form/search_form.html.erb +21 -5
- data/app/components/uchi/ui/navigation/navigation.html.erb +9 -0
- data/app/components/uchi/ui/navigation.rb +37 -0
- data/app/components/uchi/ui/no_value/no_value.html.erb +1 -0
- data/app/components/uchi/ui/no_value.rb +8 -0
- data/app/components/uchi/ui/page_header/page_header.html.erb +7 -2
- data/app/components/uchi/ui/pagination/current_link.html.erb +1 -1
- data/app/components/uchi/ui/pagination/gap.html.erb +7 -1
- data/app/components/uchi/ui/pagination/link.html.erb +1 -1
- data/app/components/uchi/ui/pagination/next_link.html.erb +18 -3
- data/app/components/uchi/ui/pagination/pagination.html.erb +3 -1
- data/app/components/uchi/ui/pagination/previous_link.html.erb +18 -3
- data/app/components/uchi/ui/pagination.rb +1 -1
- data/app/components/uchi/ui/show/attribute_fields/attribute_fields.html.erb +4 -3
- data/app/components/uchi/ui/spinner/spinner.html.erb +17 -3
- data/app/controllers/uchi/actions/executions_controller.rb +107 -0
- data/app/controllers/uchi/repository_controller.rb +21 -1
- data/app/views/layouts/uchi/_flash_messages.html.erb +1 -1
- data/app/views/layouts/uchi/application.html.erb +10 -16
- data/app/views/uchi/navigation/_main.html.erb +9 -0
- data/app/views/uchi/repository/edit.html.erb +2 -2
- data/app/views/uchi/repository/index.html.erb +12 -3
- data/app/views/uchi/repository/new.html.erb +2 -2
- data/app/views/uchi/repository/show.html.erb +13 -2
- data/lib/generators/uchi/controller/templates/controller.rb.tt +0 -5
- data/lib/generators/uchi/scaffold/scaffold_generator.rb +15 -0
- data/lib/uchi/action.rb +84 -0
- data/lib/uchi/action_response.rb +108 -0
- data/lib/uchi/repository/translate.rb +14 -0
- data/lib/uchi/repository.rb +25 -0
- data/lib/uchi/version.rb +1 -1
- data/lib/uchi.rb +2 -0
- metadata +63 -50
- data/app/components/flowbite/button/outline.rb +0 -22
- data/app/components/flowbite/button/pill.rb +0 -40
- data/app/components/flowbite/button.rb +0 -92
- data/app/components/flowbite/card.rb +0 -45
- data/app/components/flowbite/input/file.rb +0 -30
- data/app/components/flowbite/input/textarea.rb +0 -42
- data/app/components/flowbite/input/validation_error.rb +0 -11
- data/app/components/flowbite/input_field/checkbox.html.erb +0 -14
- data/app/components/flowbite/input_field/input_field.html.erb +0 -8
- data/app/components/flowbite/input_field/radio_button.html.erb +0 -14
- data/app/components/flowbite/link.rb +0 -21
- data/app/components/flowbite/toast/toast.html.erb +0 -11
- /data/app/components/{flowbite → uchi/flowbite}/toast/icon.html.erb +0 -0
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<% end %>
|
|
15
15
|
|
|
16
16
|
<div class="mx-4 md:mx-0">
|
|
17
|
-
<%= render(Flowbite::Card.new) do %>
|
|
17
|
+
<%= render(Uchi::Flowbite::Card.new) do %>
|
|
18
18
|
<%= form_with model: @record, url: @repository.routes.path_for(:update, id: @record.id) do |form| %>
|
|
19
19
|
<div class="space-y-6">
|
|
20
20
|
<% @repository.fields_for_edit.each do |field| %>
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<% end %>
|
|
32
32
|
|
|
33
33
|
<%= render(Uchi::Ui::Form::Footer.new) do |footer| %>
|
|
34
|
-
<%= footer.with_action { render(Flowbite::Button.new) { @repository.translate.submit_button } } %>
|
|
34
|
+
<%= footer.with_action { render(Uchi::Flowbite::Button.new) { @repository.translate.submit_button } } %>
|
|
35
35
|
<%= footer.with_action { link_to(@repository.translate.link_to_cancel, path_for_cancel(default: @repository.routes.path_for(:show, id: @record.id))) } %>
|
|
36
36
|
<% end %>
|
|
37
37
|
</div>
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
title: @repository.translate.title_for_index,
|
|
7
7
|
)) do |header| %>
|
|
8
8
|
<% header.with_action do %>
|
|
9
|
-
<%= link_to(@repository.translate.link_to_new, @repository.routes.path_for(:new), class: Flowbite::Button.classes) %>
|
|
9
|
+
<%= link_to(@repository.translate.link_to_new, @repository.routes.path_for(:new), class: Uchi::Flowbite::Button.classes) %>
|
|
10
10
|
<% end %>
|
|
11
|
+
|
|
11
12
|
<% header.with_breadcrumb(items: [
|
|
12
13
|
{href: @repository.routes.root_path, label: @repository.translate.breadcrumb_label_for_root },
|
|
13
14
|
{href: @repository.routes.path_for(:index), label: @repository.translate.breadcrumb_label(:index) }
|
|
@@ -19,12 +20,19 @@
|
|
|
19
20
|
repository: @repository,
|
|
20
21
|
scope: (scoped? ? scope_params : nil),
|
|
21
22
|
)) do %>
|
|
22
|
-
|
|
23
|
+
<%# Styles from https://flowbite.com/docs/components/tables/#default-table %>
|
|
24
|
+
<div
|
|
25
|
+
class="
|
|
26
|
+
relative overflow-x-auto bg-neutral-primary-soft rounded-base border
|
|
27
|
+
border-default shadow-xs
|
|
28
|
+
"
|
|
29
|
+
>
|
|
23
30
|
<% if @repository.searchable? %>
|
|
24
31
|
<div class="px-3 py-3">
|
|
25
32
|
<%= render(Uchi::Ui::Index::RecordsTable::SearchForm.new(params: params, repository: @repository)) %>
|
|
26
33
|
</div>
|
|
27
34
|
<% end %>
|
|
35
|
+
|
|
28
36
|
<% if @records.any? %>
|
|
29
37
|
<%= render(Uchi::Ui::Index::RecordsTable.new(
|
|
30
38
|
columns: @columns,
|
|
@@ -35,11 +43,12 @@
|
|
|
35
43
|
scope: (scoped? ? scope_params : nil),
|
|
36
44
|
)) %>
|
|
37
45
|
<% else %>
|
|
38
|
-
<div class="p-6 text-center text-
|
|
46
|
+
<div class="p-6 text-center text-body-subtle">
|
|
39
47
|
<%= @repository.translate.no_records_found %>
|
|
40
48
|
</div>
|
|
41
49
|
<% end %>
|
|
42
50
|
</div>
|
|
51
|
+
|
|
43
52
|
<% if @records.any? %>
|
|
44
53
|
<div class="my-4 flex justify-center">
|
|
45
54
|
<%= render(Uchi::Ui::Pagination.new(paginator: @paginator)) %>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
]) %>
|
|
13
13
|
<% end %>
|
|
14
14
|
|
|
15
|
-
<%= render(Flowbite::Card.new) do %>
|
|
15
|
+
<%= render(Uchi::Flowbite::Card.new) do %>
|
|
16
16
|
<%= form_with model: @record, url: @repository.routes.path_for(:create) do |form| %>
|
|
17
17
|
<div class="space-y-6">
|
|
18
18
|
<% @repository.fields_for_edit.each do |field| %>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<% end %>
|
|
30
30
|
|
|
31
31
|
<%= render(Uchi::Ui::Form::Footer.new) do |footer| %>
|
|
32
|
-
<%= footer.with_action { render(Flowbite::Button.new) { @repository.translate.submit_button } } %>
|
|
32
|
+
<%= footer.with_action { render(Uchi::Flowbite::Button.new) { @repository.translate.submit_button } } %>
|
|
33
33
|
<%= footer.with_action { link_to(@repository.translate.link_to_cancel, path_for_cancel(default: @repository.routes.path_for(:index))) } %>
|
|
34
34
|
<% end %>
|
|
35
35
|
</div>
|
|
@@ -6,12 +6,22 @@
|
|
|
6
6
|
title: @repository.translate.title_for_show(@record),
|
|
7
7
|
)
|
|
8
8
|
) do |header| %>
|
|
9
|
+
<% if @repository.actions.any? %>
|
|
10
|
+
<% header.with_action do %>
|
|
11
|
+
<%= render(Uchi::Ui::Actions::Dropdown.new(
|
|
12
|
+
actions: @repository.actions,
|
|
13
|
+
record: @record,
|
|
14
|
+
repository: @repository
|
|
15
|
+
)) %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
9
19
|
<% header.with_action do %>
|
|
10
20
|
<%= button_to(
|
|
11
21
|
@repository.translate.link_to_destroy(@record),
|
|
12
22
|
@repository.routes.path_for(:destroy, id: @record.id),
|
|
13
23
|
method: :delete,
|
|
14
|
-
class: Flowbite::Button.classes(style: :
|
|
24
|
+
class: Uchi::Flowbite::Button.classes(style: :danger),
|
|
15
25
|
data: {
|
|
16
26
|
:"turbo-confirm" => @repository.translate.destroy_dialog_title(@record)
|
|
17
27
|
}
|
|
@@ -19,7 +29,7 @@
|
|
|
19
29
|
<% end %>
|
|
20
30
|
|
|
21
31
|
<% header.with_action do %>
|
|
22
|
-
<%= link_to(@repository.translate.link_to_edit(@record), @repository.routes.path_for(:edit, id: @record.id), class: Flowbite::Button.classes) %>
|
|
32
|
+
<%= link_to(@repository.translate.link_to_edit(@record), @repository.routes.path_for(:edit, id: @record.id), class: Uchi::Flowbite::Button.classes) %>
|
|
23
33
|
<% end %>
|
|
24
34
|
|
|
25
35
|
<% header.with_breadcrumb(items: [
|
|
@@ -36,6 +46,7 @@
|
|
|
36
46
|
)) %>
|
|
37
47
|
|
|
38
48
|
<% association_fields = @repository.fields_for_show.select{ |field| field.group_as(:show) == :associations } %>
|
|
49
|
+
|
|
39
50
|
<% association_fields.each do |field| %>
|
|
40
51
|
<%= render(field.show_component(record: @record, repository: @repository)) %>
|
|
41
52
|
<% end %>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/rails/resource/resource_generator"
|
|
4
|
+
|
|
5
|
+
module Uchi
|
|
6
|
+
class ScaffoldGenerator < Rails::Generators::ResourceGenerator # :nodoc:
|
|
7
|
+
remove_hook_for :resource_controller
|
|
8
|
+
remove_hook_for :resource_route
|
|
9
|
+
remove_class_option :actions
|
|
10
|
+
|
|
11
|
+
def generate_repository
|
|
12
|
+
generate("uchi:repository", name)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/uchi/action.rb
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
# Base class for all Uchi actions.
|
|
5
|
+
#
|
|
6
|
+
# Actions allow you to perform custom operations on one or more records from
|
|
7
|
+
# a repository. Examples include publishing posts, exporting data, or sending
|
|
8
|
+
# notifications.
|
|
9
|
+
#
|
|
10
|
+
# To create an action, subclass this class and implement the `perform` method:
|
|
11
|
+
#
|
|
12
|
+
# class PublishPost < Uchi::Action
|
|
13
|
+
# def perform(records, input = {})
|
|
14
|
+
# records.each { |record| record.update!(published: true) }
|
|
15
|
+
# Uchi::ActionResponse.success("Published #{records.size} posts")
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# Actions are registered on repositories via the `actions` method:
|
|
20
|
+
#
|
|
21
|
+
# class PostRepository < Uchi::Repository
|
|
22
|
+
# def actions
|
|
23
|
+
# [PublishPost.new]
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
class Action
|
|
27
|
+
# Returns the display name for this action.
|
|
28
|
+
#
|
|
29
|
+
# By default, this looks up the translation key
|
|
30
|
+
# `uchi.action.[action_key].name` and falls back to the humanized class
|
|
31
|
+
# name.
|
|
32
|
+
#
|
|
33
|
+
# @return [String]
|
|
34
|
+
def name
|
|
35
|
+
translate(:name, default: self.class.name.demodulize.titleize)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns the list of fields to show in the action form.
|
|
39
|
+
#
|
|
40
|
+
# Fields are instances of Uchi::Field subclasses (e.g., Field::String,
|
|
41
|
+
# Field::Boolean).
|
|
42
|
+
#
|
|
43
|
+
# @return [Array<Uchi::Field>]
|
|
44
|
+
def fields
|
|
45
|
+
[]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Performs the action on the given records.
|
|
49
|
+
#
|
|
50
|
+
# This method must be implemented in subclasses.
|
|
51
|
+
#
|
|
52
|
+
# @param records [ActiveRecord::Relation, Array] - The records to operate on
|
|
53
|
+
# @param input [Hash] - Hash of field values from the action form
|
|
54
|
+
# @return [Uchi::ActionResponse]
|
|
55
|
+
def perform(records, input = {})
|
|
56
|
+
raise NotImplementedError, "#{self.class}#perform must be implemented"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns true if this action requires input fields.
|
|
60
|
+
#
|
|
61
|
+
# @return [Boolean]
|
|
62
|
+
def requires_input?
|
|
63
|
+
fields.any?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
# Looks up i18n key with fallback
|
|
69
|
+
# @param key [Symbol] - the key to look up (e.g., :name)
|
|
70
|
+
# @param default [String] - fallback value
|
|
71
|
+
# @param options [Hash] - additional i18n options (count, etc.)
|
|
72
|
+
# @return [String, nil]
|
|
73
|
+
def translate(key, default:, **options)
|
|
74
|
+
i18n_key = "action.#{translation_key}.#{key}"
|
|
75
|
+
Uchi::I18n.translate(i18n_key, default: default, **options)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns the i18n key segment for this action
|
|
79
|
+
# Example: PublishPost -> "publish_post"
|
|
80
|
+
def translation_key
|
|
81
|
+
self.class.name.underscore.tr("/", ".")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
# Represents the response from executing an action.
|
|
5
|
+
#
|
|
6
|
+
# ActionResponse uses a builder pattern for fluent chaining:
|
|
7
|
+
#
|
|
8
|
+
# ActionResponse.success("Done").redirect_to(path: "/posts")
|
|
9
|
+
# ActionResponse.error("Failed").message("Try again later")
|
|
10
|
+
# ActionResponse.success("Exported").download(file_path: path, filename: "data.csv")
|
|
11
|
+
class ActionResponse
|
|
12
|
+
attr_reader :status, :message_text, :redirect_path, :file_path, :filename, :turbo_stream_block
|
|
13
|
+
|
|
14
|
+
# Creates a successful response with an optional message.
|
|
15
|
+
#
|
|
16
|
+
# @param message [String, nil] - Success message to display
|
|
17
|
+
# @return [ActionResponse]
|
|
18
|
+
def self.success(message = nil)
|
|
19
|
+
new(status: :success, message: message)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Creates an error response with an optional message.
|
|
23
|
+
#
|
|
24
|
+
# @param message [String, nil] - Error message to display
|
|
25
|
+
# @return [ActionResponse]
|
|
26
|
+
def self.error(message = nil)
|
|
27
|
+
new(status: :error, message: message)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def initialize(status:, message: nil)
|
|
31
|
+
@status = status
|
|
32
|
+
@message_text = message
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Sets the message to display.
|
|
36
|
+
#
|
|
37
|
+
# @param text [String] - The message text
|
|
38
|
+
# @return [ActionResponse] self for chaining
|
|
39
|
+
def message(text)
|
|
40
|
+
@message_text = text
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Sets a redirect path.
|
|
45
|
+
#
|
|
46
|
+
# @param path [String] - The path to redirect to
|
|
47
|
+
# @return [ActionResponse] self for chaining
|
|
48
|
+
def redirect_to(path:)
|
|
49
|
+
@redirect_path = path
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Sets a file to download.
|
|
54
|
+
#
|
|
55
|
+
# @param file_path [String] - Path to the file
|
|
56
|
+
# @param filename [String] - Name for the downloaded file
|
|
57
|
+
# @return [ActionResponse] self for chaining
|
|
58
|
+
def download(file_path:, filename:)
|
|
59
|
+
@file_path = file_path
|
|
60
|
+
@filename = filename
|
|
61
|
+
self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Sets a custom Turbo Stream response.
|
|
65
|
+
#
|
|
66
|
+
# @yield [stream] Provides a Turbo Stream builder
|
|
67
|
+
# @return [ActionResponse] self for chaining
|
|
68
|
+
def turbo_stream(&block)
|
|
69
|
+
@turbo_stream_block = block
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Returns true if this is a success response.
|
|
74
|
+
#
|
|
75
|
+
# @return [Boolean]
|
|
76
|
+
def success?
|
|
77
|
+
status == :success
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns true if this is an error response.
|
|
81
|
+
#
|
|
82
|
+
# @return [Boolean]
|
|
83
|
+
def error?
|
|
84
|
+
status == :error
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns true if this response includes a redirect.
|
|
88
|
+
#
|
|
89
|
+
# @return [Boolean]
|
|
90
|
+
def redirect?
|
|
91
|
+
!redirect_path.nil?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns true if this response includes a download.
|
|
95
|
+
#
|
|
96
|
+
# @return [Boolean]
|
|
97
|
+
def download?
|
|
98
|
+
!file_path.nil?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Returns true if this response includes a custom Turbo Stream.
|
|
102
|
+
#
|
|
103
|
+
# @return [Boolean]
|
|
104
|
+
def turbo_stream?
|
|
105
|
+
!turbo_stream_block.nil?
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -5,6 +5,20 @@ module Uchi
|
|
|
5
5
|
class Translate
|
|
6
6
|
attr_reader :repository
|
|
7
7
|
|
|
8
|
+
# Returns the label for the actions button in the UI.
|
|
9
|
+
#
|
|
10
|
+
# Returns the first of the following that is present:
|
|
11
|
+
# 1. uchi.repository.author.button.actions
|
|
12
|
+
# 2. uchi.common.actions
|
|
13
|
+
# 3. "Actions"
|
|
14
|
+
def actions_button_label
|
|
15
|
+
first_present_value(
|
|
16
|
+
translate(i18n_scope("button.actions"), default: nil),
|
|
17
|
+
translate("common.actions", default: nil),
|
|
18
|
+
"Actions"
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
8
22
|
# Returns the breadcrumb label for the given page.
|
|
9
23
|
#
|
|
10
24
|
# Example translation key:
|
data/lib/uchi/repository.rb
CHANGED
|
@@ -61,6 +61,16 @@ module Uchi
|
|
|
61
61
|
apply_sort_order(query, sort_order)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# Finds multiple records by their IDs. If a record is not found, it is
|
|
65
|
+
# ignored.
|
|
66
|
+
#
|
|
67
|
+
# @param ids [Array<Integer>] The IDs of the records to find
|
|
68
|
+
#
|
|
69
|
+
# @return [ActiveRecord::Relation] The found records
|
|
70
|
+
def find_many(ids)
|
|
71
|
+
model.where(id: ids)
|
|
72
|
+
end
|
|
73
|
+
|
|
64
74
|
def find(id)
|
|
65
75
|
model.find(id)
|
|
66
76
|
end
|
|
@@ -74,6 +84,21 @@ module Uchi
|
|
|
74
84
|
[]
|
|
75
85
|
end
|
|
76
86
|
|
|
87
|
+
# Returns the list of actions available for this repository.
|
|
88
|
+
#
|
|
89
|
+
# Actions are instances of Uchi::Action subclasses that can be executed
|
|
90
|
+
# on one or more records.
|
|
91
|
+
#
|
|
92
|
+
# Example:
|
|
93
|
+
# def actions
|
|
94
|
+
# [PublishPost.new, ExportToCsv.new]
|
|
95
|
+
# end
|
|
96
|
+
#
|
|
97
|
+
# @return [Array<Uchi::Action>]
|
|
98
|
+
def actions
|
|
99
|
+
[]
|
|
100
|
+
end
|
|
101
|
+
|
|
77
102
|
def model
|
|
78
103
|
self.class.model
|
|
79
104
|
end
|
data/lib/uchi/version.rb
CHANGED
data/lib/uchi.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: uchi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jakob Skjerning
|
|
@@ -68,55 +68,6 @@ files:
|
|
|
68
68
|
- app/assets/stylesheets/uchi/application.css
|
|
69
69
|
- app/assets/stylesheets/uchi/uchi.css
|
|
70
70
|
- app/assets/tailwind/uchi.css
|
|
71
|
-
- app/components/flowbite/breadcrumb.rb
|
|
72
|
-
- app/components/flowbite/breadcrumb_home.rb
|
|
73
|
-
- app/components/flowbite/breadcrumb_item.rb
|
|
74
|
-
- app/components/flowbite/breadcrumb_item/current.rb
|
|
75
|
-
- app/components/flowbite/breadcrumb_item/first.rb
|
|
76
|
-
- app/components/flowbite/breadcrumb_separator.rb
|
|
77
|
-
- app/components/flowbite/button.rb
|
|
78
|
-
- app/components/flowbite/button/outline.rb
|
|
79
|
-
- app/components/flowbite/button/pill.rb
|
|
80
|
-
- app/components/flowbite/card.rb
|
|
81
|
-
- app/components/flowbite/input/checkbox.rb
|
|
82
|
-
- app/components/flowbite/input/date.rb
|
|
83
|
-
- app/components/flowbite/input/date_time.rb
|
|
84
|
-
- app/components/flowbite/input/email.rb
|
|
85
|
-
- app/components/flowbite/input/field.rb
|
|
86
|
-
- app/components/flowbite/input/file.rb
|
|
87
|
-
- app/components/flowbite/input/hint.rb
|
|
88
|
-
- app/components/flowbite/input/label.rb
|
|
89
|
-
- app/components/flowbite/input/number.rb
|
|
90
|
-
- app/components/flowbite/input/password.rb
|
|
91
|
-
- app/components/flowbite/input/phone.rb
|
|
92
|
-
- app/components/flowbite/input/radio_button.rb
|
|
93
|
-
- app/components/flowbite/input/select.rb
|
|
94
|
-
- app/components/flowbite/input/textarea.rb
|
|
95
|
-
- app/components/flowbite/input/url.rb
|
|
96
|
-
- app/components/flowbite/input/validation_error.rb
|
|
97
|
-
- app/components/flowbite/input_field.rb
|
|
98
|
-
- app/components/flowbite/input_field/checkbox.html.erb
|
|
99
|
-
- app/components/flowbite/input_field/checkbox.rb
|
|
100
|
-
- app/components/flowbite/input_field/date.rb
|
|
101
|
-
- app/components/flowbite/input_field/date_time.rb
|
|
102
|
-
- app/components/flowbite/input_field/email.rb
|
|
103
|
-
- app/components/flowbite/input_field/file.rb
|
|
104
|
-
- app/components/flowbite/input_field/input_field.html.erb
|
|
105
|
-
- app/components/flowbite/input_field/number.rb
|
|
106
|
-
- app/components/flowbite/input_field/password.rb
|
|
107
|
-
- app/components/flowbite/input_field/phone.rb
|
|
108
|
-
- app/components/flowbite/input_field/radio_button.html.erb
|
|
109
|
-
- app/components/flowbite/input_field/radio_button.rb
|
|
110
|
-
- app/components/flowbite/input_field/select.rb
|
|
111
|
-
- app/components/flowbite/input_field/text.rb
|
|
112
|
-
- app/components/flowbite/input_field/textarea.rb
|
|
113
|
-
- app/components/flowbite/input_field/url.rb
|
|
114
|
-
- app/components/flowbite/link.rb
|
|
115
|
-
- app/components/flowbite/style.rb
|
|
116
|
-
- app/components/flowbite/toast.rb
|
|
117
|
-
- app/components/flowbite/toast/icon.html.erb
|
|
118
|
-
- app/components/flowbite/toast/icon.rb
|
|
119
|
-
- app/components/flowbite/toast/toast.html.erb
|
|
120
71
|
- app/components/uchi/field/base.rb
|
|
121
72
|
- app/components/uchi/field/belongs_to.rb
|
|
122
73
|
- app/components/uchi/field/belongs_to/edit.html.erb
|
|
@@ -169,6 +120,59 @@ files:
|
|
|
169
120
|
- app/components/uchi/field/text/edit.html.erb
|
|
170
121
|
- app/components/uchi/field/text/index.html.erb
|
|
171
122
|
- app/components/uchi/field/text/show.html.erb
|
|
123
|
+
- app/components/uchi/flowbite/breadcrumb.rb
|
|
124
|
+
- app/components/uchi/flowbite/breadcrumb_home.rb
|
|
125
|
+
- app/components/uchi/flowbite/breadcrumb_item.rb
|
|
126
|
+
- app/components/uchi/flowbite/breadcrumb_item/current.rb
|
|
127
|
+
- app/components/uchi/flowbite/breadcrumb_item/first.rb
|
|
128
|
+
- app/components/uchi/flowbite/breadcrumb_separator.rb
|
|
129
|
+
- app/components/uchi/flowbite/button.rb
|
|
130
|
+
- app/components/uchi/flowbite/button/outline.rb
|
|
131
|
+
- app/components/uchi/flowbite/button/pill.rb
|
|
132
|
+
- app/components/uchi/flowbite/card.rb
|
|
133
|
+
- app/components/uchi/flowbite/card/card.html.erb
|
|
134
|
+
- app/components/uchi/flowbite/card/title.rb
|
|
135
|
+
- app/components/uchi/flowbite/input/checkbox.rb
|
|
136
|
+
- app/components/uchi/flowbite/input/date.rb
|
|
137
|
+
- app/components/uchi/flowbite/input/date_time.rb
|
|
138
|
+
- app/components/uchi/flowbite/input/email.rb
|
|
139
|
+
- app/components/uchi/flowbite/input/field.rb
|
|
140
|
+
- app/components/uchi/flowbite/input/file.rb
|
|
141
|
+
- app/components/uchi/flowbite/input/hint.rb
|
|
142
|
+
- app/components/uchi/flowbite/input/label.rb
|
|
143
|
+
- app/components/uchi/flowbite/input/number.rb
|
|
144
|
+
- app/components/uchi/flowbite/input/password.rb
|
|
145
|
+
- app/components/uchi/flowbite/input/phone.rb
|
|
146
|
+
- app/components/uchi/flowbite/input/radio_button.rb
|
|
147
|
+
- app/components/uchi/flowbite/input/select.rb
|
|
148
|
+
- app/components/uchi/flowbite/input/textarea.rb
|
|
149
|
+
- app/components/uchi/flowbite/input/url.rb
|
|
150
|
+
- app/components/uchi/flowbite/input/validation_error.rb
|
|
151
|
+
- app/components/uchi/flowbite/input_field.rb
|
|
152
|
+
- app/components/uchi/flowbite/input_field/checkbox.html.erb
|
|
153
|
+
- app/components/uchi/flowbite/input_field/checkbox.rb
|
|
154
|
+
- app/components/uchi/flowbite/input_field/date.rb
|
|
155
|
+
- app/components/uchi/flowbite/input_field/date_time.rb
|
|
156
|
+
- app/components/uchi/flowbite/input_field/email.rb
|
|
157
|
+
- app/components/uchi/flowbite/input_field/file.rb
|
|
158
|
+
- app/components/uchi/flowbite/input_field/input_field.html.erb
|
|
159
|
+
- app/components/uchi/flowbite/input_field/number.rb
|
|
160
|
+
- app/components/uchi/flowbite/input_field/password.rb
|
|
161
|
+
- app/components/uchi/flowbite/input_field/phone.rb
|
|
162
|
+
- app/components/uchi/flowbite/input_field/radio_button.html.erb
|
|
163
|
+
- app/components/uchi/flowbite/input_field/radio_button.rb
|
|
164
|
+
- app/components/uchi/flowbite/input_field/select.rb
|
|
165
|
+
- app/components/uchi/flowbite/input_field/text.rb
|
|
166
|
+
- app/components/uchi/flowbite/input_field/textarea.rb
|
|
167
|
+
- app/components/uchi/flowbite/input_field/url.rb
|
|
168
|
+
- app/components/uchi/flowbite/link.rb
|
|
169
|
+
- app/components/uchi/flowbite/style.rb
|
|
170
|
+
- app/components/uchi/flowbite/toast.rb
|
|
171
|
+
- app/components/uchi/flowbite/toast/icon.html.erb
|
|
172
|
+
- app/components/uchi/flowbite/toast/icon.rb
|
|
173
|
+
- app/components/uchi/flowbite/toast/toast.html.erb
|
|
174
|
+
- app/components/uchi/ui/actions/dropdown.rb
|
|
175
|
+
- app/components/uchi/ui/actions/dropdown/dropdown.html.erb
|
|
172
176
|
- app/components/uchi/ui/breadcrumb.rb
|
|
173
177
|
- app/components/uchi/ui/breadcrumb/breadcrumb.html.erb
|
|
174
178
|
- app/components/uchi/ui/form/footer.rb
|
|
@@ -182,6 +186,10 @@ files:
|
|
|
182
186
|
- app/components/uchi/ui/index/records_table/search_form.rb
|
|
183
187
|
- app/components/uchi/ui/index/records_table/search_form/search_form.html.erb
|
|
184
188
|
- app/components/uchi/ui/index/turbo_frame.rb
|
|
189
|
+
- app/components/uchi/ui/navigation.rb
|
|
190
|
+
- app/components/uchi/ui/navigation/navigation.html.erb
|
|
191
|
+
- app/components/uchi/ui/no_value.rb
|
|
192
|
+
- app/components/uchi/ui/no_value/no_value.html.erb
|
|
185
193
|
- app/components/uchi/ui/page_header.rb
|
|
186
194
|
- app/components/uchi/ui/page_header/page_header.html.erb
|
|
187
195
|
- app/components/uchi/ui/pagination.rb
|
|
@@ -201,6 +209,7 @@ files:
|
|
|
201
209
|
- app/components/uchi/ui/show/attribute_fields/attribute_fields.html.erb
|
|
202
210
|
- app/components/uchi/ui/spinner.rb
|
|
203
211
|
- app/components/uchi/ui/spinner/spinner.html.erb
|
|
212
|
+
- app/controllers/uchi/actions/executions_controller.rb
|
|
204
213
|
- app/controllers/uchi/application_controller.rb
|
|
205
214
|
- app/controllers/uchi/controller.rb
|
|
206
215
|
- app/controllers/uchi/repository_controller.rb
|
|
@@ -209,6 +218,7 @@ files:
|
|
|
209
218
|
- app/mailers/uchi/application_mailer.rb
|
|
210
219
|
- app/views/layouts/uchi/_flash_messages.html.erb
|
|
211
220
|
- app/views/layouts/uchi/application.html.erb
|
|
221
|
+
- app/views/uchi/navigation/_main.html.erb
|
|
212
222
|
- app/views/uchi/repository/edit.html.erb
|
|
213
223
|
- app/views/uchi/repository/index.html.erb
|
|
214
224
|
- app/views/uchi/repository/new.html.erb
|
|
@@ -218,8 +228,11 @@ files:
|
|
|
218
228
|
- lib/generators/uchi/install/install_generator.rb
|
|
219
229
|
- lib/generators/uchi/repository/repository_generator.rb
|
|
220
230
|
- lib/generators/uchi/repository/templates/repository.rb.tt
|
|
231
|
+
- lib/generators/uchi/scaffold/scaffold_generator.rb
|
|
221
232
|
- lib/tasks/uchi_tasks.rake
|
|
222
233
|
- lib/uchi.rb
|
|
234
|
+
- lib/uchi/action.rb
|
|
235
|
+
- lib/uchi/action_response.rb
|
|
223
236
|
- lib/uchi/application_record.rb
|
|
224
237
|
- lib/uchi/engine.rb
|
|
225
238
|
- lib/uchi/field.rb
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Flowbite
|
|
4
|
-
class Button
|
|
5
|
-
class Outline < Flowbite::Button
|
|
6
|
-
class << self
|
|
7
|
-
# rubocop:disable Layout/LineLength
|
|
8
|
-
def styles
|
|
9
|
-
{
|
|
10
|
-
default: Flowbite::Style.new(
|
|
11
|
-
default: ["text-blue-700", "hover:text-white", "border", "border-blue-700", "hover:bg-blue-800", "focus:ring-4", "focus:outline-none", "focus:ring-blue-300", "font-medium", "rounded-lg", "text-center", "me-2", "mb-2", "dark:border-blue-500", "dark:text-blue-500", "dark:hover:text-white", "dark:hover:bg-blue-500", "dark:focus:ring-blue-800"]
|
|
12
|
-
),
|
|
13
|
-
green: Flowbite::Style.new(
|
|
14
|
-
default: ["text-green-700", "hover:text-white", "border", "border-green-700", "hover:bg-green-800", "focus:ring-4", "focus:outline-none", "focus:ring-green-300", "font-medium", "rounded-lg", "text-center", "me-2", "mb-2", "dark:border-green-500", "dark:text-green-500", "dark:hover:text-white", "dark:hover:bg-green-600", "dark:focus:ring-green-800"]
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
end
|
|
18
|
-
# rubocop:enable Layout/LineLength
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Flowbite
|
|
4
|
-
class Button
|
|
5
|
-
class Pill < Flowbite::Button
|
|
6
|
-
class << self
|
|
7
|
-
# rubocop:disable Layout/LineLength, Metrics/MethodLength
|
|
8
|
-
def styles
|
|
9
|
-
{
|
|
10
|
-
alternative: Flowbite::Style.new(
|
|
11
|
-
default: ["text-sm", "font-medium", "text-gray-900", "focus:outline-none", "bg-white", "rounded-full", "border", "border-gray-200", "hover:bg-gray-100", "hover:text-blue-700", "focus:z-10", "focus:ring-4", "focus:ring-gray-100", "dark:focus:ring-gray-700", "dark:bg-gray-800", "dark:text-gray-400", "dark:border-gray-600", "dark:hover:text-white", "dark:hover:bg-gray-700"]
|
|
12
|
-
),
|
|
13
|
-
dark: Flowbite::Style.new(
|
|
14
|
-
default: ["text-white", "bg-gray-800", "hover:bg-gray-900", "focus:outline-none", "focus:ring-4", "focus:ring-gray-300", "font-medium", "rounded-full", "dark:bg-gray-800", "dark:hover:bg-gray-700", "dark:focus:ring-gray-700", "dark:border-gray-700"]
|
|
15
|
-
),
|
|
16
|
-
default: Flowbite::Style.new(
|
|
17
|
-
default: ["text-white", "bg-blue-700", "hover:bg-blue-800", "focus:outline-none", "focus:ring-4", "focus:ring-blue-300", "font-medium", "rounded-full", "text-center", "dark:bg-blue-600", "dark:hover:bg-blue-700", "dark:focus:ring-blue-800"]
|
|
18
|
-
),
|
|
19
|
-
green: Flowbite::Style.new(
|
|
20
|
-
default: ["text-white", "bg-green-700", "hover:bg-green-800", "focus:outline-none", "focus:ring-4", "focus:ring-green-300", "font-medium", "rounded-full", "text-center", "dark:bg-green-600", "dark:hover:bg-green-700", "dark:focus:ring-green-800"]
|
|
21
|
-
),
|
|
22
|
-
light: Flowbite::Style.new(
|
|
23
|
-
default: ["text-gray-900", "bg-white", "border", "border-gray-300", "focus:outline-none", "hover:bg-gray-100", "focus:ring-4", "focus:ring-gray-100", "font-medium", "rounded-full", "dark:bg-gray-800", "dark:text-white", "dark:border-gray-600", "dark:hover:bg-gray-700", "dark:hover:border-gray-600", "dark:focus:ring-gray-700"]
|
|
24
|
-
),
|
|
25
|
-
purple: Flowbite::Style.new(
|
|
26
|
-
default: ["text-white", "bg-purple-700", "hover:bg-purple-800", "focus:outline-none", "focus:ring-4", "focus:ring-purple-300", "font-medium", "rounded-full", "text-center", "dark:bg-purple-600", "dark:hover:bg-purple-700", "dark:focus:ring-purple-900"]
|
|
27
|
-
),
|
|
28
|
-
red: Flowbite::Style.new(
|
|
29
|
-
default: ["text-white", "bg-red-700", "hover:bg-red-800", "focus:outline-none", "focus:ring-4", "focus:ring-red-300", "font-medium", "rounded-full", "text-center", "dark:bg-red-600", "dark:hover:bg-red-700", "dark:focus:ring-red-900"]
|
|
30
|
-
),
|
|
31
|
-
yellow: Flowbite::Style.new(
|
|
32
|
-
default: ["text-white", "bg-yellow-400", "hover:bg-yellow-500", "focus:outline-none", "focus:ring-4", "focus:ring-yellow-300", "font-medium", "rounded-full", "text-center", "dark:focus:ring-yellow-900"]
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
end
|
|
36
|
-
# rubocop:enable Layout/LineLength, Metrics/MethodLength
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|