uchi 0.1.3 → 0.1.5
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 +222 -0
- data/app/assets/config/uchi_manifest.js +2 -0
- data/app/assets/javascripts/uchi/application.js +6095 -0
- data/app/assets/javascripts/uchi.js +4 -0
- data/app/assets/stylesheets/uchi/application.css +3971 -0
- data/app/assets/stylesheets/uchi/uchi.css +17 -0
- data/app/assets/tailwind/uchi.css +21 -0
- data/app/components/flowbite/breadcrumb.rb +33 -0
- data/app/components/flowbite/breadcrumb_home.rb +26 -0
- data/app/components/flowbite/breadcrumb_item/current.rb +33 -0
- data/app/components/flowbite/breadcrumb_item/first.rb +35 -0
- data/app/components/flowbite/breadcrumb_item.rb +48 -0
- data/app/components/flowbite/breadcrumb_separator.rb +30 -0
- data/app/components/flowbite/button/outline.rb +22 -0
- data/app/components/flowbite/button/pill.rb +40 -0
- data/app/components/flowbite/button.rb +92 -0
- data/app/components/flowbite/card.rb +45 -0
- data/app/components/flowbite/input/checkbox.rb +73 -0
- data/app/components/flowbite/input/date.rb +11 -0
- data/app/components/flowbite/input/date_time.rb +11 -0
- data/app/components/flowbite/input/email.rb +12 -0
- data/app/components/flowbite/input/field.rb +117 -0
- data/app/components/flowbite/input/file.rb +30 -0
- data/app/components/flowbite/input/hint.rb +57 -0
- data/app/components/flowbite/input/label.rb +82 -0
- data/app/components/flowbite/input/number.rb +11 -0
- data/app/components/flowbite/input/password.rb +11 -0
- data/app/components/flowbite/input/phone.rb +11 -0
- data/app/components/flowbite/input/radio_button.rb +50 -0
- data/app/components/flowbite/input/select.rb +49 -0
- data/app/components/flowbite/input/textarea.rb +42 -0
- data/app/components/flowbite/input/url.rb +12 -0
- data/app/components/flowbite/input/validation_error.rb +11 -0
- data/app/components/flowbite/input_field/checkbox.html.erb +14 -0
- data/app/components/flowbite/input_field/checkbox.rb +54 -0
- data/app/components/flowbite/input_field/date.rb +13 -0
- data/app/components/flowbite/input_field/date_time.rb +13 -0
- data/app/components/flowbite/input_field/email.rb +13 -0
- data/app/components/flowbite/input_field/file.rb +13 -0
- data/app/components/flowbite/input_field/input_field.html.erb +8 -0
- data/app/components/flowbite/input_field/number.rb +13 -0
- data/app/components/flowbite/input_field/password.rb +13 -0
- data/app/components/flowbite/input_field/phone.rb +13 -0
- data/app/components/flowbite/input_field/radio_button.html.erb +14 -0
- data/app/components/flowbite/input_field/radio_button.rb +86 -0
- data/app/components/flowbite/input_field/select.rb +31 -0
- data/app/components/flowbite/input_field/text.rb +8 -0
- data/app/components/flowbite/input_field/textarea.rb +13 -0
- data/app/components/flowbite/input_field/url.rb +13 -0
- data/app/components/flowbite/input_field.rb +192 -0
- data/app/components/flowbite/link.rb +21 -0
- data/app/components/flowbite/style.rb +13 -0
- data/app/components/flowbite/toast/icon.html.erb +5 -0
- data/app/components/flowbite/toast/icon.rb +57 -0
- data/app/components/flowbite/toast/toast.html.erb +11 -0
- data/app/components/flowbite/toast.rb +34 -0
- data/app/components/uchi/field/base.rb +57 -0
- data/app/components/uchi/field/belongs_to/edit.html.erb +1 -0
- data/app/components/uchi/field/belongs_to/index.html.erb +1 -0
- data/app/components/uchi/field/belongs_to/show.html.erb +5 -0
- data/app/components/uchi/field/belongs_to.rb +112 -0
- data/app/components/uchi/field/blank/edit.html.erb +1 -0
- data/app/components/uchi/field/blank/index.html.erb +1 -0
- data/app/components/uchi/field/blank/show.html.erb +1 -0
- data/app/components/uchi/field/blank.rb +16 -0
- data/app/components/uchi/field/boolean/edit.html.erb +1 -0
- data/app/components/uchi/field/boolean/index.html.erb +9 -0
- data/app/components/uchi/field/boolean/show.html.erb +9 -0
- data/app/components/uchi/field/boolean.rb +27 -0
- data/app/components/uchi/field/date/edit.html.erb +1 -0
- data/app/components/uchi/field/date/index.html.erb +1 -0
- data/app/components/uchi/field/date/show.html.erb +1 -0
- data/app/components/uchi/field/date.rb +27 -0
- data/app/components/uchi/field/date_time/edit.html.erb +1 -0
- data/app/components/uchi/field/date_time/index.html.erb +1 -0
- data/app/components/uchi/field/date_time/show.html.erb +1 -0
- data/app/components/uchi/field/date_time.rb +27 -0
- data/app/components/uchi/field/file/edit.html.erb +1 -0
- data/app/components/uchi/field/file/index.html.erb +6 -0
- data/app/components/uchi/field/file/show.html.erb +8 -0
- data/app/components/uchi/field/file.rb +37 -0
- data/app/components/uchi/field/has_and_belongs_to_many/edit.html.erb +9 -0
- data/app/components/uchi/field/has_and_belongs_to_many/index.html.erb +1 -0
- data/app/components/uchi/field/has_and_belongs_to_many/show.html.erb +28 -0
- data/app/components/uchi/field/has_and_belongs_to_many.rb +131 -0
- data/app/components/uchi/field/has_many/edit.html.erb +1 -0
- data/app/components/uchi/field/has_many/index.html.erb +1 -0
- data/app/components/uchi/field/has_many/show.html.erb +28 -0
- data/app/components/uchi/field/has_many.rb +107 -0
- data/app/components/uchi/field/id/index.html.erb +4 -0
- data/app/components/uchi/field/id/show.html.erb +4 -0
- data/app/components/uchi/field/id.rb +26 -0
- data/app/components/uchi/field/image/edit.html.erb +1 -0
- data/app/components/uchi/field/image/index.html.erb +6 -0
- data/app/components/uchi/field/image/show.html.erb +6 -0
- data/app/components/uchi/field/image.rb +38 -0
- data/app/components/uchi/field/number/edit.html.erb +1 -0
- data/app/components/uchi/field/number/index.html.erb +1 -0
- data/app/components/uchi/field/number/show.html.erb +1 -0
- data/app/components/uchi/field/number.rb +32 -0
- data/app/components/uchi/field/string/edit.html.erb +1 -0
- data/app/components/uchi/field/string/index.html.erb +1 -0
- data/app/components/uchi/field/string/show.html.erb +1 -0
- data/app/components/uchi/field/string.rb +33 -0
- data/app/components/uchi/field/text/edit.html.erb +1 -0
- data/app/components/uchi/field/text/index.html.erb +1 -0
- data/app/components/uchi/field/text/show.html.erb +1 -0
- data/app/components/uchi/field/text.rb +38 -0
- data/app/components/uchi/ui/breadcrumb/breadcrumb.html.erb +13 -0
- data/app/components/uchi/ui/breadcrumb.rb +14 -0
- data/app/components/uchi/ui/form/footer/footer.html.erb +5 -0
- data/app/components/uchi/ui/form/footer.rb +15 -0
- data/app/components/uchi/ui/form/input/collection_checkboxes.html.erb +32 -0
- data/app/components/uchi/ui/form/input/collection_checkboxes.rb +125 -0
- data/app/components/uchi/ui/frame/frame.html.erb +3 -0
- data/app/components/uchi/ui/frame.rb +10 -0
- data/app/components/uchi/ui/index/records_table/records_table.html.erb +67 -0
- data/app/components/uchi/ui/index/records_table/search_form/search_form.html.erb +21 -0
- data/app/components/uchi/ui/index/records_table/search_form.rb +49 -0
- data/app/components/uchi/ui/index/records_table.rb +29 -0
- data/app/components/uchi/ui/index/turbo_frame.rb +50 -0
- data/app/components/uchi/ui/page_header/page_header.html.erb +24 -0
- data/app/components/uchi/ui/page_header.rb +18 -0
- data/app/components/uchi/ui/pagination/current_link.html.erb +3 -0
- data/app/components/uchi/ui/pagination/current_link.rb +10 -0
- data/app/components/uchi/ui/pagination/gap.html.erb +3 -0
- data/app/components/uchi/ui/pagination/gap.rb +10 -0
- data/app/components/uchi/ui/pagination/item.rb +24 -0
- data/app/components/uchi/ui/pagination/link.html.erb +3 -0
- data/app/components/uchi/ui/pagination/link.rb +10 -0
- data/app/components/uchi/ui/pagination/next_link.html.erb +8 -0
- data/app/components/uchi/ui/pagination/next_link.rb +22 -0
- data/app/components/uchi/ui/pagination/pagination.html.erb +15 -0
- data/app/components/uchi/ui/pagination/previous_link.html.erb +8 -0
- data/app/components/uchi/ui/pagination/previous_link.rb +22 -0
- data/app/components/uchi/ui/pagination.rb +48 -0
- data/app/components/uchi/ui/show/attribute_fields/attribute_fields.html.erb +14 -0
- data/app/components/uchi/ui/show/attribute_fields.rb +18 -0
- data/app/components/uchi/ui/spinner/spinner.html.erb +7 -0
- data/app/components/uchi/ui/spinner.rb +15 -0
- data/app/controllers/uchi/application_controller.rb +4 -0
- data/app/controllers/uchi/controller.rb +13 -0
- data/app/controllers/uchi/repository_controller.rb +166 -0
- data/app/helpers/uchi/application_helper.rb +17 -0
- data/app/jobs/uchi/application_job.rb +4 -0
- data/app/mailers/uchi/application_mailer.rb +6 -0
- data/app/views/layouts/uchi/_flash_messages.html.erb +10 -0
- data/app/views/layouts/uchi/application.html.erb +33 -0
- data/app/views/uchi/repository/edit.html.erb +40 -0
- data/app/views/uchi/repository/index.html.erb +49 -0
- data/app/views/uchi/repository/new.html.erb +37 -0
- data/app/views/uchi/repository/show.html.erb +41 -0
- data/lib/generators/uchi/controller/controller_generator.rb +16 -0
- data/lib/generators/uchi/controller/templates/controller.rb.tt +11 -0
- data/lib/generators/uchi/install/install_generator.rb +13 -0
- data/lib/generators/uchi/repository/repository_generator.rb +16 -0
- data/lib/generators/uchi/repository/templates/repository.rb.tt +11 -0
- data/lib/tasks/uchi_tasks.rake +4 -0
- data/lib/uchi/application_record.rb +5 -0
- data/lib/uchi/engine.rb +24 -0
- data/lib/uchi/field/configuration.rb +142 -0
- data/lib/uchi/field.rb +80 -0
- data/lib/uchi/i18n.rb +13 -0
- data/lib/uchi/pagination/controller.rb +26 -0
- data/lib/uchi/pagination/page.rb +20 -0
- data/lib/uchi/pagy/LICENSE.txt +21 -0
- data/lib/uchi/pagy/classes/exceptions.rb +35 -0
- data/lib/uchi/pagy/classes/offset/offset.rb +56 -0
- data/lib/uchi/pagy/classes/request.rb +38 -0
- data/lib/uchi/pagy/modules/abilities/configurable.rb +38 -0
- data/lib/uchi/pagy/modules/abilities/linkable.rb +62 -0
- data/lib/uchi/pagy/modules/abilities/rangeable.rb +17 -0
- data/lib/uchi/pagy/modules/abilities/shiftable.rb +14 -0
- data/lib/uchi/pagy/modules/console.rb +40 -0
- data/lib/uchi/pagy/toolbox/helpers/loader.rb +19 -0
- data/lib/uchi/pagy/toolbox/helpers/page_url.rb +25 -0
- data/lib/uchi/pagy/toolbox/paginators/method.rb +21 -0
- data/lib/uchi/pagy/toolbox/paginators/offset.rb +35 -0
- data/lib/uchi/pagy.rb +60 -0
- data/lib/uchi/repository/routes.rb +62 -0
- data/lib/uchi/repository/translate.rb +368 -0
- data/lib/uchi/repository.rb +156 -0
- data/lib/uchi/sort_order.rb +35 -0
- data/lib/uchi/version.rb +5 -0
- data/lib/uchi.rb +18 -0
- data/uchi.gemspec +35 -0
- metadata +189 -97
- data/.github/dependabot.yml +0 -17
- data/.github/workflows/build.yml +0 -23
- data/.github/workflows/lint.yml +0 -30
- data/CHANGELOG.md +0 -29
- data/docs/fields.md +0 -82
- data/docs/repositories.md +0 -63
- data/package.json +0 -31
- data/sig/uchi.rbs +0 -4
- data/test/components/uchi/field/belongs_to_test.rb +0 -134
- data/test/components/uchi/field/blank_test.rb +0 -119
- data/test/components/uchi/field/boolean_test.rb +0 -163
- data/test/components/uchi/field/date_test.rb +0 -163
- data/test/components/uchi/field/date_time_test.rb +0 -152
- data/test/components/uchi/field/has_and_belongs_to_many_test.rb +0 -144
- data/test/components/uchi/field/has_many_test.rb +0 -138
- data/test/components/uchi/field/id_test.rb +0 -113
- data/test/components/uchi/field/number_test.rb +0 -163
- data/test/components/uchi/field/string_test.rb +0 -159
- data/test/components/uchi/field/text_test.rb +0 -160
- data/test/components/uchi/ui/form/input/collection_checkboxes_test.rb +0 -171
- data/test/controllers/uchi/authors_controller_test.rb +0 -120
- data/test/controllers/uchi/repository_controller_test.rb +0 -93
- data/test/controllers/uchi/scoped_repository_controller_test.rb +0 -73
- data/test/dummy/Rakefile +0 -6
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +0 -15
- data/test/dummy/app/controllers/application_controller.rb +0 -4
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/uchi/authors_controller.rb +0 -7
- data/test/dummy/app/controllers/uchi/books_controller.rb +0 -7
- data/test/dummy/app/controllers/uchi/titles_controller.rb +0 -7
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/jobs/application_job.rb +0 -7
- data/test/dummy/app/mailers/application_mailer.rb +0 -4
- data/test/dummy/app/models/application_record.rb +0 -3
- data/test/dummy/app/models/author.rb +0 -5
- data/test/dummy/app/models/book.rb +0 -4
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/title.rb +0 -3
- data/test/dummy/app/uchi/repositories/author.rb +0 -20
- data/test/dummy/app/uchi/repositories/book.rb +0 -16
- data/test/dummy/app/uchi/repositories/title.rb +0 -17
- data/test/dummy/app/views/layouts/application.html.erb +0 -27
- data/test/dummy/app/views/layouts/mailer.html.erb +0 -13
- data/test/dummy/app/views/layouts/mailer.text.erb +0 -1
- data/test/dummy/app/views/pwa/manifest.json.erb +0 -22
- data/test/dummy/app/views/pwa/service-worker.js +0 -26
- data/test/dummy/bin/dev +0 -2
- data/test/dummy/bin/rails +0 -4
- data/test/dummy/bin/rake +0 -4
- data/test/dummy/bin/setup +0 -34
- data/test/dummy/config/application.rb +0 -29
- data/test/dummy/config/boot.rb +0 -5
- data/test/dummy/config/cable.yml +0 -10
- data/test/dummy/config/database.yml +0 -32
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -69
- data/test/dummy/config/environments/production.rb +0 -89
- data/test/dummy/config/environments/test.rb +0 -53
- data/test/dummy/config/initializers/content_security_policy.rb +0 -25
- data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -8
- data/test/dummy/config/initializers/inflections.rb +0 -16
- data/test/dummy/config/locales/da.yml +0 -52
- data/test/dummy/config/locales/en.yml +0 -31
- data/test/dummy/config/puma.rb +0 -38
- data/test/dummy/config/routes.rb +0 -9
- data/test/dummy/config/storage.yml +0 -34
- data/test/dummy/config.ru +0 -6
- data/test/dummy/db/migrate/20251002183635_create_authors.rb +0 -11
- data/test/dummy/db/migrate/20251005131726_create_books.rb +0 -9
- data/test/dummy/db/migrate/20251005131811_create_titles.rb +0 -11
- data/test/dummy/db/migrate/20251031140958_add_author_books_join_table.rb +0 -9
- data/test/dummy/db/schema.rb +0 -44
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/400.html +0 -114
- data/test/dummy/public/404.html +0 -114
- data/test/dummy/public/406-unsupported-browser.html +0 -114
- data/test/dummy/public/422.html +0 -114
- data/test/dummy/public/500.html +0 -114
- data/test/dummy/public/icon.png +0 -0
- data/test/dummy/public/icon.svg +0 -3
- data/test/dummy/storage/.keep +0 -0
- data/test/dummy/test/fixtures/authors.yml +0 -11
- data/test/dummy/test/models/author_test.rb +0 -7
- data/test/dummy/tmp/.keep +0 -0
- data/test/dummy/tmp/pids/.keep +0 -0
- data/test/dummy/tmp/storage/.keep +0 -0
- data/test/test_helper.rb +0 -15
- data/test/uchi/field_test.rb +0 -77
- data/test/uchi/i18n_test.rb +0 -18
- data/test/uchi/repository/routes_test.rb +0 -49
- data/test/uchi/repository/translate_test.rb +0 -272
- data/test/uchi/repository_test.rb +0 -137
- data/test/uchi/sort_order_test.rb +0 -47
- data/test/uchi_test.rb +0 -7
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
module Uchi
|
|
6
|
+
class Pagy
|
|
7
|
+
# Provide the helpers to handle the url and anchor
|
|
8
|
+
module Linkable
|
|
9
|
+
module QueryUtils
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# Extracted from Rack::Utils and reformatted for rubocop
|
|
13
|
+
# Add the 'unescaped' param, and use it for simple and safe url-templating.
|
|
14
|
+
# All string keyed hashes
|
|
15
|
+
def build_nested_query(value, prefix = nil, unescaped = [])
|
|
16
|
+
case value
|
|
17
|
+
when Array
|
|
18
|
+
value.map { |v| build_nested_query(v, "#{prefix}[]", unescaped) }.join('&')
|
|
19
|
+
when Hash
|
|
20
|
+
value.map do |k, v|
|
|
21
|
+
new_k = prefix ? "#{prefix}[#{escape(k)}]" : escape(k)
|
|
22
|
+
unescaped[unescaped.find_index(k)] = new_k if unescaped.size.positive? && new_k != k && unescaped.include?(k)
|
|
23
|
+
build_nested_query(v, new_k, unescaped)
|
|
24
|
+
end.delete_if(&:empty?).join('&')
|
|
25
|
+
when nil
|
|
26
|
+
escape(prefix)
|
|
27
|
+
else
|
|
28
|
+
raise ArgumentError, 'value must be a Hash' if prefix.nil?
|
|
29
|
+
return "#{escape(prefix)}=#{value}" if unescaped.include?(prefix)
|
|
30
|
+
|
|
31
|
+
"#{escape(prefix)}=#{escape(value)}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def escape(str)
|
|
36
|
+
URI.encode_www_form_component(str)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
protected
|
|
41
|
+
|
|
42
|
+
# Return the URL for the page, relying on the Pagy::Request
|
|
43
|
+
def compose_page_url(page, limit_token: nil, **options)
|
|
44
|
+
jsonapi, page_key, limit_key, limit, client_max_limit, querify, absolute, path, fragment =
|
|
45
|
+
@options.merge(options)
|
|
46
|
+
.values_at(:jsonapi, :page_key, :limit_key, :limit, :client_max_limit, :querify, :absolute, :path, :fragment)
|
|
47
|
+
query = @request.query.clone(freeze: false)
|
|
48
|
+
query.delete(jsonapi ? 'page' : page_key)
|
|
49
|
+
factors = {}.tap do |h|
|
|
50
|
+
h[page_key] = countless? ? "#{page || 1}+#{@last}" : page
|
|
51
|
+
h[limit_key] = limit_token || limit if client_max_limit
|
|
52
|
+
end.compact # No empty params
|
|
53
|
+
query.merge!(jsonapi ? { 'page' => factors } : factors) if factors.size.positive?
|
|
54
|
+
querify&.(query) # Must modify the query: the returned value is ignored
|
|
55
|
+
query_string = QueryUtils.build_nested_query(query, nil, [page_key, limit_key])
|
|
56
|
+
query_string = "?#{query_string}" unless query_string.empty?
|
|
57
|
+
fragment &&= %(##{fragment}) unless fragment&.start_with?('#')
|
|
58
|
+
"#{@request.base_url if absolute}#{path || @request.path}#{query_string}#{fragment}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
class Pagy
|
|
5
|
+
# Add method supporting range checking, range error and rescue
|
|
6
|
+
module Rangeable
|
|
7
|
+
# Check if in range
|
|
8
|
+
def in_range?
|
|
9
|
+
return @in_range if defined?(@in_range) || (@in_range = yield)
|
|
10
|
+
raise RangeError.new(self, :page, "in 1..#{@last}", @page) if @options[:raise_range_error]
|
|
11
|
+
|
|
12
|
+
assign_empty_page_variables
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
class Pagy
|
|
5
|
+
# Provide a ready to use pagy environment when included in irb/rails console
|
|
6
|
+
module Console
|
|
7
|
+
class Request
|
|
8
|
+
attr_accessor :base_url, :path, :params
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@base_url = 'http://www.example.com'
|
|
12
|
+
@path = '/path'
|
|
13
|
+
@params = { example: '123' }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def GET = @params # rubocop:disable Naming/MethodName
|
|
17
|
+
|
|
18
|
+
def cookies = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Collection < Array
|
|
22
|
+
def initialize(arr = Array(1..1000))
|
|
23
|
+
super
|
|
24
|
+
@collection = clone
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def offset(value) = tap { @collection = self[value..] }
|
|
28
|
+
def limit(value) = @collection[0, value]
|
|
29
|
+
def count(*) = size
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
include Method
|
|
33
|
+
|
|
34
|
+
# Direct reference to request.params via a method
|
|
35
|
+
def params = request.params
|
|
36
|
+
def request = @request ||= Request.new
|
|
37
|
+
def collection = Collection
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
class Pagy
|
|
5
|
+
module Loader
|
|
6
|
+
paths = { public: { page_url: 'page_url' } }.freeze
|
|
7
|
+
|
|
8
|
+
paths.each do |visibility, methods|
|
|
9
|
+
send(visibility)
|
|
10
|
+
# Load the method, overriding its own alias. Next requests will call the method directly.
|
|
11
|
+
define_method(:"load_#{visibility}") do |*args, **kwargs|
|
|
12
|
+
require_relative methods[__callee__]
|
|
13
|
+
send(__callee__, *args, **kwargs)
|
|
14
|
+
end
|
|
15
|
+
methods.each_key { |method| alias_method method, :"load_#{visibility}" }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
class Pagy
|
|
5
|
+
# Return the page url for any page
|
|
6
|
+
# :nocov:
|
|
7
|
+
def page_url(page, **)
|
|
8
|
+
case page
|
|
9
|
+
when :first
|
|
10
|
+
compose_page_url(nil, **)
|
|
11
|
+
when :current
|
|
12
|
+
compose_page_url(@page, **) if @page
|
|
13
|
+
when :previous
|
|
14
|
+
compose_page_url(@previous, **) if @previous
|
|
15
|
+
when :next
|
|
16
|
+
compose_page_url(@next, **) if @next
|
|
17
|
+
when :last
|
|
18
|
+
compose_page_url(@last, **) if @last
|
|
19
|
+
when Integer, String
|
|
20
|
+
compose_page_url(page, **)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
# :nocov:
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../classes/request'
|
|
4
|
+
|
|
5
|
+
module Uchi
|
|
6
|
+
class Pagy
|
|
7
|
+
paginators = { offset: :OffsetPaginator }.freeze
|
|
8
|
+
|
|
9
|
+
path = Pathname.new(__dir__)
|
|
10
|
+
paginators.each { |symbol, name| autoload name, path.join(symbol.to_s) }
|
|
11
|
+
|
|
12
|
+
# Defines the pagy method. Include in the app controller/view.
|
|
13
|
+
Method = Module.new do
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
define_method :pagy do |paginator = :offset, collection, **options|
|
|
17
|
+
Pagy.const_get(paginators[paginator]).paginate(self, collection, **Pagy.options, **options)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
class Pagy
|
|
5
|
+
module OffsetPaginator
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
# Return instance and page of results
|
|
9
|
+
def paginate(context, collection, **options)
|
|
10
|
+
context.instance_eval do
|
|
11
|
+
request = Request.new(options[:request] || self.request, options)
|
|
12
|
+
options[:page] ||= request.resolve_page(options)
|
|
13
|
+
options[:limit] = request.resolve_limit(options)
|
|
14
|
+
options[:count] ||= collection.instance_of?(Array) ? collection.size : OffsetPaginator.get_count(collection, options)
|
|
15
|
+
pagy = Offset.new(**options, request:)
|
|
16
|
+
[pagy, collection.instance_of?(Array) ? collection[pagy.offset, pagy.limit] : pagy.records(collection)]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Get the collection count
|
|
21
|
+
def get_count(collection, options)
|
|
22
|
+
return collection.count unless defined?(::ActiveRecord) && collection.is_a?(::ActiveRecord::Relation)
|
|
23
|
+
|
|
24
|
+
count = if options[:count_over] && !collection.group_values.empty?
|
|
25
|
+
# COUNT(*) OVER ()
|
|
26
|
+
sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
|
|
27
|
+
collection.unscope(:order).pick(sql).to_i
|
|
28
|
+
else
|
|
29
|
+
collection.count(:all)
|
|
30
|
+
end
|
|
31
|
+
count.is_a?(Hash) ? count.size : count
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/uchi/pagy.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require_relative 'pagy/classes/exceptions'
|
|
5
|
+
require_relative 'pagy/modules/abilities/linkable'
|
|
6
|
+
require_relative 'pagy/modules/abilities/configurable'
|
|
7
|
+
require_relative 'pagy/toolbox/helpers/loader'
|
|
8
|
+
|
|
9
|
+
module Uchi
|
|
10
|
+
# Top superclass: it defines only what's common to all the subclasses
|
|
11
|
+
class Pagy
|
|
12
|
+
VERSION = '43.0.0.rc4'
|
|
13
|
+
ROOT = Pathname.new(__dir__).parent.freeze
|
|
14
|
+
DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
|
|
15
|
+
PAGE_TOKEN = 'P '
|
|
16
|
+
LIMIT_TOKEN = 'L '
|
|
17
|
+
LABEL_TOKEN = 'L'
|
|
18
|
+
A_TAG = '<a style="display: none;">#</a>'
|
|
19
|
+
|
|
20
|
+
path = Pathname.new(__FILE__).sub_ext('')
|
|
21
|
+
autoload :Method, path.join('toolbox/paginators/method')
|
|
22
|
+
autoload :I18n, path.join('modules/i18n/i18n')
|
|
23
|
+
autoload :Console, path.join('modules/console')
|
|
24
|
+
autoload :Offset, path.join('classes/offset/offset')
|
|
25
|
+
|
|
26
|
+
def self.options = @options ||= {}
|
|
27
|
+
|
|
28
|
+
extend Configurable
|
|
29
|
+
include Linkable
|
|
30
|
+
include Loader
|
|
31
|
+
|
|
32
|
+
attr_reader :page, :next, :in, :limit, :options
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
# Define the hierarchical identity methods, overridden by the respective classes
|
|
37
|
+
def offset? = false
|
|
38
|
+
def countless? = false
|
|
39
|
+
|
|
40
|
+
# Validates and assign the passed options: var must be present and value.to_i must be >= to min
|
|
41
|
+
def assign_and_check(name_min)
|
|
42
|
+
name_min.each do |name, min|
|
|
43
|
+
raise OptionError.new(self, name, ">= #{min}", @options[name]) \
|
|
44
|
+
unless @options[name].respond_to?(:to_i) && instance_variable_set(:"@#{name}", @options[name].to_i) >= min
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Merge all the DEFAULT constants of the class hierarchy with the options
|
|
49
|
+
def assign_options(**options)
|
|
50
|
+
@request = options.delete(:request) # internal object
|
|
51
|
+
default = {}
|
|
52
|
+
current = self.class
|
|
53
|
+
begin
|
|
54
|
+
default = current::DEFAULT.merge(default)
|
|
55
|
+
current = current.superclass
|
|
56
|
+
end until current == Object # rubocop:disable Lint/Loop -- see https://github.com/rubocop/rubocop-performance/issues/362
|
|
57
|
+
@options = default.merge!(options.delete_if { |k, v| default.key?(k) && (v.nil? || v == '') }).freeze
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
class Repository
|
|
5
|
+
class Routes
|
|
6
|
+
attr_reader :plural, :repository, :singular
|
|
7
|
+
|
|
8
|
+
def initialize(repository)
|
|
9
|
+
@repository = repository
|
|
10
|
+
@singular = repository.controller_name.singularize
|
|
11
|
+
@plural = repository.controller_name.pluralize
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def path_for(action, **options)
|
|
15
|
+
action = action.to_sym
|
|
16
|
+
case action
|
|
17
|
+
when :destroy, :edit, :new, :show, :update
|
|
18
|
+
singular_path_for(action, **options)
|
|
19
|
+
else
|
|
20
|
+
plural_path_for(action, **options)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def root_path
|
|
25
|
+
"/#{uchi_namespace}/"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def call_url_helper_in_main_app(parts, **options)
|
|
31
|
+
url_helper_name = parts.join("_")
|
|
32
|
+
Rails.application.routes.url_helpers.send(url_helper_name, **options)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def plural_path_for(_action, **options)
|
|
36
|
+
parts = [
|
|
37
|
+
uchi_namespace,
|
|
38
|
+
plural,
|
|
39
|
+
"path"
|
|
40
|
+
].compact
|
|
41
|
+
call_url_helper_in_main_app(parts, **options)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def singular_path_for(action, **options)
|
|
45
|
+
action = nil if action == :show
|
|
46
|
+
action = nil if action == :update
|
|
47
|
+
action = nil if action == :destroy
|
|
48
|
+
parts = [
|
|
49
|
+
action,
|
|
50
|
+
uchi_namespace,
|
|
51
|
+
singular,
|
|
52
|
+
"path"
|
|
53
|
+
].compact
|
|
54
|
+
call_url_helper_in_main_app(parts, **options)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def uchi_namespace
|
|
58
|
+
:uchi
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|