katalyst-koi 5.1.0 → 5.2.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 +4 -4
- data/README.md +6 -4
- data/app/assets/builds/katalyst/koi.esm.js +0 -323
- data/app/assets/builds/katalyst/koi.js +0 -323
- data/app/assets/builds/katalyst/koi.min.js +1 -1
- data/app/assets/builds/katalyst/koi.min.js.map +1 -1
- data/app/assets/stylesheets/koi/blocks/pagy.css +2 -1
- data/app/assets/stylesheets/koi/utilities/visually-hidden.css +0 -7
- data/app/controllers/admin/admin_users_controller.rb +2 -2
- data/app/controllers/admin/caches_controller.rb +1 -1
- data/app/controllers/admin/otps_controller.rb +1 -1
- data/app/controllers/concerns/koi/controller.rb +9 -5
- data/app/javascript/koi/controllers/index.js +0 -15
- data/config/locales/pagy/en.yml +24 -0
- data/lib/generators/koi/admin_controller/templates/controller.rb.tt +8 -8
- data/lib/koi/engine.rb +6 -1
- metadata +2 -7
- data/Upgrade.md +0 -10
- data/app/assets/stylesheets/koi/blocks/index-actions.css +0 -69
- data/app/helpers/koi/index_actions_helper.rb +0 -98
- data/app/javascript/koi/controllers/form_request_submit_controller.js +0 -11
- data/app/javascript/koi/controllers/index_actions_controller.js +0 -60
- data/config/locales/pagy.en.yml +0 -11
|
@@ -14,14 +14,11 @@ application.load(tables);
|
|
|
14
14
|
|
|
15
15
|
import ClipboardController from "./clipboard_controller";
|
|
16
16
|
import FlashController from "./flash_controller";
|
|
17
|
-
import FormRequestSubmitController from "./form_request_submit_controller";
|
|
18
|
-
import IndexActionsController from "./index_actions_controller";
|
|
19
17
|
import KeyboardController from "./keyboard_controller";
|
|
20
18
|
import ModalController from "./modal_controller";
|
|
21
19
|
import NavigationController from "./navigation_controller";
|
|
22
20
|
import NavigationToggleController from "./navigation_toggle_controller";
|
|
23
21
|
import PagyNavController from "./pagy_nav_controller";
|
|
24
|
-
import ShowHideController from "./show_hide_controller";
|
|
25
22
|
import SluggableController from "./sluggable_controller";
|
|
26
23
|
import WebauthnAuthenticationController from "./webauthn_authentication_controller";
|
|
27
24
|
import WebauthnRegistrationController from "./webauthn_registration_controller";
|
|
@@ -35,14 +32,6 @@ const Definitions = [
|
|
|
35
32
|
identifier: "flash",
|
|
36
33
|
controllerConstructor: FlashController,
|
|
37
34
|
},
|
|
38
|
-
{
|
|
39
|
-
identifier: "form-request-submit",
|
|
40
|
-
controllerConstructor: FormRequestSubmitController,
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
identifier: "index-actions",
|
|
44
|
-
controllerConstructor: IndexActionsController,
|
|
45
|
-
},
|
|
46
35
|
{
|
|
47
36
|
identifier: "keyboard",
|
|
48
37
|
controllerConstructor: KeyboardController,
|
|
@@ -63,10 +52,6 @@ const Definitions = [
|
|
|
63
52
|
identifier: "pagy-nav",
|
|
64
53
|
controllerConstructor: PagyNavController,
|
|
65
54
|
},
|
|
66
|
-
{
|
|
67
|
-
identifier: "show-hide",
|
|
68
|
-
controllerConstructor: ShowHideController,
|
|
69
|
-
},
|
|
70
55
|
{
|
|
71
56
|
identifier: "sluggable",
|
|
72
57
|
controllerConstructor: SluggableController,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
en:
|
|
2
|
+
pagy:
|
|
3
|
+
p11n: 'OneOther'
|
|
4
|
+
aria_label:
|
|
5
|
+
nav:
|
|
6
|
+
one: "Pagination"
|
|
7
|
+
other: "Pagination"
|
|
8
|
+
prev: "Previous page"
|
|
9
|
+
previous: "Previous page" # @deprecated
|
|
10
|
+
next: "Next page"
|
|
11
|
+
prev: "← Previous" # @deprecated
|
|
12
|
+
previous: "← Previous"
|
|
13
|
+
next: "Next →"
|
|
14
|
+
gap: "…"
|
|
15
|
+
item_name:
|
|
16
|
+
one: "item"
|
|
17
|
+
other: "items"
|
|
18
|
+
info_tag:
|
|
19
|
+
no_count: "Page %{page} of %{pages}"
|
|
20
|
+
no_items: "No %{item_name} found"
|
|
21
|
+
single_page: "Displaying %{count} %{item_name}"
|
|
22
|
+
multiple_pages: "Displaying %{item_name} %{from}-%{to} of %{count} in total"
|
|
23
|
+
input_nav_js: "Page %{page_input} of %{pages}"
|
|
24
|
+
limit_tag_js: "Show %{limit_input} %{item_name} per page"
|
|
@@ -41,9 +41,9 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
41
41
|
@<%= singular_name %> = <%= class_name %>.new(<%= singular_table_name %>_params)
|
|
42
42
|
|
|
43
43
|
if <%= singular_name %>.save
|
|
44
|
-
redirect_to
|
|
44
|
+
redirect_to(<%= admin_show_helper %>, status: :see_other)
|
|
45
45
|
else
|
|
46
|
-
render
|
|
46
|
+
render(:new, locals: { <%= singular_name %>: }, status: :unprocessable_content)
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
51
51
|
if <%= singular_name %>.update(<%= singular_table_name %>_params)
|
|
52
52
|
redirect_to <%= admin_show_helper %>, status: :see_other
|
|
53
53
|
else
|
|
54
|
-
render
|
|
54
|
+
render(:edit, locals: { <%= singular_name %>: }, status: :unprocessable_content)
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -59,13 +59,13 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
59
59
|
def archive
|
|
60
60
|
<%= class_name %>.where(id: params[:id]).each(&:archive!)
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
redirect_back_or_to(<%= admin_index_helper %>, status: :see_other)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def restore
|
|
66
66
|
<%= class_name %>.archived.where(id: params[:id]).each(&:restore!)
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
redirect_back_or_to(<%= admin_index_helper %>, status: :see_other)
|
|
69
69
|
end
|
|
70
70
|
<%- end -%>
|
|
71
71
|
|
|
@@ -75,7 +75,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
75
75
|
<%= class_name %>.find(id).update(attrs)
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
redirect_back_or_to(<%= admin_index_helper %>, status: :see_other)
|
|
79
79
|
end
|
|
80
80
|
<%- end -%>
|
|
81
81
|
|
|
@@ -84,7 +84,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
84
84
|
if <%= singular_name %>.archived?
|
|
85
85
|
<%= singular_name %>.destroy!
|
|
86
86
|
|
|
87
|
-
redirect_to
|
|
87
|
+
redirect_to(<%= admin_index_helper %>, status: :see_other)
|
|
88
88
|
else
|
|
89
89
|
<%= singular_name %>.archive!
|
|
90
90
|
|
|
@@ -93,7 +93,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
93
93
|
<%- else -%>
|
|
94
94
|
<%= singular_name %>.destroy!
|
|
95
95
|
|
|
96
|
-
redirect_to
|
|
96
|
+
redirect_to(<%= admin_index_helper %>, status: :see_other)
|
|
97
97
|
<%- end -%>
|
|
98
98
|
end
|
|
99
99
|
|
data/lib/koi/engine.rb
CHANGED
|
@@ -64,7 +64,12 @@ module Koi
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
initializer "koi.pagination" do
|
|
67
|
-
Pagy::I18n.
|
|
67
|
+
if Pagy::I18n.respond_to?(:pathnames)
|
|
68
|
+
Pagy::I18n.pathnames << root.join("config/locales/pagy")
|
|
69
|
+
else
|
|
70
|
+
# @deprecated support for Pagy <43
|
|
71
|
+
Pagy::I18n.load(locale: "en", filepath: root.join("config/locales/pagy/en.yml"))
|
|
72
|
+
end
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
initializer "koi.views" do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: katalyst-koi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Katalyst Interactive
|
|
@@ -227,7 +227,6 @@ extra_rdoc_files: []
|
|
|
227
227
|
files:
|
|
228
228
|
- MIT-LICENSE
|
|
229
229
|
- README.md
|
|
230
|
-
- Upgrade.md
|
|
231
230
|
- app/assets/builds/katalyst/koi.esm.js
|
|
232
231
|
- app/assets/builds/katalyst/koi.js
|
|
233
232
|
- app/assets/builds/katalyst/koi.min.js
|
|
@@ -272,7 +271,6 @@ files:
|
|
|
272
271
|
- app/assets/stylesheets/koi/blocks/clipboard.css
|
|
273
272
|
- app/assets/stylesheets/koi/blocks/flash.css
|
|
274
273
|
- app/assets/stylesheets/koi/blocks/icon.css
|
|
275
|
-
- app/assets/stylesheets/koi/blocks/index-actions.css
|
|
276
274
|
- app/assets/stylesheets/koi/blocks/index.css
|
|
277
275
|
- app/assets/stylesheets/koi/blocks/modal.css
|
|
278
276
|
- app/assets/stylesheets/koi/blocks/navigation.css
|
|
@@ -352,16 +350,13 @@ files:
|
|
|
352
350
|
- app/controllers/well_knowns_controller.rb
|
|
353
351
|
- app/helpers/koi/form_helper.rb
|
|
354
352
|
- app/helpers/koi/header_helper.rb
|
|
355
|
-
- app/helpers/koi/index_actions_helper.rb
|
|
356
353
|
- app/helpers/koi/modal_helper.rb
|
|
357
354
|
- app/helpers/koi/pagy.rb
|
|
358
355
|
- app/javascript/koi/application.js
|
|
359
356
|
- app/javascript/koi/controllers/application.js
|
|
360
357
|
- app/javascript/koi/controllers/clipboard_controller.js
|
|
361
358
|
- app/javascript/koi/controllers/flash_controller.js
|
|
362
|
-
- app/javascript/koi/controllers/form_request_submit_controller.js
|
|
363
359
|
- app/javascript/koi/controllers/index.js
|
|
364
|
-
- app/javascript/koi/controllers/index_actions_controller.js
|
|
365
360
|
- app/javascript/koi/controllers/keyboard_controller.js
|
|
366
361
|
- app/javascript/koi/controllers/modal_controller.js
|
|
367
362
|
- app/javascript/koi/controllers/navigation_controller.js
|
|
@@ -440,7 +435,7 @@ files:
|
|
|
440
435
|
- config/initializers/flipper.rb
|
|
441
436
|
- config/initializers/inflections.rb
|
|
442
437
|
- config/locales/koi.en.yml
|
|
443
|
-
- config/locales/pagy
|
|
438
|
+
- config/locales/pagy/en.yml
|
|
444
439
|
- config/routes.rb
|
|
445
440
|
- db/migrate/20120220130849_devise_create_admins.rb
|
|
446
441
|
- db/migrate/20130509235316_add_url_rewriter.rb
|
data/Upgrade.md
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
.index-actions > form {
|
|
2
|
-
display: flex;
|
|
3
|
-
align-items: stretch;
|
|
4
|
-
justify-content: space-between;
|
|
5
|
-
margin-bottom: 1rem;
|
|
6
|
-
|
|
7
|
-
// checkbox styles based on govuk-frontend
|
|
8
|
-
|
|
9
|
-
input[type="checkbox"] {
|
|
10
|
-
cursor: pointer;
|
|
11
|
-
position: absolute;
|
|
12
|
-
z-index: 1;
|
|
13
|
-
top: 0;
|
|
14
|
-
bottom: 0;
|
|
15
|
-
left: 0;
|
|
16
|
-
width: 2.5rem;
|
|
17
|
-
opacity: 0;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
label:has(input[type="checkbox"]) {
|
|
21
|
-
display: inline-block;
|
|
22
|
-
position: relative;
|
|
23
|
-
margin-bottom: 0;
|
|
24
|
-
padding: 0 0 0 calc(2.5rem + 5px);
|
|
25
|
-
line-height: 2.5rem;
|
|
26
|
-
cursor: pointer;
|
|
27
|
-
-ms-touch-action: manipulation;
|
|
28
|
-
touch-action: manipulation;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
label:has(input[type="checkbox"])::before {
|
|
32
|
-
content: "";
|
|
33
|
-
box-sizing: border-box;
|
|
34
|
-
position: absolute;
|
|
35
|
-
top: 0;
|
|
36
|
-
bottom: 0;
|
|
37
|
-
left: 0;
|
|
38
|
-
aspect-ratio: 1/1;
|
|
39
|
-
border: 2px solid currentcolor;
|
|
40
|
-
background: transparent;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
label:has(input[type="checkbox"]:focus)::before {
|
|
44
|
-
border-width: 4px;
|
|
45
|
-
outline: 3px solid transparent;
|
|
46
|
-
outline-offset: 1px;
|
|
47
|
-
box-shadow: 0 0 0 3px #ffdd00;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
label:has(input[type="checkbox"])::after {
|
|
51
|
-
content: "";
|
|
52
|
-
box-sizing: border-box;
|
|
53
|
-
position: absolute;
|
|
54
|
-
top: 12px;
|
|
55
|
-
left: 9px;
|
|
56
|
-
width: 23px;
|
|
57
|
-
height: 12px;
|
|
58
|
-
transform: rotate(-45deg);
|
|
59
|
-
border: solid;
|
|
60
|
-
border-width: 0 0 5px 5px;
|
|
61
|
-
border-top-color: transparent;
|
|
62
|
-
opacity: 0;
|
|
63
|
-
background: transparent;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
label:has(input[type="checkbox"][checked])::after {
|
|
67
|
-
opacity: 1;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Koi
|
|
4
|
-
module IndexActionsHelper
|
|
5
|
-
# @deprecated to be removed in Koi 5
|
|
6
|
-
def koi_index_actions(search: false, create: false, &)
|
|
7
|
-
IndexActionsBuilder.new(self, search:, create:).render(&)
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
class IndexActionsBuilder
|
|
12
|
-
delegate_missing_to :@context
|
|
13
|
-
|
|
14
|
-
def initialize(context, search:, create:)
|
|
15
|
-
@context = context
|
|
16
|
-
@search = search
|
|
17
|
-
@create = create
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def search?
|
|
21
|
-
!!@search
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def create?
|
|
25
|
-
!!@create
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def render(&)
|
|
29
|
-
tag.nav class: "index-actions", data: { controller: "index-actions", action: actions } do
|
|
30
|
-
form_with(**search_options,
|
|
31
|
-
data: { controller: "search",
|
|
32
|
-
turbo_action: "replace",
|
|
33
|
-
action: <<~ACTIONS,
|
|
34
|
-
input->index-actions#update
|
|
35
|
-
change->index-actions#update
|
|
36
|
-
submit->index-actions#submit
|
|
37
|
-
ACTIONS
|
|
38
|
-
}) do |form|
|
|
39
|
-
concat(links(form, &))
|
|
40
|
-
concat(sort_input(form))
|
|
41
|
-
concat(search(form)) if create? || search?
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def search(form)
|
|
47
|
-
tag.div class: "actions" do
|
|
48
|
-
concat(search_button(form)) if search?
|
|
49
|
-
concat(create_button(form)) if create?
|
|
50
|
-
concat(search_input(form)) if search?
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def sort_input(form)
|
|
55
|
-
form.hidden_field(:sort, value: params[:sort], data: { index_actions_target: "sort" })
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Hidden button to trigger search, avoids triggering create instead.
|
|
59
|
-
def search_button(form)
|
|
60
|
-
form.submit("Search", hidden: "")
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def create_button(_form)
|
|
64
|
-
tag.button(t("koi.labels.new", default: "New"),
|
|
65
|
-
type: :submit,
|
|
66
|
-
formaction: @create == true ? url_for(action: :new) : new_polymorphic_path(@create),
|
|
67
|
-
class: "button--primary",
|
|
68
|
-
data: { index_actions_target: "create" })
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def search_input(form)
|
|
72
|
-
form.search_field(:search,
|
|
73
|
-
placeholder: t("koi.labels.search", default: "Search"),
|
|
74
|
-
value: params[:search],
|
|
75
|
-
data: { index_actions_target: "search", turbo_permanent: "" })
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def links(form, &)
|
|
79
|
-
tag.div(class: "actions") do
|
|
80
|
-
yield(form) if block_given?
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def actions
|
|
85
|
-
[
|
|
86
|
-
("shortcut:cancel@document->index-actions#clear" if search?),
|
|
87
|
-
("shortcut:create@document->index-actions#create" if create?),
|
|
88
|
-
("shortcut:search@document->index-actions#search" if search?),
|
|
89
|
-
].compact.join(" ")
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def search_options
|
|
93
|
-
options = { url: request.path, method: :get, scope: "" }
|
|
94
|
-
options.merge!(@search) if @search.is_a?(Hash)
|
|
95
|
-
options
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Controller } from "@hotwired/stimulus";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
A stimulus controller to request form submissions.
|
|
5
|
-
This controller should be attached to a form element.
|
|
6
|
-
*/
|
|
7
|
-
export default class FormRequestSubmitController extends Controller {
|
|
8
|
-
requestSubmit() {
|
|
9
|
-
this.element.requestSubmit();
|
|
10
|
-
}
|
|
11
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { Controller } from "@hotwired/stimulus";
|
|
2
|
-
|
|
3
|
-
export default class IndexActionsController extends Controller {
|
|
4
|
-
static targets = ["create", "search", "sort"];
|
|
5
|
-
|
|
6
|
-
initialize() {
|
|
7
|
-
// debounce search
|
|
8
|
-
this.update = debounce(this, this.update);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
disconnect() {
|
|
12
|
-
clearTimeout(this.timer);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
create() {
|
|
16
|
-
this.createTarget.click();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
search() {
|
|
20
|
-
this.searchTarget.focus();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
clear() {
|
|
24
|
-
this.searchTarget.value = "";
|
|
25
|
-
this.searchTarget.closest("form").requestSubmit();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
update() {
|
|
29
|
-
this.searchTarget.closest("form").requestSubmit();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
submit() {
|
|
33
|
-
const shouldFocus = document.activeElement === this.searchTarget;
|
|
34
|
-
|
|
35
|
-
if (this.searchTarget.value === "") {
|
|
36
|
-
this.searchTarget.disabled = true;
|
|
37
|
-
}
|
|
38
|
-
if (this.sortTarget.value === "") {
|
|
39
|
-
this.sortTarget.disabled = true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// restore state and focus after submit
|
|
43
|
-
Promise.resolve().then(() => {
|
|
44
|
-
this.searchTarget.disabled = false;
|
|
45
|
-
this.sortTarget.disabled = false;
|
|
46
|
-
if (shouldFocus) {
|
|
47
|
-
this.searchTarget.focus();
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function debounce(self, f) {
|
|
54
|
-
return (...args) => {
|
|
55
|
-
clearTimeout(self.timer);
|
|
56
|
-
self.timer = setTimeout(() => {
|
|
57
|
-
f.apply(self, ...args);
|
|
58
|
-
}, 300);
|
|
59
|
-
};
|
|
60
|
-
}
|