fluxbit_view_components 0.3.0 → 0.4.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 +10 -0
- data/app/assets/javascripts/fluxbit_view_components/assigner_controller.js +49 -0
- data/app/assets/javascripts/fluxbit_view_components/auto_submit_controller.js +39 -0
- data/app/assets/javascripts/fluxbit_view_components/drawer_controller.js +135 -0
- data/app/assets/javascripts/fluxbit_view_components/index.js +56 -0
- data/app/assets/javascripts/fluxbit_view_components/method_link_controller.js +143 -0
- data/app/assets/javascripts/fluxbit_view_components/modal_controller.js +118 -0
- data/app/assets/javascripts/fluxbit_view_components/password_controller.js +170 -0
- data/app/assets/javascripts/fluxbit_view_components/progress_controller.js +374 -0
- data/app/assets/javascripts/fluxbit_view_components/row_click_controller.js +32 -0
- data/app/assets/javascripts/fluxbit_view_components/select_all_controller.js +122 -0
- data/app/assets/javascripts/fluxbit_view_components/spinner_percent_controller.js +174 -0
- data/app/assets/javascripts/fluxbit_view_components/theme_button_controller.js +90 -0
- data/app/assets/javascripts/fluxbit_view_components.js +1175 -0
- data/app/components/fluxbit/accordion_component.rb +125 -0
- data/app/components/fluxbit/alert_component.rb +8 -8
- data/app/components/fluxbit/avatar_component.rb +11 -12
- data/app/components/fluxbit/avatar_group_component.rb +1 -1
- data/app/components/fluxbit/badge_component.rb +8 -7
- data/app/components/fluxbit/banner_component.rb +139 -0
- data/app/components/fluxbit/bottom_navigation_component.rb +437 -0
- data/app/components/fluxbit/breadcrumb_component.rb +66 -0
- data/app/components/fluxbit/button_component.rb +39 -11
- data/app/components/fluxbit/button_group_component.rb +1 -1
- data/app/components/fluxbit/card_component.rb +26 -23
- data/app/components/fluxbit/carousel_component.rb +154 -0
- data/app/components/fluxbit/component.rb +24 -3
- data/app/components/fluxbit/drawer_component.html.erb +30 -0
- data/app/components/fluxbit/drawer_component.rb +125 -0
- data/app/components/fluxbit/dropdown_component.rb +41 -0
- data/app/components/fluxbit/dropdown_item_component.rb +68 -0
- data/app/components/fluxbit/flex_component.rb +1 -1
- data/app/components/fluxbit/form/component.rb +15 -8
- data/app/components/fluxbit/form/dropzone_component.rb +3 -3
- data/app/components/fluxbit/form/field_component.rb +4 -2
- data/app/components/fluxbit/form/help_text_component.rb +1 -1
- data/app/components/fluxbit/form/label_component.rb +10 -3
- data/app/components/fluxbit/form/password_component.rb +247 -0
- data/app/components/fluxbit/form/radio_group_button_component.rb +126 -0
- data/app/components/fluxbit/form/select_component.rb +108 -11
- data/app/components/fluxbit/form/text_field_component.rb +40 -23
- data/app/components/fluxbit/form/toggle_component.rb +2 -2
- data/app/components/fluxbit/form/upload_image_component.html.erb +3 -3
- data/app/components/fluxbit/form/upload_image_component.rb +12 -1
- data/app/components/fluxbit/gravatar_component.rb +7 -0
- data/app/components/fluxbit/icon_helpers.rb +167 -0
- data/app/components/fluxbit/link_component.rb +42 -0
- data/app/components/fluxbit/modal_component.rb +28 -31
- data/app/components/fluxbit/pagination_component.rb +206 -0
- data/app/components/fluxbit/popover_component.rb +14 -14
- data/app/components/fluxbit/progress_component.rb +196 -0
- data/app/components/fluxbit/skeleton_component.rb +237 -0
- data/app/components/fluxbit/speed_dial_action_component.html.erb +30 -0
- data/app/components/fluxbit/speed_dial_action_component.rb +59 -0
- data/app/components/fluxbit/speed_dial_component.html.erb +33 -0
- data/app/components/fluxbit/speed_dial_component.rb +73 -0
- data/app/components/fluxbit/spinner_component.rb +71 -0
- data/app/components/fluxbit/spinner_percent_component.rb +174 -0
- data/app/components/fluxbit/stepper_component.rb +223 -0
- data/app/components/fluxbit/tab_component.rb +44 -25
- data/app/components/fluxbit/table_component.rb +186 -0
- data/app/components/fluxbit/table_group_component.rb +28 -0
- data/app/components/fluxbit/theme_button_component.rb +64 -0
- data/app/components/fluxbit/timeline_component.rb +63 -0
- data/app/components/fluxbit/timeline_item_component.html.erb +64 -0
- data/app/components/fluxbit/timeline_item_component.rb +78 -0
- data/app/components/fluxbit/tooltip_component.rb +2 -2
- data/app/helpers/fluxbit/components_helper.rb +74 -4
- data/app/helpers/fluxbit/form_builder.rb +64 -15
- data/app/helpers/fluxbit/view_helper.rb +71 -0
- data/config/locales/en.yml +37 -4
- data/config/locales/pt-BR.yml +36 -0
- data/lib/fluxbit/config/accordion_component.rb +73 -0
- data/lib/fluxbit/config/avatar_component.rb +11 -11
- data/lib/fluxbit/config/badge_component.rb +14 -11
- data/lib/fluxbit/config/banner_component.rb +60 -0
- data/lib/fluxbit/config/bottom_navigation_component.rb +74 -0
- data/lib/fluxbit/config/breadcrumb_component.rb +24 -0
- data/lib/fluxbit/config/button_component.rb +6 -4
- data/lib/fluxbit/config/card_component.rb +23 -12
- data/lib/fluxbit/config/carousel_component.rb +33 -0
- data/lib/fluxbit/config/drawer_component.rb +48 -0
- data/lib/fluxbit/config/dropdown_component.rb +29 -0
- data/lib/fluxbit/config/form/check_box_component.rb +1 -1
- data/lib/fluxbit/config/form/dropzone_component.rb +1 -1
- data/lib/fluxbit/config/form/help_text_component.rb +1 -1
- data/lib/fluxbit/config/form/label_component.rb +3 -2
- data/lib/fluxbit/config/form/password_component.rb +19 -0
- data/lib/fluxbit/config/form/radio_group_button_component.rb +24 -0
- data/lib/fluxbit/config/form/text_field_component.rb +11 -11
- data/lib/fluxbit/config/form/toggle_component.rb +5 -5
- data/lib/fluxbit/config/link_component.rb +24 -0
- data/lib/fluxbit/config/modal_component.rb +1 -1
- data/lib/fluxbit/config/pagination_component.rb +31 -0
- data/lib/fluxbit/config/popover_component.rb +1 -1
- data/lib/fluxbit/config/progress_component.rb +63 -0
- data/lib/fluxbit/config/skeleton_component.rb +82 -0
- data/lib/fluxbit/config/speed_dial_component.rb +50 -0
- data/lib/fluxbit/config/spinner_component.rb +30 -0
- data/lib/fluxbit/config/spinner_percent_component.rb +61 -0
- data/lib/fluxbit/config/stepper_component.rb +299 -0
- data/lib/fluxbit/config/tab_component.rb +6 -0
- data/lib/fluxbit/config/table_component.rb +75 -0
- data/lib/fluxbit/config/theme_button_component.rb +19 -0
- data/lib/fluxbit/config/timeline_component.rb +77 -0
- data/lib/fluxbit/view_components/engine.rb +11 -3
- data/lib/fluxbit/view_components/version.rb +1 -1
- data/lib/fluxbit/view_components.rb +20 -0
- data/lib/generators/fluxbit/devise_views_generator.rb +116 -0
- data/lib/generators/fluxbit/pagy_generator.rb +39 -0
- data/lib/generators/fluxbit/scaffold_generator.rb +165 -0
- data/lib/generators/fluxbit/templates/_alert.html.erb.tt +1 -0
- data/lib/generators/fluxbit/templates/_flash.html.erb.tt +15 -0
- data/lib/generators/fluxbit/templates/_form.html.erb.tt +38 -0
- data/lib/generators/fluxbit/templates/_metadata.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/controller.rb.tt +406 -0
- data/lib/generators/fluxbit/templates/create.turbo_stream.erb.tt +7 -0
- data/lib/generators/fluxbit/templates/destroy.turbo_stream.erb.tt +3 -0
- data/lib/generators/fluxbit/templates/destroy_all.turbo_stream.erb.tt +9 -0
- data/lib/generators/fluxbit/templates/devise_views/confirmations/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/layouts/devise.html.erb +64 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/confirmation_instructions.html.erb +5 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/email_changed.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/password_changed.html.erb +3 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/reset_password_instructions.html.erb +8 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/unlock_instructions.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/edit.html.erb +29 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/edit.html.erb +43 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/new.html.erb +34 -0
- data/lib/generators/fluxbit/templates/devise_views/sessions/new.html.erb +15 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_error_messages.html.erb +14 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_links.html.erb +25 -0
- data/lib/generators/fluxbit/templates/devise_views/unlocks/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/edit.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/fluxbit_pagy.css +27 -0
- data/lib/generators/fluxbit/templates/i18n.en.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/i18n.pt-BR.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/index.html.erb.tt +254 -0
- data/lib/generators/fluxbit/templates/index.json.jbuilder.tt +33 -0
- data/lib/generators/fluxbit/templates/new.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/partial.html.erb.tt +61 -0
- data/lib/generators/fluxbit/templates/policy.rb.tt +36 -0
- data/lib/generators/fluxbit/templates/send_alert_via_drawer.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/show.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/show.json.jbuilder.tt +6 -0
- data/lib/generators/fluxbit/templates/update.turbo_stream.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/update_all.turbo_stream.erb.tt +20 -0
- data/lib/install/install.rb +58 -0
- metadata +107 -18
- data/app/helpers/fluxbit/classes_helper.rb +0 -9
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<% singular = file_name.singularize; plural = file_name.pluralize -%>
|
|
2
|
+
<%% if <%= singular %>.persisted? %>
|
|
3
|
+
<%%= fx_flex(vertical: false, gap: 1, class: "mt-4") do %>
|
|
4
|
+
<%%= fx_flex(align_items: :center, justify_content: :center, class: "bg-blue-500 dark:bg-blue-700 size-6 rounded-full") do %>
|
|
5
|
+
<%%= anyicon("heroicons_solid:plus", class: "size-4 text-white justify-center") %>
|
|
6
|
+
<%% end %>
|
|
7
|
+
<%%= fx_flex(vertical: true) do %>
|
|
8
|
+
<p class="text-sm font-medium text-gray-900 dark:text-white"><%%= t("<%= plural %>.fields.created_at") %></p>
|
|
9
|
+
<p class="text-sm text-gray-500">
|
|
10
|
+
<%%= <%= singular %>.created_at.strftime("%A, %B %d, %Y at %I:%M %p") %>
|
|
11
|
+
</p>
|
|
12
|
+
<p class="text-xs text-gray-400">
|
|
13
|
+
<%%= time_ago_in_words(<%= singular %>.created_at) %>
|
|
14
|
+
</p>
|
|
15
|
+
<%% end %>
|
|
16
|
+
<%% end %>
|
|
17
|
+
|
|
18
|
+
<%%= fx_flex(vertical: false, gap: 1, class: "mt-4") do %>
|
|
19
|
+
<%%= fx_flex(align_items: :center, justify_content: :center, class: "bg-green-500 dark:bg-green-700 size-6 rounded-full") do %>
|
|
20
|
+
<%%= anyicon("heroicons_solid:pencil", class: "size-4 text-white justify-center") %>
|
|
21
|
+
<%% end %>
|
|
22
|
+
<%%= fx_flex(vertical: true) do %>
|
|
23
|
+
<p class="text-sm font-medium text-gray-900 dark:text-white"><%%= t("<%= plural %>.fields.updated_at") %></p>
|
|
24
|
+
<p class="text-sm text-gray-500">
|
|
25
|
+
<%%= <%= singular %>.updated_at.strftime("%A, %B %d, %Y at %I:%M %p") %>
|
|
26
|
+
</p>
|
|
27
|
+
<p class="text-xs text-gray-400">
|
|
28
|
+
<%%= time_ago_in_words(<%= singular %>.updated_at) %>
|
|
29
|
+
</p>
|
|
30
|
+
<%% end %>
|
|
31
|
+
<%% end %>
|
|
32
|
+
|
|
33
|
+
<%%= fx_flex(vertical: false, gap: 1, class: "mt-4") do %>
|
|
34
|
+
<%%= fx_flex(align_items: :center, justify_content: :center, class: "bg-gray-500 dark:bg-gray-700 size-6 rounded-full") do %>
|
|
35
|
+
<%%= anyicon("heroicons_solid:finger-print", class: "size-4 text-white justify-center") %>
|
|
36
|
+
<%% end %>
|
|
37
|
+
<%%= fx_flex(vertical: true) do %>
|
|
38
|
+
<p class="text-sm font-medium text-gray-900 dark:text-white"><%%= t("<%= plural %>.fields.id") %></p>
|
|
39
|
+
<p class="text-sm text-gray-500">
|
|
40
|
+
<%%= <%= singular %>.id %>
|
|
41
|
+
</p>
|
|
42
|
+
<%% end %>
|
|
43
|
+
<%% end %>
|
|
44
|
+
<%% end %>
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
<% singular = file_name.singularize; plural = file_name.pluralize -%>
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
class <%= namespaced? ? "#{namespace_module}::" : "" %><%= class_name.pluralize %>Controller < ApplicationController
|
|
5
|
+
include Pundit::Authorization
|
|
6
|
+
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
|
7
|
+
|
|
8
|
+
before_action :set_<%= singular %>, only: %i[ show edit update destroy ]
|
|
9
|
+
before_action :set_<%= plural %>_for_bulk_actions, only: %i[ update_all destroy_all ]
|
|
10
|
+
<% if options[:pundit] %>
|
|
11
|
+
after_action :verify_authorized, except: :index
|
|
12
|
+
after_action :verify_policy_scoped, only: :index
|
|
13
|
+
<% end %>
|
|
14
|
+
|
|
15
|
+
# GET /<%= "#{namespace_path}/" %><%= plural %>
|
|
16
|
+
def index
|
|
17
|
+
<% if options[:paginator] -%>
|
|
18
|
+
@page_size = 10
|
|
19
|
+
Pagy::DEFAULT[:limit] = (params[:per_page].presence || @page_size).to_i
|
|
20
|
+
<% end -%>
|
|
21
|
+
@<%= plural %> = policy_scope(<%= class_name.singularize %>).all
|
|
22
|
+
|
|
23
|
+
# Search and filter logic
|
|
24
|
+
@q = params[:q]
|
|
25
|
+
@<%= plural %> = @<%= plural %>.where("name LIKE ?", "%#{@q}%") if @q.present?
|
|
26
|
+
<% attributes.first(5).each do |att|
|
|
27
|
+
name, type = att.name, att.type.to_s
|
|
28
|
+
next if type == 'password_digest' # handle password fields separately
|
|
29
|
+
-%>
|
|
30
|
+
<% if ['integer','decimal'].include?(type) -%>
|
|
31
|
+
@<%= name %> = params[:<%= name %>]
|
|
32
|
+
@<%= plural %> = @<%= plural %>.where("<%= name %> >= ?", @<%= name %>) if @<%= name %>.present?
|
|
33
|
+
<% elsif ['text', 'string'].include?(type) -%>
|
|
34
|
+
@<%= name %> = params[:<%= name %>]
|
|
35
|
+
@<%= plural %> = @<%= plural %>.where("<%= name %> LIKE ?", "%#{@<%= name %>}") if @<%= name %>.present?
|
|
36
|
+
<% end -%>
|
|
37
|
+
<% end -%>
|
|
38
|
+
@has_filters = [<%= attributes.reject { |a|
|
|
39
|
+
a.type.to_s == "password_digest" }.map { |a| "@#{a.name}" }.join(', ') %>, @q].compact_blank.any?
|
|
40
|
+
|
|
41
|
+
# Sort logic
|
|
42
|
+
if params[:order].present?
|
|
43
|
+
order = params[:order].rpartition("_")
|
|
44
|
+
order_options = %w[<%= attributes.map(&:name).join(" ") %> created_at updated_at]
|
|
45
|
+
if order.length == 3 && %w[asc desc].include?(order.last) && order_options.include?(order.first)
|
|
46
|
+
@<%= plural %> = @<%= plural %>.order(order.first.to_sym => order.last.to_sym)
|
|
47
|
+
else
|
|
48
|
+
flash[:error] = t("<%= plural %>.messages.order_error")
|
|
49
|
+
@<%= plural %> = @<%= plural %>.order(created_at: :desc)
|
|
50
|
+
end
|
|
51
|
+
else
|
|
52
|
+
@<%= plural %> = @<%= plural %>.order(created_at: :desc) # Default order
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
<% if options[:paginator] -%>
|
|
56
|
+
@pagy, @<%= plural %> = pagy(@<%= plural %>)
|
|
57
|
+
<% end -%>
|
|
58
|
+
respond_to do |format|
|
|
59
|
+
format.html # index.html.erb
|
|
60
|
+
format.json
|
|
61
|
+
format.csv { send_data generate_csv(@<%= plural %>), filename: "<%= plural %>-#{Date.today}.csv" }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# GET /<%= "#{namespace_path}/" %><%= plural %>/1
|
|
66
|
+
def show
|
|
67
|
+
authorize @<%= singular %>
|
|
68
|
+
respond_to do |format|
|
|
69
|
+
format.html # show.html.erb
|
|
70
|
+
format.json
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# GET /<%= "#{namespace_path}/" %><%= plural %>/new
|
|
75
|
+
def new
|
|
76
|
+
@<%= singular %> = <%= class_name.singularize %>.new
|
|
77
|
+
authorize @<%= singular %>
|
|
78
|
+
respond_to do |format|
|
|
79
|
+
format.html # new.html.erb (form in modal)
|
|
80
|
+
format.json { render template: "<%= "#{namespace_path}/" %><%= plural %>/show", locals: { <%= singular %>: @<%= singular %> } }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# GET /<%= "#{namespace_path}/" %><%= plural %>/1/edit
|
|
85
|
+
def edit
|
|
86
|
+
authorize @<%= singular %>
|
|
87
|
+
respond_to do |format|
|
|
88
|
+
format.html
|
|
89
|
+
format.json { render template: "<%= "#{namespace_path}/" %><%= plural %>/show", locals: { <%= singular %>: @<%= singular %> } }
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# POST /<%= "#{namespace_path}/" %><%= plural %>
|
|
94
|
+
def create
|
|
95
|
+
@<%= singular %> = <%= class_name.singularize %>.new(<%= singular %>_params)
|
|
96
|
+
authorize @<%= singular %>
|
|
97
|
+
|
|
98
|
+
respond_to do |format|
|
|
99
|
+
if @<%= singular %>.save
|
|
100
|
+
@message = t("<%= plural %>.messages.create_success")
|
|
101
|
+
format.html do
|
|
102
|
+
flash[:notice] = @message
|
|
103
|
+
|
|
104
|
+
if turbo_frame_request?
|
|
105
|
+
render "shared/send_alert_via_drawer", locals: { message: @message, color: :success }
|
|
106
|
+
else
|
|
107
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
<% if options[:turbo] -%>
|
|
111
|
+
format.turbo_stream # renders create.turbo_stream.erb
|
|
112
|
+
<% end -%>
|
|
113
|
+
format.json { render template: "<%= "#{namespace_path}/" %><%= plural %>/show", locals: { <%= singular %>: @<%= singular %> }, status: :created }
|
|
114
|
+
else
|
|
115
|
+
format.html do
|
|
116
|
+
# Re-render the form for HTML (status 422 for validation errors)
|
|
117
|
+
render :new, status: :unprocessable_content
|
|
118
|
+
end
|
|
119
|
+
<% if options[:turbo] -%>
|
|
120
|
+
format.turbo_stream # renders create.turbo_stream.erb (re-render form with errors)
|
|
121
|
+
<% end -%>
|
|
122
|
+
format.json { render template: "<%= "#{namespace_path}/" %><%= plural %>/show", locals: { <%= singular %>: @<%= singular %> }, status: :unprocessable_content }
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# PATCH/PUT /<%= "#{namespace_path}/" %><%= plural %>/1
|
|
128
|
+
def update
|
|
129
|
+
authorize @<%= singular %>
|
|
130
|
+
respond_to do |format|
|
|
131
|
+
if @<%= singular %>.update(<%= singular %>_params)
|
|
132
|
+
@message = t("<%= plural %>.messages.update_success")
|
|
133
|
+
format.html do
|
|
134
|
+
flash[:notice] = @message
|
|
135
|
+
|
|
136
|
+
if turbo_frame_request?
|
|
137
|
+
render "shared/send_alert_via_drawer", locals: { message: @message, color: :success }
|
|
138
|
+
else
|
|
139
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
<% if options[:turbo] -%>
|
|
143
|
+
format.turbo_stream # renders update.turbo_stream.erb
|
|
144
|
+
<% end -%>
|
|
145
|
+
format.json { render template: "<%= "#{namespace_path}/" %><%= plural %>/show", locals: { <%= singular %>: @<%= singular %> } }
|
|
146
|
+
else
|
|
147
|
+
format.html do
|
|
148
|
+
render :edit, status: :unprocessable_content
|
|
149
|
+
end
|
|
150
|
+
<% if options[:turbo] -%>
|
|
151
|
+
format.turbo_stream # renders update.turbo_stream.erb (re-render form with errors)
|
|
152
|
+
<% end -%>
|
|
153
|
+
format.json { render template: "<%= "#{namespace_path}/" %><%= plural %>/show", locals: { <%= singular %>: @<%= singular %> }, status: :unprocessable_content }
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# DELETE /<%= "#{namespace_path}/" %><%= plural %>/1
|
|
159
|
+
def destroy
|
|
160
|
+
authorize @<%= singular %>
|
|
161
|
+
if @<%= singular %>.destroy
|
|
162
|
+
@message = t("<%= plural %>.messages.destroy_success")
|
|
163
|
+
color_alert = :success
|
|
164
|
+
else
|
|
165
|
+
@message = t("<%= plural %>.messages.destroy_failure")
|
|
166
|
+
color_alert = :danger
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
respond_to do |format|
|
|
170
|
+
format.html do
|
|
171
|
+
flash[:notice] = @message
|
|
172
|
+
|
|
173
|
+
if turbo_frame_request?
|
|
174
|
+
render "shared/send_alert_via_drawer", locals: { message: @message, color: color_alert }
|
|
175
|
+
else
|
|
176
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
<% if options[:turbo] -%>
|
|
180
|
+
format.turbo_stream # renders destroy.turbo_stream.erb
|
|
181
|
+
<% end -%>
|
|
182
|
+
format.json { head :no_content }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# UPDATE_ALL /<%= "#{namespace_path}/" %><%= plural %>/update_all
|
|
187
|
+
def update_all
|
|
188
|
+
authorize @<%= plural %>
|
|
189
|
+
@errors = []
|
|
190
|
+
@count = 0
|
|
191
|
+
|
|
192
|
+
ActiveRecord::Base.transaction do
|
|
193
|
+
@<%= plural %>.each do |<%= singular %>|
|
|
194
|
+
if <%= singular %>.update(<%= singular %>_params)
|
|
195
|
+
@count += 1
|
|
196
|
+
else
|
|
197
|
+
@errors << { id: <%= singular %>.id, errors: <%= singular %>.errors.full_messages }
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Rollback if any validation fails (optional - remove if you want partial updates)
|
|
202
|
+
raise ActiveRecord::Rollback if @errors.any?
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
@message = if @errors.empty?
|
|
206
|
+
t("<%= plural %>.messages.bulk_update_success", count: @count)
|
|
207
|
+
else
|
|
208
|
+
t("<%= plural %>.messages.bulk_update_failure", count: @count, errors: @errors.map { |e| "<%= singular.humanize %> ID #{e[:id]}: #{e[:errors].join(', ')}" }.join('; '))
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
respond_with_bulk_result(@errors.empty?)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# DESTROY_ALL /<%= "#{namespace_path}/" %><%= plural %>/destroy_all
|
|
215
|
+
def destroy_all
|
|
216
|
+
authorize @<%= plural %>
|
|
217
|
+
@errors = []
|
|
218
|
+
@count = 0
|
|
219
|
+
|
|
220
|
+
ActiveRecord::Base.transaction do
|
|
221
|
+
@<%= plural %>.each do |<%= singular %>|
|
|
222
|
+
if <%= singular %>.destroy
|
|
223
|
+
@count += 1
|
|
224
|
+
else
|
|
225
|
+
@errors << { id: <%= singular %>.id, errors: <%= singular %>.errors.full_messages }
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Rollback if any validation fails (optional - remove if you want partial updates)
|
|
230
|
+
raise ActiveRecord::Rollback if @errors.any?
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
@message = if @errors.empty?
|
|
234
|
+
t("<%= plural %>.messages.bulk_destroy_success", count: @count)
|
|
235
|
+
else
|
|
236
|
+
t("<%= plural %>.messages.bulk_destroy_failure", errors: @errors.map { |e| "<%= singular.humanize %> ID #{e[:id]}: #{e[:errors].join(', ')}" }.join('; '))
|
|
237
|
+
end
|
|
238
|
+
respond_with_bulk_result(@errors.empty?)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
private
|
|
242
|
+
|
|
243
|
+
def set_<%= singular %>
|
|
244
|
+
@<%= singular %> = <%= class_name.singularize %>.find(params[:id])
|
|
245
|
+
# Note: Pundit authorization for @<%= singular %> happens in each action
|
|
246
|
+
rescue ActiveRecord::RecordNotFound
|
|
247
|
+
@message = t("<%= plural %>.messages.not_found")
|
|
248
|
+
respond_to do |format|
|
|
249
|
+
format.html do
|
|
250
|
+
flash[:error] = @message
|
|
251
|
+
|
|
252
|
+
if turbo_frame_request?
|
|
253
|
+
render "shared/send_alert_via_drawer", locals: { message: @message, color: :success }
|
|
254
|
+
else
|
|
255
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
format.json { render json: { error: @message }, status: :not_found }
|
|
259
|
+
<% if options[:turbo] -%>
|
|
260
|
+
format.turbo_stream { render turbo_stream: turbo_stream.append("notice", partial: "shared/alert", locals: { message: @message, color: :error }) }
|
|
261
|
+
<% end -%>
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def set_<%= plural %>_for_bulk_actions
|
|
266
|
+
<%= singular %>_ids = Array(params[:<%= singular %>_ids]).reject(&:blank?)
|
|
267
|
+
@<%= plural %> = <%= class_name.singularize %>.where(id: <%= singular %>_ids)
|
|
268
|
+
|
|
269
|
+
if @<%= plural %>.empty?
|
|
270
|
+
@message = t("<%= plural %>.messages.not_selected_for_action")
|
|
271
|
+
respond_to do |format|
|
|
272
|
+
format.html do
|
|
273
|
+
flash[:warning] = @message
|
|
274
|
+
|
|
275
|
+
if turbo_frame_request?
|
|
276
|
+
render "shared/send_alert_via_drawer", locals: { message: @message, color: :danger }
|
|
277
|
+
else
|
|
278
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
<% if options[:turbo] -%>
|
|
282
|
+
format.turbo_stream { render turbo_stream: turbo_stream.append("notice", partial: "shared/alert", locals: { message: @message, color: :danger }) }
|
|
283
|
+
<% end -%>
|
|
284
|
+
format.json { render json: { message: @message }, status: :bad_request }
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def respond_with_bulk_result(success)
|
|
290
|
+
respond_to do |format|
|
|
291
|
+
if success
|
|
292
|
+
format.html do
|
|
293
|
+
flash[:notice] = @message
|
|
294
|
+
|
|
295
|
+
if turbo_frame_request?
|
|
296
|
+
render "shared/send_alert_via_drawer", locals: { message: @message, color: :success }
|
|
297
|
+
else
|
|
298
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
<% if options[:turbo] -%>
|
|
302
|
+
format.turbo_stream
|
|
303
|
+
<% end -%>
|
|
304
|
+
format.json { render json: { message: @message, count: @count }, status: :ok }
|
|
305
|
+
else
|
|
306
|
+
format.html do
|
|
307
|
+
flash[:error] = @message
|
|
308
|
+
|
|
309
|
+
if turbo_frame_request?
|
|
310
|
+
render "shared/send_alert_via_drawer", locals: { message: @message, color: :danger }
|
|
311
|
+
else
|
|
312
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
<% if options[:turbo] -%>
|
|
316
|
+
format.turbo_stream
|
|
317
|
+
<% end -%>
|
|
318
|
+
format.json {
|
|
319
|
+
render json: {
|
|
320
|
+
message: @message,
|
|
321
|
+
errors: @errors
|
|
322
|
+
}, status: :unprocessable_content
|
|
323
|
+
}
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Only allow a list of trusted parameters through.
|
|
329
|
+
def <%= singular %>_params
|
|
330
|
+
params.require(:<%= singular %>).permit(
|
|
331
|
+
<%- allowed_attrs = attributes.map do |att|
|
|
332
|
+
attr_name, attr_type = att.name, att.type.to_s
|
|
333
|
+
if ['references', 'belongs_to'].include?(attr_type)
|
|
334
|
+
":#{attr_name}_id"
|
|
335
|
+
elsif attr_type == 'password_digest'
|
|
336
|
+
# For password digest, permit password and password_confirmation
|
|
337
|
+
':password, :password_confirmation'
|
|
338
|
+
else
|
|
339
|
+
":#{attr_name}"
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
-%>
|
|
343
|
+
<%= allowed_attrs.join(', ') %>
|
|
344
|
+
)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def user_not_authorized
|
|
348
|
+
@message = t("<%= plural %>.messages.not_authorized")
|
|
349
|
+
respond_to do |format|
|
|
350
|
+
format.html do
|
|
351
|
+
flash[:error] = @message
|
|
352
|
+
redirect_to <%= path_prefix %><%= plural %>_path
|
|
353
|
+
end
|
|
354
|
+
format.json { render json: { error: @message }, status: :forbidden }
|
|
355
|
+
<% if options[:turbo] -%>
|
|
356
|
+
format.turbo_stream { render turbo_stream: turbo_stream.append("error", partial: "shared/alert", locals: { message: @message, color: :error }) }
|
|
357
|
+
<% end -%>
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def generate_csv(<%= plural %>)
|
|
362
|
+
attribute_names = %w[<%= attributes.map(&:name).map(&:camelize).join(" ") %>]
|
|
363
|
+
require "csv" unless defined?(CSV)
|
|
364
|
+
|
|
365
|
+
CSV.generate(headers: true) do |csv|
|
|
366
|
+
csv << attribute_names
|
|
367
|
+
<%= plural %>.each do |<%= singular %>|
|
|
368
|
+
csv << [
|
|
369
|
+
<% attributes.reject { |attr| attr.type == :password_digest }.each_with_index do |attr, idx| -%>
|
|
370
|
+
<%=
|
|
371
|
+
case attr.type
|
|
372
|
+
when :boolean
|
|
373
|
+
"I18n.t(#{singular}.#{attr.name}?, scope: \"#{plural}.values.#{attr.name}\")"
|
|
374
|
+
when :datetime
|
|
375
|
+
"#{singular}.#{attr.name}.strftime('%Y-%m-%d %H:%M:%S')"
|
|
376
|
+
else
|
|
377
|
+
"#{singular}.#{attr.name}"
|
|
378
|
+
end
|
|
379
|
+
%><%= "," unless idx == attributes.size - 1 %>
|
|
380
|
+
<% end -%>
|
|
381
|
+
]
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
rescue LoadError
|
|
385
|
+
# Fallback if CSV is not available
|
|
386
|
+
content = "#{attribute_names.join(',')}\n"
|
|
387
|
+
<%= plural %>.each do |<%= singular %>|
|
|
388
|
+
|
|
389
|
+
content += [
|
|
390
|
+
<% attributes.reject { |attr| attr.type == :password_digest }.each_with_index do |attr, idx| -%>
|
|
391
|
+
<%=
|
|
392
|
+
case attr.type
|
|
393
|
+
when :boolean
|
|
394
|
+
"I18n.t(#{singular}.#{attr.name}?, scope: \"#{plural}.values.#{attr.name}\")"
|
|
395
|
+
when :datetime
|
|
396
|
+
"#{singular}.#{attr.name}.strftime('%Y-%m-%d %H:%M:%S')"
|
|
397
|
+
else
|
|
398
|
+
"#{singular}.#{attr.name}"
|
|
399
|
+
end
|
|
400
|
+
%><%= "," unless idx == attributes.size - 1 %>
|
|
401
|
+
<% end -%>
|
|
402
|
+
].join(",")
|
|
403
|
+
end
|
|
404
|
+
content
|
|
405
|
+
end
|
|
406
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<% singular = file_name.singularize; plural = file_name.pluralize -%>
|
|
2
|
+
<%%= if @<%= singular %>.errors.any?
|
|
3
|
+
turbo_stream.replace "<%= singular %>_form", partial: "<%= namespace_path %>/<%= plural %>/form", locals: { <%= plural %>: [@<%= singular %>] }
|
|
4
|
+
else
|
|
5
|
+
flash[:notice] = @message
|
|
6
|
+
turbo_stream.action :refresh, "body"
|
|
7
|
+
end %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<% singular = file_name.singularize; plural = file_name.pluralize -%>
|
|
2
|
+
<%% if @errors.any? %>
|
|
3
|
+
<%%= turbo_stream.append "notice", fx_alert(with_content: @message, color: :danger) %>
|
|
4
|
+
<%% else %>
|
|
5
|
+
<%% @<%= plural %>.each do |<%= singular %>| %>
|
|
6
|
+
<%%= turbo_stream.remove dom_id(<%= singular %>) %>
|
|
7
|
+
<%% end %>
|
|
8
|
+
<%%= turbo_stream.append "notice", fx_alert(with_content: @message, color: :success) %>
|
|
9
|
+
<%% end %>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% content_for(:header) do %>
|
|
2
|
+
<%= fx_heading with_content: "Resend confirmation instructions", size: 2, class: "text-center mt-8" %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }, builder: Fluxbit::FormBuilder) do |f| %>
|
|
6
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
7
|
+
<%= f.fx_email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), wrapper_html: {class: "mb-6 field"} %>
|
|
8
|
+
<%= f.fx_submit "Resend confirmation instructions" %>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<%= render "devise/shared/links" %>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title><%%= content_for(:title) || "Application Name" %></title>
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
7
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
8
|
+
<%%= csrf_meta_tags %>
|
|
9
|
+
<%%= csp_meta_tag %>
|
|
10
|
+
|
|
11
|
+
<%%= yield :head %>
|
|
12
|
+
<link rel="icon" href="/icon.png" type="image/png">
|
|
13
|
+
<link rel="icon" href="/icon.svg" type="image/svg+xml">
|
|
14
|
+
<link rel="apple-touch-icon" href="/icon.png">
|
|
15
|
+
|
|
16
|
+
<%%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
|
|
17
|
+
<%%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
|
|
18
|
+
<script>
|
|
19
|
+
if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
20
|
+
document.documentElement.classList.add('dark');
|
|
21
|
+
} else {
|
|
22
|
+
document.documentElement.classList.remove('dark')
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
</head>
|
|
26
|
+
<body class="<%%= fx_body_class %>">
|
|
27
|
+
<p class="notice">
|
|
28
|
+
<%% if notice %>
|
|
29
|
+
<%%= fx_alert(color: :info, 'data-turbo-cache' => "false", with_content: notice) %>
|
|
30
|
+
<%% end %>
|
|
31
|
+
</p>
|
|
32
|
+
<p class="alert">
|
|
33
|
+
<%% if alert %>
|
|
34
|
+
<%%= fx_alert(color: :danger, 'data-turbo-cache' => "false", with_content: alert) %>
|
|
35
|
+
<%% end %>
|
|
36
|
+
</p>
|
|
37
|
+
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
|
38
|
+
<div class="sm:mx-auto sm:w-full sm:max-w-md">
|
|
39
|
+
<!-- Replace with your company logo -->
|
|
40
|
+
<%%= fx_heading(class: "text-center text-blue-900 flex justify-center items-center", remove_class: "text-gray-900") do %>
|
|
41
|
+
<svg width="512" height="512" viewBox="0 0 31.999996 31.999992" fill="#0068e6" aria-hidden="true" data-slot="icon" version="1.1" id="fluxbit" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" alt="Fluxbit Logo" class="h-24 w-auto px-2">
|
|
42
|
+
<g transform="translate(-14.895488,-76.954309)">
|
|
43
|
+
<g transform="matrix(0.03883817,0,0,0.03883817,-18.205404,74.713827)">
|
|
44
|
+
<path d="m 1089.7476,425.74218 c 57.5807,-87.88823 229.5277,-143.25616 138.5588,-203.04776 -35.7449,-21.73146 3.8792,-32.89434 29.8425,-24.79965 56.6117,17.64991 66.3127,69.78167 57.5963,102.44516 -25.5052,95.57597 -173.0966,108.96892 -164.5857,215.80641 14.7244,113.56667 178.4751,104.15893 218.0103,9.19107 13.1682,-31.63159 3.7281,-58.61968 -21.3229,-60.95897 -43.9037,-4.09979 -79.283,70.54958 -103.9213,79.24255 -23.0709,8.13988 -59.7994,-24.2899 -13.7305,-48.62764 51.675,-26.4149 68.1608,-106.93054 145.1876,-91.59293 84.7516,20.2064 88.9232,201.5204 -41.4396,268.20255 -164.4932,84.14041 -337.34273,-103.68571 -244.1955,-245.86079 z"/>
|
|
45
|
+
<rect width="55.374088" height="54.900341" x="1366.8969" y="321.34384" ry="10.65924" />
|
|
46
|
+
<path d="M 1264.2422,57.6875 A 411.96594,411.96594 0 0 0 852.27734,469.65234 411.96594,411.96594 0 0 0 1264.2422,881.61914 411.96594,411.96594 0 0 0 1676.209,469.65234 411.96594,411.96594 0 0 0 1264.2422,57.6875 Z m 0,40.025391 A 371.93936,371.93936 0 0 1 1636.1816,469.65234 371.93936,371.93936 0 0 1 1264.2422,841.5918 371.93936,371.93936 0 0 1 892.30469,469.65234 371.93936,371.93936 0 0 1 1264.2422,97.712891 Z" />
|
|
47
|
+
</g>
|
|
48
|
+
</g>
|
|
49
|
+
</svg>
|
|
50
|
+
Fluxbit
|
|
51
|
+
<%% end %>
|
|
52
|
+
<!-- /End replace -->
|
|
53
|
+
|
|
54
|
+
<%%= yield(:header) if content_for?(:header) %>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
58
|
+
<div class="py-8 px-4 sm:px-10 bg-white border border-gray-200 rounded-lg shadow dark:bg-slate-800 dark:border-slate-700">
|
|
59
|
+
<%%= yield %>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<p>Hello <%= @email %>!</p>
|
|
2
|
+
|
|
3
|
+
<% if @resource.try(:unconfirmed_email?) %>
|
|
4
|
+
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
|
|
5
|
+
<% else %>
|
|
6
|
+
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
|
|
7
|
+
<% end %>
|
data/lib/generators/fluxbit/templates/devise_views/mailer/reset_password_instructions.html.erb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<p>Hello <%= @resource.email %>!</p>
|
|
2
|
+
|
|
3
|
+
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
|
4
|
+
|
|
5
|
+
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
|
6
|
+
|
|
7
|
+
<p>If you didn't request this, please ignore this email.</p>
|
|
8
|
+
<p>Your password won't change until you access the link above and create a new one.</p>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<p>Hello <%= @resource.email %>!</p>
|
|
2
|
+
|
|
3
|
+
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
|
4
|
+
|
|
5
|
+
<p>Click the link below to unlock your account:</p>
|
|
6
|
+
|
|
7
|
+
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<% content_for(:header) do %>
|
|
2
|
+
<%= fx_heading with_content: "Change your password", size: 2, class: "text-center mt-8" %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }, builder: Fluxbit::FormBuilder) do |f| %>
|
|
6
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
7
|
+
<%= f.hidden_field :reset_password_token %>
|
|
8
|
+
<%= f.fx_password :password,
|
|
9
|
+
autofocus: true,
|
|
10
|
+
autocomplete: "new-password",
|
|
11
|
+
min_length: 6,
|
|
12
|
+
require_uppercase: true,
|
|
13
|
+
require_lowercase: true,
|
|
14
|
+
require_numbers: true,
|
|
15
|
+
require_special: true,
|
|
16
|
+
wrapper_html: {class: "mb-6 field"} %>
|
|
17
|
+
<%= f.fx_password :password_confirmation,
|
|
18
|
+
autocomplete: "new-password",
|
|
19
|
+
min_length: 6,
|
|
20
|
+
require_uppercase: true,
|
|
21
|
+
require_lowercase: true,
|
|
22
|
+
require_numbers: true,
|
|
23
|
+
require_special: true,
|
|
24
|
+
wrapper_html: {class: "mb-6 field"},
|
|
25
|
+
help_text: "We need your current password to confirm your changes" %>
|
|
26
|
+
<%= f.fx_submit "Change my password" %>
|
|
27
|
+
<% end %>
|
|
28
|
+
|
|
29
|
+
<%= render "devise/shared/links" %>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% content_for(:header) do %>
|
|
2
|
+
<%= fx_heading with_content: "Forgot your password?", size: 2, class: "text-center mt-8" %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }, builder: Fluxbit::FormBuilder) do |f| %>
|
|
6
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
7
|
+
<%= f.fx_email_field :email, autofocus: true, autocomplete: "email", wrapper_html: {class: "mb-6 field"} %>
|
|
8
|
+
<%= f.fx_submit "Send me password reset instructions" %>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<%= render "devise/shared/links" %>
|