katalyst-koi 4.18.1 → 5.0.0.alpha.1
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/images/koi/icons/add.svg +3 -0
- data/app/assets/images/koi/icons/close.svg +1 -0
- data/app/assets/images/koi/koi.png +0 -0
- data/app/assets/javascripts/koi/controllers/file_field_controller.js +2 -2
- data/app/assets/javascripts/koi/controllers/index.js +0 -3
- data/app/assets/javascripts/koi/controllers/koi/modal_controller.js +40 -0
- data/app/assets/javascripts/koi/controllers/navigation_controller.js +14 -21
- data/app/assets/javascripts/koi/controllers/webauthn_registration_controller.js +4 -1
- data/app/assets/stylesheets/koi/blocks/actions.css +8 -0
- data/app/assets/stylesheets/koi/blocks/application-header.css +15 -0
- data/app/assets/stylesheets/koi/blocks/application-navigation.css +54 -0
- data/app/assets/stylesheets/koi/blocks/button.css +90 -0
- data/app/assets/stylesheets/koi/blocks/flash.css +19 -0
- data/app/assets/stylesheets/koi/blocks/icon.css +15 -0
- data/app/assets/stylesheets/koi/blocks/index.css +13 -0
- data/app/assets/stylesheets/koi/blocks/modal.css +26 -0
- data/app/assets/stylesheets/koi/blocks/navigation.css +23 -0
- data/app/assets/stylesheets/koi/blocks/page-header.css +31 -0
- data/app/assets/stylesheets/koi/blocks/pagy.css +82 -0
- data/app/assets/stylesheets/koi/blocks/prose.css +37 -0
- data/app/assets/stylesheets/koi/blocks/tables/index.css +4 -0
- data/app/assets/stylesheets/koi/{components/_query.scss → blocks/tables/query.css} +13 -13
- data/app/assets/stylesheets/koi/{base/_tables.scss → blocks/tables/table.css} +11 -59
- data/app/assets/stylesheets/koi/compositions/cover.css +17 -0
- data/app/assets/stylesheets/koi/{base/_flow.scss → compositions/flow.css} +1 -1
- data/app/assets/stylesheets/koi/compositions/index.css +4 -0
- data/app/assets/stylesheets/koi/compositions/wrapper.css +11 -0
- data/app/assets/stylesheets/koi/forms/caption.css +22 -0
- data/app/assets/stylesheets/koi/forms/checkboxes.css +153 -0
- data/app/assets/stylesheets/koi/forms/date-input.css +12 -0
- data/app/assets/stylesheets/koi/{components/_document-field.scss → forms/document-field.css} +20 -15
- data/app/assets/stylesheets/koi/forms/errors.css +38 -0
- data/app/assets/stylesheets/koi/forms/fieldset.css +73 -0
- data/app/assets/stylesheets/koi/forms/file-upload.css +20 -0
- data/app/assets/stylesheets/koi/forms/form-group.css +19 -0
- data/app/assets/stylesheets/koi/forms/hint.css +11 -0
- data/app/assets/stylesheets/koi/forms/image-field.css +96 -0
- data/app/assets/stylesheets/koi/forms/index.css +44 -0
- data/app/assets/stylesheets/koi/forms/input.css +194 -0
- data/app/assets/stylesheets/koi/forms/label.css +43 -0
- data/app/assets/stylesheets/koi/forms/password.css +18 -0
- data/app/assets/stylesheets/koi/forms/radios.css +162 -0
- data/app/assets/stylesheets/koi/forms/select.css +18 -0
- data/app/assets/stylesheets/koi/forms/textarea.css +3 -0
- data/app/assets/stylesheets/koi/forms/trix.css +33 -0
- data/app/assets/stylesheets/koi/global/fonts.css +22 -0
- data/app/assets/stylesheets/koi/global/global-styles.css +297 -0
- data/app/assets/stylesheets/koi/global/reset.css +98 -0
- data/app/assets/stylesheets/koi/global/variables.css +97 -0
- data/app/assets/stylesheets/koi/icons.css +14 -0
- data/app/assets/stylesheets/koi/{admin.scss → index.css} +16 -7
- data/app/assets/stylesheets/koi/login.css +26 -0
- data/app/assets/stylesheets/koi/themes/_index.scss +0 -1
- data/app/assets/stylesheets/koi/utilities/index.css +1 -0
- data/app/assets/stylesheets/koi/utilities/visually-hidden.css +18 -0
- data/app/components/concerns/koi/tables/cells.rb +3 -3
- data/app/components/koi/header_component.html.erb +12 -11
- data/app/components/koi/header_component.rb +2 -0
- data/app/components/koi/table_component.rb +8 -0
- data/app/controllers/admin/admin_users_controller.rb +24 -18
- data/app/controllers/admin/application_controller.rb +1 -3
- data/app/controllers/admin/credentials_controller.rb +18 -14
- data/app/controllers/admin/otps_controller.rb +15 -13
- data/app/controllers/admin/sessions_controller.rb +12 -1
- data/app/controllers/admin/url_rewrites_controller.rb +19 -17
- data/app/controllers/admin/well_knowns_controller.rb +20 -18
- data/app/controllers/concerns/koi/controller.rb +37 -0
- data/app/helpers/koi/form_helper.rb +18 -0
- data/app/helpers/koi/header_helper.rb +122 -0
- data/app/helpers/koi/index_actions_helper.rb +3 -2
- data/app/helpers/koi/modal_helper.rb +71 -0
- data/app/models/admin/user.rb +7 -1
- data/app/models/url_rewrite.rb +1 -9
- data/app/views/admin/admin_users/_form.html+self.erb +8 -0
- data/app/views/admin/admin_users/_form.html.erb +8 -0
- data/app/views/admin/admin_users/archived.html.erb +7 -4
- data/app/views/admin/admin_users/edit.html+self.erb +12 -0
- data/app/views/admin/admin_users/edit.html.erb +13 -8
- data/app/views/admin/admin_users/index.html.erb +10 -5
- data/app/views/admin/admin_users/new.html.erb +8 -8
- data/app/views/admin/admin_users/show.html+self.erb +26 -14
- data/app/views/admin/admin_users/show.html.erb +22 -20
- data/app/views/admin/credentials/_credentials.html+self.erb +8 -6
- data/app/views/admin/credentials/_credentials.html.erb +3 -1
- data/app/views/admin/credentials/create.turbo_stream.erb +4 -3
- data/app/views/admin/credentials/destroy.turbo_stream.erb +4 -2
- data/app/views/admin/credentials/new.html.erb +42 -36
- data/app/views/admin/dashboards/show.html.erb +13 -1
- data/app/views/admin/otps/_form.html.erb +7 -7
- data/app/views/admin/otps/create.turbo_stream.erb +3 -3
- data/app/views/admin/otps/new.html.erb +5 -3
- data/app/views/admin/sessions/new.html.erb +2 -3
- data/app/views/admin/sessions/otp.html.erb +1 -3
- data/app/views/admin/sessions/password.html.erb +1 -3
- data/app/views/admin/tokens/show.html.erb +4 -6
- data/app/views/admin/url_rewrites/_form.html.erb +9 -0
- data/app/views/admin/url_rewrites/edit.html.erb +13 -9
- data/app/views/admin/url_rewrites/index.html.erb +10 -7
- data/app/views/admin/url_rewrites/new.html.erb +8 -8
- data/app/views/admin/url_rewrites/show.html.erb +17 -12
- data/app/views/admin/well_knowns/_form.html.erb +9 -0
- data/app/views/admin/well_knowns/edit.html.erb +13 -9
- data/app/views/admin/well_knowns/index.html.erb +8 -5
- data/app/views/admin/well_knowns/new.html.erb +8 -8
- data/app/views/admin/well_knowns/show.html.erb +14 -13
- data/app/views/katalyst/content/asides/_aside.html+form.erb +6 -4
- data/app/views/katalyst/content/columns/_column.html+form.erb +5 -3
- data/app/views/katalyst/content/contents/_content.html+form.erb +8 -6
- data/app/views/katalyst/content/figures/_figure.html+form.erb +8 -5
- data/app/views/katalyst/content/groups/_group.html+form.erb +5 -3
- data/app/views/katalyst/content/items/_item.html+form.erb +5 -3
- data/app/views/katalyst/content/sections/_section.html+form.erb +5 -3
- data/app/views/katalyst/content/tables/_table.html+form.erb +16 -11
- data/app/views/katalyst/navigation/items/_button.html.erb +6 -12
- data/app/views/katalyst/navigation/items/_heading.html.erb +3 -10
- data/app/views/katalyst/navigation/items/_link.html.erb +6 -11
- data/app/views/katalyst/navigation/menus/edit.html.erb +10 -6
- data/app/views/katalyst/navigation/menus/index.html.erb +4 -2
- data/app/views/katalyst/navigation/menus/new.html.erb +5 -3
- data/app/views/katalyst/navigation/menus/show.html.erb +8 -7
- data/app/views/layouts/koi/_application_header.html.erb +20 -0
- data/app/views/layouts/koi/_application_navigation.html.erb +34 -0
- data/app/views/layouts/koi/_flash.html.erb +6 -3
- data/app/views/layouts/koi/_navigation_header.html.erb +0 -2
- data/app/views/layouts/koi/application.html.erb +22 -27
- data/app/views/layouts/koi/frame.html.erb +1 -3
- data/app/views/layouts/koi/login.html.erb +12 -5
- data/config/locales/koi.en.yml +9 -1
- data/config/routes.rb +1 -1
- data/lib/generators/koi/admin/admin_generator.rb +3 -12
- data/lib/generators/koi/admin_controller/admin_controller_generator.rb +6 -16
- data/lib/generators/koi/admin_controller/templates/controller.rb.tt +82 -18
- data/lib/generators/koi/admin_controller/templates/controller_spec.rb.tt +113 -47
- data/lib/generators/koi/admin_route/admin_route_generator.rb +60 -6
- data/lib/generators/koi/admin_views/USAGE +18 -7
- data/lib/generators/koi/admin_views/admin_views_generator.rb +19 -11
- data/lib/generators/koi/admin_views/templates/_form.html.erb.tt +8 -0
- data/lib/generators/koi/admin_views/templates/archived.html.erb.tt +33 -0
- data/lib/generators/koi/admin_views/templates/edit.html.erb.tt +17 -9
- data/lib/generators/koi/admin_views/templates/index.html.erb.tt +31 -3
- data/lib/generators/koi/admin_views/templates/new.html.erb.tt +8 -8
- data/lib/generators/koi/admin_views/templates/show.html.erb.tt +15 -18
- data/lib/generators/koi/helpers/attribute_helpers.rb +147 -0
- data/lib/generators/koi/helpers/attribute_types.rb +218 -0
- data/lib/generators/koi/helpers/resource_helpers.rb +121 -0
- data/lib/generators/koi/{active_record/active_record_generator.rb → model/model_generator.rb} +1 -1
- data/lib/koi/config.rb +3 -1
- data/lib/koi/engine.rb +0 -9
- data/lib/koi/form/builder.rb +4 -4
- data/lib/koi/form/content.rb +55 -0
- data/lib/koi/form/elements/document.rb +1 -1
- data/lib/koi/form/elements/image.rb +1 -1
- data/lib/koi/form_builder.rb +1 -0
- data/lib/koi/menu.rb +14 -1
- data/spec/factories/admins.rb +1 -1
- metadata +90 -99
- data/app/assets/builds/koi/admin.css +0 -1
- data/app/assets/stylesheets/koi/base/_button.scss +0 -122
- data/app/assets/stylesheets/koi/base/_icon.scss +0 -29
- data/app/assets/stylesheets/koi/base/_index.scss +0 -21
- data/app/assets/stylesheets/koi/base/_input.scss +0 -19
- data/app/assets/stylesheets/koi/base/_link.scss +0 -26
- data/app/assets/stylesheets/koi/base/_list.scss +0 -11
- data/app/assets/stylesheets/koi/base/_typography.scss +0 -160
- data/app/assets/stylesheets/koi/components/_actions-group.scss +0 -7
- data/app/assets/stylesheets/koi/components/_image-field.scss +0 -95
- data/app/assets/stylesheets/koi/components/_index.scss +0 -9
- data/app/assets/stylesheets/koi/components/_pagy.scss +0 -29
- data/app/assets/stylesheets/koi/components/_summary-list.scss +0 -40
- data/app/assets/stylesheets/koi/layouts/_banner.scss +0 -7
- data/app/assets/stylesheets/koi/layouts/_content.scss +0 -40
- data/app/assets/stylesheets/koi/layouts/_flash.scss +0 -41
- data/app/assets/stylesheets/koi/layouts/_header.scss +0 -61
- data/app/assets/stylesheets/koi/layouts/_index.scss +0 -48
- data/app/assets/stylesheets/koi/layouts/_main.scss +0 -23
- data/app/assets/stylesheets/koi/layouts/_navigation.scss +0 -180
- data/app/assets/stylesheets/koi/layouts/_stack.scss +0 -13
- data/app/assets/stylesheets/koi/pages/_index.scss +0 -1
- data/app/assets/stylesheets/koi/pages/_login.scss +0 -46
- data/app/assets/stylesheets/koi/themes/_govuk.scss +0 -56
- data/app/assets/stylesheets/koi/themes/_kpop.scss +0 -5
- data/app/assets/stylesheets/koi/utils/_breakpoints.scss +0 -13
- data/app/assets/stylesheets/koi/utils/_hide.scss +0 -11
- data/app/assets/stylesheets/koi/utils/_index.scss +0 -2
- data/app/assets/stylesheets/koi/utils/_typography.scss +0 -42
- data/app/components/koi/content/editor/item_form_component.html.erb +0 -11
- data/app/components/koi/content/editor/item_form_component.rb +0 -94
- data/app/components/koi/summary_list/attachment_component.rb +0 -47
- data/app/components/koi/summary_list/base.rb +0 -59
- data/app/components/koi/summary_list/boolean_component.rb +0 -15
- data/app/components/koi/summary_list/date_component.rb +0 -17
- data/app/components/koi/summary_list/datetime_component.rb +0 -17
- data/app/components/koi/summary_list/item_component.rb +0 -26
- data/app/components/koi/summary_list/number_component.rb +0 -21
- data/app/components/koi/summary_list/rich_text_component.rb +0 -8
- data/app/components/koi/summary_list/text_component.rb +0 -8
- data/app/components/koi/summary_list_component.html.erb +0 -5
- data/app/components/koi/summary_list_component.rb +0 -75
- data/app/controllers/concerns/koi/controller/is_admin_controller.rb +0 -66
- data/app/helpers/koi/application_helper.rb +0 -7
- data/app/helpers/koi/date_helper.rb +0 -26
- data/app/helpers/koi/definition_list_helper.rb +0 -10
- data/app/views/admin/admin_users/_fields.html+self.erb +0 -3
- data/app/views/admin/admin_users/_fields.html.erb +0 -3
- data/app/views/admin/url_rewrites/_fields.html.erb +0 -4
- data/app/views/admin/well_knowns/_fields.html.erb +0 -6
- data/app/views/layouts/koi/_environment.html.erb +0 -4
- data/app/views/layouts/koi/_header.html.erb +0 -11
- data/app/views/layouts/koi/_navigation.html.erb +0 -23
- data/app/views/layouts/koi/_navigation_collapse.html.erb +0 -3
- data/lib/generators/koi/admin_views/templates/_fields.html.erb.tt +0 -3
- data/lib/generators/koi/helpers/admin_generator_attributes.rb +0 -66
- data/lib/koi/extensions/dartsass.rb +0 -23
- /data/app/assets/stylesheets/koi/{components/_clipboard.scss → blocks/clipboard.css} +0 -0
- /data/app/assets/stylesheets/koi/{components/_index-actions.scss → blocks/index-actions.css} +0 -0
- /data/app/assets/stylesheets/koi/{components/_toolbar.scss → blocks/toolbar.css} +0 -0
- /data/app/assets/stylesheets/koi/{base/_repel.scss → compositions/repel.css} +0 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Koi
|
4
|
+
module ModalHelper
|
5
|
+
def koi_modal_tag(frame_id = "modal", frame: {}, dialog: {}, **attributes, &block)
|
6
|
+
if block
|
7
|
+
turbo_frame_tag(frame_id, **_koi_modal_frame_attributes(frame)) do
|
8
|
+
tag.dialog(**_koi_modal_dialog_attributes(dialog)) do
|
9
|
+
tag.article(**_koi_modal_article_attributes(attributes), &block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
else
|
13
|
+
turbo_frame_tag(frame_id, **_koi_modal_frame_attributes(frame))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def koi_modal_header(title:, form_id:, **)
|
18
|
+
tag.header(class: "repel", data: "nowrap") do
|
19
|
+
concat(tag.h2(title))
|
20
|
+
concat(tag.button(
|
21
|
+
form: form_id,
|
22
|
+
formmethod: "dialog",
|
23
|
+
class: "button",
|
24
|
+
data: { button_padding: "tight",
|
25
|
+
"text-button": "" },
|
26
|
+
) do
|
27
|
+
tag.icon(" ".html_safe, aria: { hidden: true }, class: "icon", data: { icon: "close" }) +
|
28
|
+
tag.span("Close", class: "visually-hidden")
|
29
|
+
end)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def koi_modal_footer(submit = "Save", discard = "Discard", form_id:, reverse: true)
|
34
|
+
tag.footer(class: "actions", data: { reverse: ("" if reverse) }) do
|
35
|
+
concat(tag.button(submit, form: form_id, class: "button", data: { close_dialog: "" }))
|
36
|
+
if discard.present?
|
37
|
+
concat(tag.button(discard, form: form_id, formmethod: "dialog", class: "button", data: { ghost_button: "" }))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
using Katalyst::HtmlAttributes::HasHtmlAttributes
|
45
|
+
|
46
|
+
def _koi_modal_frame_attributes(attributes)
|
47
|
+
{
|
48
|
+
data: { controller: "koi--modal" },
|
49
|
+
}.merge_html(attributes)
|
50
|
+
end
|
51
|
+
|
52
|
+
def _koi_modal_dialog_attributes(attributes)
|
53
|
+
{
|
54
|
+
class: "modal",
|
55
|
+
data: {
|
56
|
+
koi__modal_target: "dialog",
|
57
|
+
action: %w[
|
58
|
+
click->koi--modal#click
|
59
|
+
close->koi--modal#dismiss
|
60
|
+
],
|
61
|
+
},
|
62
|
+
}.merge_html(attributes)
|
63
|
+
end
|
64
|
+
|
65
|
+
def _koi_modal_article_attributes(attributes)
|
66
|
+
{
|
67
|
+
class: "flow",
|
68
|
+
}.merge_html(attributes)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/app/models/admin/user.rb
CHANGED
@@ -6,9 +6,11 @@ module Admin
|
|
6
6
|
include Koi::Model::OTP
|
7
7
|
|
8
8
|
def self.model_name
|
9
|
-
ActiveModel::Name.new(self, nil, "
|
9
|
+
ActiveModel::Name.new(self, nil, "AdminUser")
|
10
10
|
end
|
11
11
|
|
12
|
+
self.table_name = :admins
|
13
|
+
|
12
14
|
# disable validations for password_digest
|
13
15
|
has_secure_password validations: false
|
14
16
|
|
@@ -51,5 +53,9 @@ module Admin
|
|
51
53
|
credentials.any?
|
52
54
|
end
|
53
55
|
alias passkey? passkey
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
name
|
59
|
+
end
|
54
60
|
end
|
55
61
|
end
|
data/app/models/url_rewrite.rb
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class UrlRewrite < ApplicationRecord
|
4
|
-
|
5
|
-
|
6
|
-
STATUS_CODES = [
|
7
|
-
StatusCode.new(303, "See other"),
|
8
|
-
StatusCode.new(307, "Temporary redirect"),
|
9
|
-
StatusCode.new(308, "Permanent redirect"),
|
10
|
-
].freeze
|
11
|
-
|
12
|
-
enum :status_code, STATUS_CODES.map(&:code).index_by(&:itself)
|
4
|
+
enum :status_code, [303, 307, 308].index_by(&:itself)
|
13
5
|
|
14
6
|
attribute :status_code, :integer, default: 303
|
15
7
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<%= form_with(model: admin_user) do |form| %>
|
4
|
+
<%= form.govuk_text_field :email %>
|
5
|
+
<%= form.govuk_text_field :name %>
|
6
|
+
<%= form.govuk_password_field :password, label: { text: "Password (optional)" } %>
|
7
|
+
<%= form.button(type: :submit, class: "button") %>
|
8
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<%= form_with(model: admin_user) do |form| %>
|
4
|
+
<%= form.govuk_text_field :email %>
|
5
|
+
<%= form.govuk_text_field :name %>
|
6
|
+
<%= form.govuk_check_box_field :archived if form.object.persisted? %>
|
7
|
+
<%= form.button(type: :submit, class: "button") %>
|
8
|
+
<% end %>
|
@@ -1,13 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
<%# locals: (collection:) %>
|
2
|
+
|
3
|
+
<% content_for(:header) do %>
|
4
|
+
<%= breadcrumb_list do %>
|
5
|
+
<li><%= link_to("Admin users", admin_admin_users_path) %></li>
|
4
6
|
<% end %>
|
7
|
+
<h1>Archived admin users</h1>
|
5
8
|
<% end %>
|
6
9
|
|
7
10
|
<%= table_query_with(collection:) %>
|
8
11
|
|
9
12
|
<%= table_selection_with(collection:) do %>
|
10
|
-
<%= tag.button
|
13
|
+
<%= tag.button("Restore", formaction: restore_admin_admin_users_path, formmethod: :put, class: "button") %>
|
11
14
|
<% end %>
|
12
15
|
|
13
16
|
<%= table_with(collection:) do |row| %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<% content_for(:header) do %>
|
4
|
+
<%= breadcrumb_list do %>
|
5
|
+
<li><%= link_to("Admin users", admin_admin_users_path) %></li>
|
6
|
+
<li><%= link_to(admin_user, admin_admin_user_path(admin_user)) %></li>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<h1>Edit profile</h1>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<%= render("form", admin_user:) %>
|
@@ -1,11 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
<%
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<% content_for(:header) do %>
|
4
|
+
<%= breadcrumb_list do %>
|
5
|
+
<li><%= link_to("Admin users", admin_admin_users_path) %></li>
|
6
|
+
<li><%= link_to(admin_user, admin_admin_user_path(admin_user)) %></li>
|
7
|
+
<% end %>
|
4
8
|
|
5
|
-
|
6
|
-
<%= render "fields", form: %>
|
9
|
+
<h1>Edit admin user</h1>
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
+
<%= actions_list do %>
|
12
|
+
<li><%= link_to_archive_or_delete(admin_user) %></li>
|
13
|
+
<% end %>
|
11
14
|
<% end %>
|
15
|
+
|
16
|
+
<%= render("form", admin_user:) %>
|
@@ -1,14 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
<%# locals: (collection:) %>
|
2
|
+
|
3
|
+
<% content_for(:header) do %>
|
4
|
+
<h1>Admin users</h1>
|
5
|
+
|
6
|
+
<%= actions_list do %>
|
7
|
+
<li><%= link_to("New", new_admin_admin_user_path) %></li>
|
8
|
+
<li><%= link_to("Archived", archived_admin_admin_users_path) %></li>
|
5
9
|
<% end %>
|
6
10
|
<% end %>
|
7
11
|
|
8
12
|
<%= table_query_with(collection:) %>
|
9
13
|
|
10
14
|
<%= table_selection_with(collection:) do %>
|
11
|
-
<%= tag.button
|
15
|
+
<%= tag.button("Archive", formaction: archive_admin_admin_users_path, formmethod: :put, class: "button") %>
|
12
16
|
<% end %>
|
13
17
|
|
14
18
|
<%= table_with(collection:) do |row| %>
|
@@ -21,6 +25,7 @@
|
|
21
25
|
<% row.boolean :otp, label: "MFA" do |cell| %>
|
22
26
|
<%= cell.value.present? ? "Yes" : "No" %>
|
23
27
|
<% end %>
|
28
|
+
<% row.date :last_sign_in_at, label: "Last active" %>
|
24
29
|
<% end %>
|
25
30
|
|
26
31
|
<%= table_pagination_with(collection:) %>
|
@@ -1,11 +1,11 @@
|
|
1
|
-
|
2
|
-
<%= render Koi::Header::NewComponent.new(model: Admin::User) %>
|
3
|
-
<% end %>
|
1
|
+
<%# locals: (admin_user:) %>
|
4
2
|
|
5
|
-
|
6
|
-
<%=
|
3
|
+
<% content_for(:header) do %>
|
4
|
+
<%= breadcrumb_list do %>
|
5
|
+
<li><%= link_to("Admin users", admin_admin_users_path) %></li>
|
6
|
+
<% end %>
|
7
7
|
|
8
|
-
<
|
9
|
-
<%= form.admin_save %>
|
10
|
-
</div>
|
8
|
+
<h1>New admin user</h1>
|
11
9
|
<% end %>
|
10
|
+
|
11
|
+
<%= render("form", admin_user:) %>
|
@@ -1,25 +1,34 @@
|
|
1
|
-
<%# locals: (
|
1
|
+
<%# locals: (admin_user:) %>
|
2
2
|
|
3
|
-
<% content_for
|
4
|
-
<%=
|
3
|
+
<% content_for(:header) do %>
|
4
|
+
<%= breadcrumb_list do %>
|
5
|
+
<li><%= link_to("Admin users", admin_admin_users_path) %></li>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<h1><%= admin_user %></h1>
|
9
|
+
|
10
|
+
<%= actions_list do %>
|
11
|
+
<li><%= link_to("Edit", edit_admin_admin_user_path(admin_user)) %></li>
|
12
|
+
<% end %>
|
5
13
|
<% end %>
|
6
14
|
|
7
|
-
<%=
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
<%= summary_table_with(model: admin_user) do |row| %>
|
16
|
+
<% row.text :name %>
|
17
|
+
<% row.text :email %>
|
18
|
+
<% row.date :created_at %>
|
19
|
+
<% row.date(:last_sign_in_at, label: "Last access") %>
|
20
|
+
<% row.boolean :passkey %>
|
21
|
+
<% row.boolean(:otp, label: "MFA") do |otp| %>
|
14
22
|
<span class="repel">
|
15
23
|
<%= otp %>
|
16
24
|
<% if otp.value %>
|
17
|
-
<%= button_to("Remove", admin_admin_user_otp_path(
|
25
|
+
<%= button_to("Remove", admin_admin_user_otp_path(admin_user),
|
18
26
|
class: "button button--text",
|
19
27
|
method: :delete,
|
20
28
|
form: { data: { turbo_confirm: "Are you sure?" } }) %>
|
21
29
|
<% else %>
|
22
|
-
<%=
|
30
|
+
<%= link_to("Add", new_admin_admin_user_otp_path(admin_user),
|
31
|
+
class: "button", data: { turbo_frame: "edit" }) %>
|
23
32
|
<% end %>
|
24
33
|
</span>
|
25
34
|
<% end %>
|
@@ -27,7 +36,10 @@
|
|
27
36
|
|
28
37
|
<div class="repel">
|
29
38
|
<h3>Passkeys</h3>
|
30
|
-
<%=
|
39
|
+
<%= link_to("New passkey", new_admin_admin_user_credential_path(admin_user),
|
40
|
+
class: "button", data: { turbo_frame: "edit" }) %>
|
31
41
|
</div>
|
32
42
|
|
33
|
-
<%= render "admin/credentials/credentials",
|
43
|
+
<%= render "admin/credentials/credentials", admin_user: %>
|
44
|
+
|
45
|
+
<%= koi_modal_tag("edit") %>
|
@@ -1,25 +1,27 @@
|
|
1
|
-
<%# locals: (
|
1
|
+
<%# locals: (admin_user:) %>
|
2
2
|
|
3
|
-
<% content_for
|
4
|
-
<%=
|
3
|
+
<% content_for(:header) do %>
|
4
|
+
<%= breadcrumb_list do %>
|
5
|
+
<li><%= link_to("Admin users", admin_admin_users_path) %></li>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<h1><%= admin_user %></h1>
|
9
|
+
|
10
|
+
<%= actions_list do %>
|
11
|
+
<li><%= link_to("Edit", edit_admin_admin_user_path(admin_user)) %></li>
|
12
|
+
<% end %>
|
5
13
|
<% end %>
|
6
14
|
|
7
|
-
<%=
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
+
<%= summary_table_with(model: admin_user) do |row| %>
|
16
|
+
<% row.text :name %>
|
17
|
+
<% row.text :email %>
|
18
|
+
<% row.date :created_at %>
|
19
|
+
<% row.date :last_sign_in_at, label: "Last access" %>
|
20
|
+
<% row.boolean :passkey %>
|
21
|
+
<% row.boolean :otp, label: "MFA" %>
|
22
|
+
<% row.boolean :archived? %>
|
15
23
|
<% end %>
|
16
24
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
class: "button button--secondary",
|
21
|
-
method: :delete,
|
22
|
-
form: { data: { turbo_confirm: "Are you sure?" } } %>
|
23
|
-
<% end %>
|
24
|
-
<%= button_to "Generate login link", admin_admin_user_tokens_path(admin), class: "button button--primary", form: { id: "invite" } %>
|
25
|
-
</div>
|
25
|
+
<% unless admin_user.archived? %>
|
26
|
+
<%= button_to "Generate login link", admin_admin_user_tokens_path(admin_user), class: "button", form: { id: "invite" } %>
|
27
|
+
<% end %>
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<%= table_with(id: dom_id(admin_user, :credentials), collection: admin_user.credentials) do |table, credential| %>
|
4
|
+
<% table.text :nickname, label: "Name" %>
|
5
|
+
<% table.date :updated_at, label: "Last use" do |date| %>
|
6
|
+
<%= date unless credential.created_at == credential.updated_at %>
|
5
7
|
<% end %>
|
6
|
-
<%
|
7
|
-
<%= link_to("Remove passkey", admin_admin_user_credential_path(
|
8
|
+
<% table.cell :actions, label: "" do %>
|
9
|
+
<%= link_to("Remove passkey", admin_admin_user_credential_path(admin_user, credential),
|
8
10
|
data: { turbo_method: :delete }) %>
|
9
11
|
<% end %>
|
10
12
|
<% end %>
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<%= table_with(id: dom_id(admin_user, :credentials), collection: admin_user.credentials) do |t, c| %>
|
2
4
|
<% t.text :nickname, label: "Name" %>
|
3
5
|
<% t.date :updated_at, label: "Last use" do |date| %>
|
4
6
|
<%= date unless c.created_at == c.updated_at %>
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<%= turbo_stream.replace(dom_id(admin_user, :credentials)) do %>
|
4
|
+
<%= render "admin/credentials/credentials", admin_user: %>
|
4
5
|
<% end %>
|
@@ -1,3 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
<%# locals: (admin_user:) %>
|
2
|
+
|
3
|
+
<%= turbo_stream.replace(dom_id(admin_user, :credentials)) do %>
|
4
|
+
<%= render "admin/credentials/credentials", admin_user: %>
|
3
5
|
<% end %>
|
@@ -1,37 +1,43 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
<
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
1
|
+
<%# locals: (admin_user:, credential:, options:) %>
|
2
|
+
|
3
|
+
<%= koi_modal_tag("edit", title: "New passkey") do %>
|
4
|
+
<%= koi_modal_header(title: "New passkey", form_id: dom_id(credential, :form)) %>
|
5
|
+
<main>
|
6
|
+
<%= form_with(model: credential,
|
7
|
+
url: admin_admin_user_credentials_path(admin_user),
|
8
|
+
id: dom_id(credential, :form),
|
9
|
+
class: "flow prose",
|
10
|
+
data: {
|
11
|
+
controller: "webauthn-registration",
|
12
|
+
action: "submit->webauthn-registration#submit",
|
13
|
+
webauthn_registration_options_value: { publicKey: options },
|
14
|
+
}) do |form| %>
|
15
|
+
<%= form.hidden_field :response, data: { webauthn_registration_target: "response" } %>
|
16
|
+
<section class="flow prose" data-webauthn-registration-target="intro">
|
17
|
+
<p>
|
18
|
+
Passkeys are secure secrets that are stored by your device.
|
19
|
+
You will need the device where your passkey is stored to log in.
|
20
|
+
</p>
|
21
|
+
<p>
|
22
|
+
Unlike a password, your password doesn't get sent to the server when you log
|
23
|
+
in and can't be stolen in a data breach. When you log in with a passkey,
|
24
|
+
your operating system will prompt you for permission to use the passkey
|
25
|
+
secret to authenticate the login attempt.
|
26
|
+
</p>
|
27
|
+
<p>
|
28
|
+
We recommend that you store your passkey on your phone or cloud account.
|
29
|
+
Depending on your browser, you may need to choose "more options" to see
|
30
|
+
a QR code that you can scan with your phone.
|
31
|
+
</p>
|
32
|
+
</section>
|
33
|
+
<section class="flow" data-webauthn-registration-target="nickname" hidden>
|
34
|
+
<%= form.govuk_text_field :nickname, label: { text: "Passkey name" } do %>
|
35
|
+
Enter a name for this passkey to help you distinguish it from other passkeys you may have for this site.
|
36
|
+
<br>
|
37
|
+
Example: My Phone, Chrome, iCloud, 1Password
|
38
|
+
<% end %>
|
39
|
+
</section>
|
40
|
+
<% end %>
|
41
|
+
</main>
|
42
|
+
<%= koi_modal_footer("Next", nil, form_id: dom_id(credential, :form)) %>
|
37
43
|
<% end %>
|
@@ -1 +1,13 @@
|
|
1
|
-
<% content_for :
|
1
|
+
<% content_for :header do %>
|
2
|
+
<h1>Dashboard</h1>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<%= navigation_menu_with(
|
6
|
+
menu: Koi::Menu.dashboard_menu,
|
7
|
+
list: {
|
8
|
+
class: "navigation-list | flow",
|
9
|
+
role: "list",
|
10
|
+
},
|
11
|
+
class: "navigation-group | flow",
|
12
|
+
role: "list",
|
13
|
+
) %>
|
@@ -1,8 +1,8 @@
|
|
1
|
-
<%# locals: (
|
1
|
+
<%# locals: (admin_user:) %>
|
2
2
|
|
3
|
-
<%= form_with(id: dom_id(
|
4
|
-
model:
|
5
|
-
url: admin_admin_user_otp_path(
|
3
|
+
<%= form_with(id: dom_id(admin_user, :otp),
|
4
|
+
model: admin_user,
|
5
|
+
url: admin_admin_user_otp_path(admin_user),
|
6
6
|
method: :post,
|
7
7
|
class: "flow") do |form| %>
|
8
8
|
<section class="flow prose">
|
@@ -15,11 +15,12 @@
|
|
15
15
|
<ol class="flow">
|
16
16
|
<li>Install an MFA app. Most password managers support MFA.</li>
|
17
17
|
<li>Scan this code using your mobile device or password manager:<br>
|
18
|
-
<% otp_app_name = t("koi.auth.otp_app_name", host: URI.parse(root_url).host, email:
|
19
|
-
<%== RQRCode::QRCode.new(
|
18
|
+
<% otp_app_name = t("koi.auth.otp_app_name", host: URI.parse(root_url).host, email: admin_user.email) %>
|
19
|
+
<%== RQRCode::QRCode.new(admin_user.otp.provisioning_uri(otp_app_name)).as_svg(
|
20
20
|
color: "000",
|
21
21
|
shape_rendering: "crispEdges",
|
22
22
|
module_size: 3,
|
23
|
+
svg_attributes: { class: "qrcode" },
|
23
24
|
use_path: true,
|
24
25
|
) %>
|
25
26
|
</li>
|
@@ -28,5 +29,4 @@
|
|
28
29
|
</section>
|
29
30
|
<%= form.hidden_field :otp_secret %>
|
30
31
|
<%= form.govuk_text_field :token %>
|
31
|
-
<%= form.admin_save %>
|
32
32
|
<% end %>
|
@@ -1,5 +1,7 @@
|
|
1
|
-
<%# locals: (
|
1
|
+
<%# locals: (admin_user:) %>
|
2
2
|
|
3
|
-
<%=
|
4
|
-
<%=
|
3
|
+
<%= koi_modal_tag("edit") do %>
|
4
|
+
<%= koi_modal_header(title: "Configure MFA", form_id: dom_id(admin_user, :otp)) %>
|
5
|
+
<%= tag.main(render("form", admin_user:)) %>
|
6
|
+
<%= koi_modal_footer(form_id: dom_id(admin_user, :otp)) %>
|
5
7
|
<% end %>
|
@@ -1,9 +1,8 @@
|
|
1
1
|
<%# locals: (admin_user:) %>
|
2
2
|
|
3
|
-
<%= render "layouts/koi/navigation_header" %>
|
4
|
-
|
5
3
|
<%= form_with(
|
6
4
|
model: admin_user,
|
5
|
+
scope: :admin,
|
7
6
|
url: admin_session_path,
|
8
7
|
data: {
|
9
8
|
controller: "webauthn-authentication",
|
@@ -24,7 +23,7 @@
|
|
24
23
|
<%= form.govuk_email_field :email, autofocus: true, autocomplete: "off" %>
|
25
24
|
<%= form.hidden_field :response, data: { webauthn_authentication_target: "response" } %>
|
26
25
|
<%= hidden_field_tag(:redirect, redirect) %>
|
27
|
-
<div class="actions
|
26
|
+
<div class="actions">
|
28
27
|
<%= form.admin_save "Next" %>
|
29
28
|
<%= form.button "🔑", type: :button, class: "button button--secondary", data: { action: "webauthn-authentication#authenticate" } %>
|
30
29
|
</div>
|
@@ -1,8 +1,6 @@
|
|
1
1
|
<%# locals: (admin_user:) %>
|
2
2
|
|
3
|
-
<%=
|
4
|
-
|
5
|
-
<%= form_with(model: admin_user, url: admin_session_path, method: :post) do |form| %>
|
3
|
+
<%= form_with(model: admin_user, scope: :admin, url: admin_session_path, method: :post) do |form| %>
|
6
4
|
<%# note, autocomplete off is ignored by browsers but required by PCI-DSS %>
|
7
5
|
<%= form.govuk_text_field :token, autofocus: true, autocomplete: "off" %>
|
8
6
|
<%= hidden_field_tag(:redirect, params[:redirect]) %>
|
@@ -1,8 +1,6 @@
|
|
1
1
|
<%# locals: (admin_user:) %>
|
2
2
|
|
3
|
-
<%=
|
4
|
-
|
5
|
-
<%= form_with(model: admin_user, url: admin_session_path) do |form| %>
|
3
|
+
<%= form_with(model: admin_user, scope: :admin, url: admin_session_path) do |form| %>
|
6
4
|
<%= form.hidden_field(:email) %>
|
7
5
|
<%# note, autocomplete off is ignored by browsers but required by PCI-DSS %>
|
8
6
|
<%= form.govuk_password_field :password, autofocus: true, autocomplete: "off" %>
|
@@ -1,14 +1,12 @@
|
|
1
1
|
<%# locals: (admin_user:, token:) %>
|
2
2
|
|
3
|
-
<%= render "layouts/koi/navigation_header" %>
|
4
|
-
|
5
3
|
<%= form_with(url: admin_session_token_path(token), method: :patch) do |form| %>
|
6
4
|
<p>Welcome to Koi Admin</p>
|
7
|
-
<%=
|
8
|
-
<%=
|
9
|
-
<%=
|
5
|
+
<%= summary_table_with(model: admin_user) do |row| %>
|
6
|
+
<%= row.text :name %>
|
7
|
+
<%= row.text :email %>
|
10
8
|
<% end %>
|
11
|
-
<div class="actions
|
9
|
+
<div class="actions">
|
12
10
|
<%= form.admin_save "Sign in" %>
|
13
11
|
</div>
|
14
12
|
<% end %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<%# locals: (url_rewrite:) %>
|
2
|
+
|
3
|
+
<%= form_with(model: url_rewrite) do |form| %>
|
4
|
+
<%= form.govuk_text_field(:from, hint: { text: "Should begin with /" }) %>
|
5
|
+
<%= form.govuk_text_field :to %>
|
6
|
+
<%= form.govuk_check_box_field :active %>
|
7
|
+
<%= form.govuk_enum_select :status_code %>
|
8
|
+
<%= form.button(type: :submit, class: "button") %>
|
9
|
+
<% end %>
|