uchi 0.1.0 → 0.1.3
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/.github/dependabot.yml +17 -0
- data/.github/workflows/build.yml +23 -0
- data/.github/workflows/lint.yml +30 -0
- data/CHANGELOG.md +29 -0
- data/docs/fields.md +82 -0
- data/docs/repositories.md +63 -0
- data/package.json +31 -0
- data/test/components/uchi/field/belongs_to_test.rb +134 -0
- data/test/components/uchi/field/blank_test.rb +119 -0
- data/test/components/uchi/field/boolean_test.rb +163 -0
- data/test/components/uchi/field/date_test.rb +163 -0
- data/test/components/uchi/field/date_time_test.rb +152 -0
- data/test/components/uchi/field/has_and_belongs_to_many_test.rb +144 -0
- data/test/components/uchi/field/has_many_test.rb +138 -0
- data/test/components/uchi/field/id_test.rb +113 -0
- data/test/components/uchi/field/number_test.rb +163 -0
- data/test/components/uchi/field/string_test.rb +159 -0
- data/test/components/uchi/field/text_test.rb +160 -0
- data/test/components/uchi/ui/form/input/collection_checkboxes_test.rb +171 -0
- data/test/controllers/uchi/authors_controller_test.rb +120 -0
- data/test/controllers/uchi/repository_controller_test.rb +93 -0
- data/test/controllers/uchi/scoped_repository_controller_test.rb +73 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +4 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/uchi/authors_controller.rb +7 -0
- data/test/dummy/app/controllers/uchi/books_controller.rb +7 -0
- data/test/dummy/app/controllers/uchi/titles_controller.rb +7 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +7 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/author.rb +5 -0
- data/test/dummy/app/models/book.rb +4 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/title.rb +3 -0
- data/test/dummy/app/uchi/repositories/author.rb +20 -0
- data/test/dummy/app/uchi/repositories/book.rb +16 -0
- data/test/dummy/app/uchi/repositories/title.rb +17 -0
- data/test/dummy/app/views/layouts/application.html.erb +27 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/app/views/pwa/manifest.json.erb +22 -0
- data/test/dummy/app/views/pwa/service-worker.js +26 -0
- data/test/dummy/bin/dev +2 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +34 -0
- data/test/dummy/config/application.rb +29 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/database.yml +32 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +69 -0
- data/test/dummy/config/environments/production.rb +89 -0
- data/test/dummy/config/environments/test.rb +53 -0
- data/test/dummy/config/initializers/content_security_policy.rb +25 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/locales/da.yml +52 -0
- data/test/dummy/config/locales/en.yml +31 -0
- data/test/dummy/config/puma.rb +38 -0
- data/test/dummy/config/routes.rb +9 -0
- data/test/dummy/config/storage.yml +34 -0
- data/test/dummy/config.ru +6 -0
- data/test/dummy/db/migrate/20251002183635_create_authors.rb +11 -0
- data/test/dummy/db/migrate/20251005131726_create_books.rb +9 -0
- data/test/dummy/db/migrate/20251005131811_create_titles.rb +11 -0
- data/test/dummy/db/migrate/20251031140958_add_author_books_join_table.rb +9 -0
- data/test/dummy/db/schema.rb +44 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/400.html +114 -0
- data/test/dummy/public/404.html +114 -0
- data/test/dummy/public/406-unsupported-browser.html +114 -0
- data/test/dummy/public/422.html +114 -0
- data/test/dummy/public/500.html +114 -0
- data/test/dummy/public/icon.png +0 -0
- data/test/dummy/public/icon.svg +3 -0
- data/test/dummy/storage/.keep +0 -0
- data/test/dummy/test/fixtures/authors.yml +11 -0
- data/test/dummy/test/models/author_test.rb +7 -0
- 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 +15 -0
- data/test/uchi/field_test.rb +77 -0
- data/test/uchi/i18n_test.rb +18 -0
- data/test/uchi/repository/routes_test.rb +49 -0
- data/test/uchi/repository/translate_test.rb +272 -0
- data/test/uchi/repository_test.rb +137 -0
- data/test/uchi/sort_order_test.rb +47 -0
- data/test/uchi_test.rb +7 -0
- metadata +147 -10
- data/README.md +0 -35
- data/Rakefile +0 -6
- data/lib/uchi/version.rb +0 -5
- data/lib/uchi.rb +0 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 92849fb71ff71c56d796e3e43601dd99eabc565180c902ac129feb25f8cc5fc0
|
|
4
|
+
data.tar.gz: 789df26e207ac6ed7e8857269bafc4bcd06d21c3ec22b6070c1092c222a42d08
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 146839a586037ec5e0b713aec63ca699b50346c9d0be98935db42a562fe1f78be1bc6d16d4afe9a4ec38431cb440efb4d63b79527b2873db87ce01225f256153
|
|
7
|
+
data.tar.gz: 002ea4b08886edfefbab4c7580db0524b1776824f2aea0d75077c90ed2331cc3297ed3616121cf6dd86bc9e54cc0556e5d4a00ccc8848a749d1af6b593bf9223
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "bundler"
|
|
9
|
+
directory: "/"
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
12
|
+
|
|
13
|
+
- package-ecosystem: "npm"
|
|
14
|
+
directory: "/"
|
|
15
|
+
schedule:
|
|
16
|
+
interval: "weekly"
|
|
17
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: "Build"
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [ "main" ]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [ "main" ]
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
env:
|
|
11
|
+
RAILS_ENV: test
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout code
|
|
14
|
+
uses: actions/checkout@v5
|
|
15
|
+
- name: Install Ruby and gems
|
|
16
|
+
uses: ruby/setup-ruby@v1
|
|
17
|
+
with:
|
|
18
|
+
bundler-cache: true
|
|
19
|
+
ruby-version: '3.4.5'
|
|
20
|
+
- name: Set up database schema
|
|
21
|
+
run: bundle exec rake app:db:schema:load
|
|
22
|
+
- name: Run tests
|
|
23
|
+
run: bundle exec rake app:test
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: "Lint"
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [ "main" ]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [ "main" ]
|
|
7
|
+
jobs:
|
|
8
|
+
erb:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- name: Checkout code
|
|
12
|
+
uses: actions/checkout@v5
|
|
13
|
+
- name: Install Node
|
|
14
|
+
uses: actions/setup-node@v5
|
|
15
|
+
- name: Install dependencies
|
|
16
|
+
run: npm install
|
|
17
|
+
- name: Herb
|
|
18
|
+
run: npm run herb:lint
|
|
19
|
+
ruby:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout code
|
|
23
|
+
uses: actions/checkout@v5
|
|
24
|
+
- name: Install Ruby and gems
|
|
25
|
+
uses: ruby/setup-ruby@v1
|
|
26
|
+
with:
|
|
27
|
+
bundler-cache: true
|
|
28
|
+
ruby-version: '3.4.5'
|
|
29
|
+
- name: Standard
|
|
30
|
+
run: bundle exec rake standard
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
### Removed
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [0.1.3]
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Field::Text for multi-line text content like descriptions, biographies, notes, and comments.
|
|
22
|
+
- Field for HasAndBelongsToMany associations.
|
|
23
|
+
- Better blank slate when a RecordsTable has no records; we also no longer show page navigation when there are no records.
|
|
24
|
+
- A changelog!
|
|
25
|
+
- Everything else up until now ;)
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- uchi:controller generator now generates proper controller names when name contains multiple words.
|
data/docs/fields.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Fields
|
|
2
|
+
|
|
3
|
+
## Only show a field on specific pages
|
|
4
|
+
|
|
5
|
+
Use the `on` method to control what pages to show a field on. For example if your id field should only be visible on the index listing, you can configure it as
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
Field::Number.new(:id).on(:index)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Possible actions are
|
|
12
|
+
|
|
13
|
+
- `:index`
|
|
14
|
+
- `:show`
|
|
15
|
+
- `:new`
|
|
16
|
+
- `:edit`
|
|
17
|
+
|
|
18
|
+
The default is to show all fields on all pages.
|
|
19
|
+
|
|
20
|
+
## Search
|
|
21
|
+
|
|
22
|
+
If a repository contains at least one searchable `Field` a search field appears on the index page. By default all text-based fields are considered searchable.
|
|
23
|
+
|
|
24
|
+
The search is fairly naive and is a bunch of `LIKE '%query%'` (`ILIKE` in PostgreSQL) clauses strung together by `OR`.
|
|
25
|
+
|
|
26
|
+
### Disable search
|
|
27
|
+
|
|
28
|
+
To toggle searchability for a field use the `:searchable` option:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
Field::String.new(:password).searchable(false)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Enable search
|
|
35
|
+
|
|
36
|
+
You can also enable search for fields that don't enable it by default:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
Field::Number.new(:id).searchable(true)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Uchi casts whatever datatype the field uses into a string when searching and perform a partial match on it using `LIKE` (`ILIKE` in PostgreSQL), which may or may not yield the results you expect.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## Sorting
|
|
46
|
+
|
|
47
|
+
All fields are considered sortable by default. This means that a link to toggle the order of a column appears for all columns on index pages. How to sort a specific field - or to disable it entirely - is configured using the `:sortable` option.
|
|
48
|
+
|
|
49
|
+
### Disable sorting
|
|
50
|
+
|
|
51
|
+
To disable sorting a specific field:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
Field::Number.new(:calculated_sum).sortable(false)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Customize sorting
|
|
58
|
+
|
|
59
|
+
To customize the query used to sort by a given field, pass a lambda to the `sortable` method:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
Field::Number.new(:users_count).sortable(lambda { |query, direction|
|
|
63
|
+
query.joins(:users).group(:id).order("COUNT(users.id) #{direction}")
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The lambda receives 2 arguments:
|
|
68
|
+
|
|
69
|
+
1. `query`: The `ActiveRecord::Relation` that makes up the current database query
|
|
70
|
+
2. `direction`: A symbol indicating what order to sort; either `:asc` or `:desc`.
|
|
71
|
+
|
|
72
|
+
The lambda should return an `ActiveRecord::Relation` with the desired sort order added.
|
|
73
|
+
|
|
74
|
+
### Sorting by columns in another table
|
|
75
|
+
|
|
76
|
+
Thanks to ActiveRecord we can even sort by columns in other tables/models. If you have an `Employee` model that belongs to a `Company` and you want to allow your users to sort the employee list by company name, you can configure the field like this:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
Field::BelongsTo.new(:company).sortable(lambda { |query, direction|
|
|
80
|
+
query.joins(:office).order(:offices => {:name => direction})
|
|
81
|
+
})
|
|
82
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Repositories
|
|
2
|
+
|
|
3
|
+
The cornerstones of Uchi are the repositories. This is where you configure what parts of your models you want to expose and how to do it.
|
|
4
|
+
|
|
5
|
+
## Models
|
|
6
|
+
|
|
7
|
+
There's a one-to-one mapping between a repository and a model. So if you have a `User` model that you want to include in Uchi, you must have a `User` repository as well.
|
|
8
|
+
|
|
9
|
+
## Routes
|
|
10
|
+
|
|
11
|
+
In order to expose your requests to your users, you need a route for each of them. These routes are added to `config/routes.rb` in your main application under the `uchi` namespace:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
namespace :uchi do
|
|
15
|
+
resources :companies
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
See [Rails' routing documentation](https://guides.rubyonrails.org/routing.html) for more details.
|
|
20
|
+
|
|
21
|
+
### Root URL
|
|
22
|
+
|
|
23
|
+
If you want to expose a repository at the root URL (ie `/uchi/`) you can configure a [`root`](https://guides.rubyonrails.org/routing.html#using-root) for the namespace:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
namespace :uchi do
|
|
27
|
+
root "companies#index"
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Default sort order
|
|
32
|
+
|
|
33
|
+
Lists of records in a repository are by default sorted by a column called `id`. To customize the default sort order, which is used when a user hasn’t explicitly chosen to sort by a specific field, you can create a `default_sort_order` method in the repository:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
module Uchi
|
|
37
|
+
class CustomersRepository < Uchi::Repository
|
|
38
|
+
def default_sort_order
|
|
39
|
+
SortOrder.new(:name, :desc)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`default_sort_order` should return a `Uchi::Repository::SortOrder`.
|
|
46
|
+
|
|
47
|
+
## Avoiding n+1
|
|
48
|
+
|
|
49
|
+
To avoid n+1 performance issues on your index pages and other lists, you can set up includes for the repository.
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
module Uchi
|
|
53
|
+
module Repositories
|
|
54
|
+
class User < Repository
|
|
55
|
+
def includes
|
|
56
|
+
[:account]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
See https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-includes for details.
|
data/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "uchi",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "## Installation",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"directories": {
|
|
7
|
+
"lib": "lib",
|
|
8
|
+
"test": "test"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"assets:build": "npm run build:css && npm run build:js",
|
|
12
|
+
"build:css": "node_modules/.bin/tailwindcss -i ./app/assets/tailwind/uchi.css -o ./app/assets/stylesheets/uchi/application.css",
|
|
13
|
+
"build:js": "node_modules/.bin/esbuild --bundle --outfile=app/assets/javascripts/uchi/application.js app/assets/javascripts/uchi.js",
|
|
14
|
+
"herb:lint": "herb-lint '**/*.html.erb'",
|
|
15
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
16
|
+
"watch:css": "node_modules/.bin/tailwindcss --watch -i ./app/assets/tailwind/uchi.css -o ./app/assets/stylesheets/uchi/application.css",
|
|
17
|
+
"watch:js": "node_modules/.bin/esbuild --watch --bundle --outfile=app/assets/javascripts/uchi/application.js app/assets/javascripts/uchi.js"
|
|
18
|
+
},
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@hotwired/turbo-rails": "^8.0.16",
|
|
23
|
+
"@tailwindcss/cli": "^4.1.13",
|
|
24
|
+
"flowbite": "^3.1.2",
|
|
25
|
+
"tailwindcss": "^4.1.13"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@herb-tools/linter": "^0.7.4",
|
|
29
|
+
"esbuild": "0.25.11"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "ostruct"
|
|
3
|
+
|
|
4
|
+
module Uchi
|
|
5
|
+
class Field
|
|
6
|
+
class BelongsToTest < ActiveSupport::TestCase
|
|
7
|
+
def setup
|
|
8
|
+
@field = Uchi::Field::BelongsTo.new(:book)
|
|
9
|
+
@form = OpenStruct.new(object: Title.new)
|
|
10
|
+
@repository = Uchi::Repositories::Title.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test "inherits from Uchi::Field" do
|
|
14
|
+
assert_kind_of Uchi::Field, @field
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "has default options" do
|
|
18
|
+
assert_equal [:edit, :index, :show], @field.on
|
|
19
|
+
assert_not @field.searchable?
|
|
20
|
+
assert @field.sortable?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "has custom collection_query" do
|
|
24
|
+
custom_query = ->(query) { query.where(active: true) }
|
|
25
|
+
field = Uchi::Field::BelongsTo.new(:book).collection_query(custom_query)
|
|
26
|
+
assert_equal custom_query, field.collection_query
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
test "uses default collection_query" do
|
|
30
|
+
assert_equal Uchi::Field::BelongsTo::DEFAULT_COLLECTION_QUERY, @field.collection_query
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
test "#param_key returns foreign key name" do
|
|
34
|
+
assert_equal :book_id, @field.param_key
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
test "#edit_component returns an instance of Edit component" do
|
|
38
|
+
component = @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
|
|
39
|
+
assert_equal "Custom hint", component.hint
|
|
40
|
+
assert_equal "Custom label", component.label
|
|
41
|
+
assert_equal @field, component.field
|
|
42
|
+
assert_equal @form, component.form
|
|
43
|
+
assert_equal @repository, component.repository
|
|
44
|
+
assert_kind_of Uchi::Field::BelongsTo::Edit, component
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test "#group_as returns :attributes for :edit" do
|
|
48
|
+
assert_equal :attributes, @field.group_as(:edit)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
test "#group_as returns :attributes for :show" do
|
|
52
|
+
assert_equal :attributes, @field.group_as(:show)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
test "#index_component returns an instance of Index component" do
|
|
56
|
+
component = @field.index_component(record: @form.object, repository: @repository)
|
|
57
|
+
assert_equal @field, component.field
|
|
58
|
+
assert_equal @form.object, component.record
|
|
59
|
+
assert_equal @repository, component.repository
|
|
60
|
+
assert_kind_of Uchi::Field::BelongsTo::Index, component
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
test "#searchable? returns false when explicitly set" do
|
|
64
|
+
field = Uchi::Field::BelongsTo.new(:book).searchable(false)
|
|
65
|
+
assert_not field.searchable?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
test "#show_component returns an instance of Show component" do
|
|
69
|
+
component = @field.show_component(record: @form.object, repository: @repository)
|
|
70
|
+
assert_equal @field, component.field
|
|
71
|
+
assert_equal @form.object, component.record
|
|
72
|
+
assert_equal @repository, component.repository
|
|
73
|
+
assert_kind_of Uchi::Field::BelongsTo::Show, component
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
test "#sortable? returns false when explicitly set" do
|
|
77
|
+
field = Uchi::Field::BelongsTo.new(:book).sortable(false)
|
|
78
|
+
assert_not field.sortable?
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class BelongsToIndexTest < ViewComponent::TestCase
|
|
83
|
+
def setup
|
|
84
|
+
@book = Book.create!(original_title: "The Hobbit")
|
|
85
|
+
@title = Title.new(book: @book, locale: "da-DK", title: "Hobbitten")
|
|
86
|
+
@field = Uchi::Field::BelongsTo.new(:book)
|
|
87
|
+
@repository = Uchi::Repositories::Title.new
|
|
88
|
+
|
|
89
|
+
@component = Uchi::Field::BelongsTo::Index.new(
|
|
90
|
+
field: @field,
|
|
91
|
+
record: @title,
|
|
92
|
+
repository: @repository
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
test "inherits from Base component" do
|
|
97
|
+
assert_kind_of Uchi::Field::Base::Index, @component
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
test "renders the field content" do
|
|
101
|
+
result = render_inline(@component)
|
|
102
|
+
|
|
103
|
+
# The component renders the object directly, so we check for the object representation
|
|
104
|
+
assert_not_nil result.to_html
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class BelongsToShowTest < ViewComponent::TestCase
|
|
109
|
+
def setup
|
|
110
|
+
@book = Book.create!(original_title: "The Hobbit")
|
|
111
|
+
@field = Uchi::Field::BelongsTo.new(:book)
|
|
112
|
+
@record = Title.new(book: @book, locale: "da-DK", title: "Hobbitten")
|
|
113
|
+
@repository = Uchi::Repositories::Title.new
|
|
114
|
+
|
|
115
|
+
@component = Uchi::Field::BelongsTo::Show.new(
|
|
116
|
+
field: @field,
|
|
117
|
+
record: @record,
|
|
118
|
+
repository: @repository
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
test "inherits from Base component" do
|
|
123
|
+
assert_kind_of Uchi::Field::Base::Show, @component
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
test "can be rendered without errors" do
|
|
127
|
+
# Skip rendering test due to missing route dependencies
|
|
128
|
+
assert_nothing_raised do
|
|
129
|
+
@component
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "ostruct"
|
|
3
|
+
|
|
4
|
+
module Uchi
|
|
5
|
+
class Field
|
|
6
|
+
class BlankTest < ActiveSupport::TestCase
|
|
7
|
+
def setup
|
|
8
|
+
@field = Uchi::Field::Blank.new(:separator)
|
|
9
|
+
@form = OpenStruct.new(object: OpenStruct.new(separator: nil))
|
|
10
|
+
@repository = Uchi::Repositories::Author.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test "inherits from Uchi::Field" do
|
|
14
|
+
assert_kind_of Uchi::Field, @field
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "has default options" do
|
|
18
|
+
assert_equal [:edit, :index, :show], @field.on
|
|
19
|
+
assert_not @field.searchable?
|
|
20
|
+
assert @field.sortable?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "#edit_component returns an instance of Edit component" do
|
|
24
|
+
component = @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
|
|
25
|
+
assert_equal "Custom hint", component.hint
|
|
26
|
+
assert_equal "Custom label", component.label
|
|
27
|
+
assert_equal @field, component.field
|
|
28
|
+
assert_equal @form, component.form
|
|
29
|
+
assert_equal @repository, component.repository
|
|
30
|
+
assert_kind_of Uchi::Field::Blank::Edit, component
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
test "#index_component returns an instance of Index component" do
|
|
34
|
+
component = @field.index_component(record: @form.object, repository: @repository)
|
|
35
|
+
assert_equal @field, component.field
|
|
36
|
+
assert_equal @form.object, component.record
|
|
37
|
+
assert_equal @repository, component.repository
|
|
38
|
+
assert_kind_of Uchi::Field::Blank::Index, component
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test "#searchable? returns false when explicitly set" do
|
|
42
|
+
field = Uchi::Field::Blank.new(:separator).searchable(false)
|
|
43
|
+
assert_not field.searchable?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
test "#show_component returns an instance of Show component" do
|
|
47
|
+
component = @field.show_component(record: @form.object, repository: @repository)
|
|
48
|
+
assert_equal @field, component.field
|
|
49
|
+
assert_equal @form.object, component.record
|
|
50
|
+
assert_equal @repository, component.repository
|
|
51
|
+
assert_kind_of Uchi::Field::Blank::Show, component
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
test "#sortable? returns false when explicitly set" do
|
|
55
|
+
field = Uchi::Field::Blank.new(:separator).sortable(false)
|
|
56
|
+
assert_not field.sortable?
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class BlankEditTest < ViewComponent::TestCase
|
|
61
|
+
def setup
|
|
62
|
+
@field = Uchi::Field::Blank.new(:separator)
|
|
63
|
+
@record = Author.new(name: "Test Author")
|
|
64
|
+
@repository = Uchi::Repositories::Author.new
|
|
65
|
+
@view_context = ActionController::Base.new.view_context
|
|
66
|
+
|
|
67
|
+
@form = ActionView::Helpers::FormBuilder.new(:author, @record, @view_context, {})
|
|
68
|
+
|
|
69
|
+
@component = Uchi::Field::Blank::Edit.new(
|
|
70
|
+
field: @field,
|
|
71
|
+
form: @form,
|
|
72
|
+
hint: "Custom hint",
|
|
73
|
+
label: "Custom label",
|
|
74
|
+
repository: @repository
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
test "inherits from Base component" do
|
|
79
|
+
assert_kind_of Uchi::Field::Base::Edit, @component
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
class BlankIndexTest < ViewComponent::TestCase
|
|
84
|
+
def setup
|
|
85
|
+
@field = Uchi::Field::Blank.new(:separator)
|
|
86
|
+
@record = Author.new(name: "Test Author")
|
|
87
|
+
@repository = Uchi::Repositories::Author.new
|
|
88
|
+
|
|
89
|
+
@component = Uchi::Field::Blank::Index.new(
|
|
90
|
+
field: @field,
|
|
91
|
+
record: @record,
|
|
92
|
+
repository: @repository
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
test "inherits from Base component" do
|
|
97
|
+
assert_kind_of Uchi::Field::Base::Index, @component
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class BlankShowTest < ViewComponent::TestCase
|
|
102
|
+
def setup
|
|
103
|
+
@field = Uchi::Field::Blank.new(:separator)
|
|
104
|
+
@record = Author.new(name: "Test Author")
|
|
105
|
+
@repository = Uchi::Repositories::Author.new
|
|
106
|
+
|
|
107
|
+
@component = Uchi::Field::Blank::Show.new(
|
|
108
|
+
field: @field,
|
|
109
|
+
record: @record,
|
|
110
|
+
repository: @repository
|
|
111
|
+
)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
test "inherits from Base component" do
|
|
115
|
+
assert_kind_of Uchi::Field::Base::Show, @component
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|