lesli 5.0.19 → 5.0.21

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/lesli/brand/register-background.jpg +0 -0
  3. data/app/assets/stylesheets/lesli/application.css +1 -0
  4. data/app/helpers/lesli/navigation_helper.rb +6 -0
  5. data/app/interfaces/lesli/responder_interface.rb +35 -19
  6. data/app/models/concerns/lesli/account_initializer.rb +79 -0
  7. data/app/models/concerns/lesli/user_extensions.rb +133 -0
  8. data/app/models/concerns/lesli/user_security.rb +220 -0
  9. data/app/models/lesli/role/action.rb +3 -2
  10. data/app/models/lesli/shared/dashboard.rb +2 -2
  11. data/app/models/lesli/user/session.rb +1 -1
  12. data/app/models/lesli/user.rb +15 -15
  13. data/app/operators/lesli/role_operator.rb +9 -4
  14. data/app/services/lesli/role/action_service.rb +2 -3
  15. data/app/services/lesli/role_service.rb +3 -3
  16. data/app/views/lesli/abouts/welcome.html.erb +8 -5
  17. data/app/views/lesli/apps/show.html.erb +21 -33
  18. data/app/views/lesli/errors/not_found.html.erb +32 -0
  19. data/app/views/lesli/errors/unauthorized.html.erb +48 -0
  20. data/app/views/lesli/layouts/application-devise.html.erb +2 -2
  21. data/app/views/lesli/layouts/application-lesli.html.erb +1 -2
  22. data/app/views/lesli/partials/_application-analytics.html.erb +2 -2
  23. data/app/views/lesli/partials/_application-data.html.erb +0 -1
  24. data/app/views/lesli/partials/_application-head.html.erb +4 -4
  25. data/app/views/lesli/partials/_application-lesli-header.html.erb +47 -67
  26. data/app/views/lesli/partials/_application-lesli-navigation.html.erb +23 -5
  27. data/config/importmap.rb +0 -10
  28. data/config/initializers/devise_rails_8_patch.rb +8 -0
  29. data/config/initializers/lesli.rb +27 -23
  30. data/db/migrate/v1/0000120310_create_lesli_role_privileges.rb +2 -2
  31. data/db/seed/accounts.rb +1 -1
  32. data/db/seed/users.rb +6 -4
  33. data/db/seeds.rb +6 -6
  34. data/lib/lesli/engine.rb +0 -14
  35. data/lib/lesli/routing.rb +1 -1
  36. data/lib/lesli/version.rb +2 -2
  37. data/lib/rspec/testers/request.rb +15 -6
  38. data/lib/scss/_apps.scss +93 -0
  39. data/lib/scss/application.scss +34 -0
  40. data/lib/tasks/lesli/controllers.rake +1 -1
  41. data/lib/tasks/lesli/db.rake +27 -27
  42. data/lib/tasks/lesli_tasks.rake +3 -0
  43. data/readme.md +9 -10
  44. metadata +33 -13
  45. data/app/models/concerns/account_initializer.rb +0 -83
  46. data/app/models/concerns/user_extensions.rb +0 -152
  47. data/app/models/concerns/user_security.rb +0 -276
  48. data/app/operators/lesli/user_registration_operator.rb +0 -122
  49. /data/app/models/concerns/{user_activities.rb → lesli/user_activities.rb} +0 -0
@@ -34,12 +34,14 @@ module Lesli
34
34
  class RoleOperator < Lesli::ApplicationLesliService
35
35
 
36
36
  @role = nil
37
+ @action = nil
37
38
 
38
- def initialize role
39
+ def initialize role, action=nil
39
40
  @role = role
41
+ @action = action
40
42
  end
41
43
 
42
- def add_profile_privileges
44
+ def add_profile_actions
43
45
 
44
46
  # Adding default system actions for profile descriptor
45
47
  [
@@ -100,12 +102,15 @@ module Lesli
100
102
  lesli_role_actions.role_id as role_id,
101
103
  lesli_system_controllers.route as controller,
102
104
  lesli_system_controller_actions.name as action,
103
- true as active
105
+ lesli_role_actions.deleted_at IS NULL as active
104
106
  )).with_deleted
105
107
 
106
108
 
107
109
  # get privileges only for the given role, this is needed to sync only modified roles
108
- records = records.where("lesli_role_actions.role_id" => @role)
110
+ records = records.where("lesli_role_actions.role_id" => @role.id)
111
+
112
+ # get privileges only for the given role action, this is needed to sync only modified actions
113
+ records = records.where("lesli_role_actions.id" => @action.id) if @action
109
114
 
110
115
 
111
116
  # we use the deleted_at column to know if a privilege is enable or disable, NULL values
@@ -6,7 +6,7 @@ module Lesli
6
6
  super(Lesli::Role::Action.with_deleted.find(id))
7
7
  end
8
8
 
9
- def index params
9
+ def index role_id
10
10
 
11
11
  def clean action
12
12
  {
@@ -21,6 +21,7 @@ module Lesli
21
21
  role_actions = {}
22
22
 
23
23
  Lesli::Role::Action.with_deleted.joins(system_controller_action: :system_controller)
24
+ .where(:role_id => role_id)
24
25
  .select(
25
26
  :id,
26
27
  :role_id,
@@ -68,8 +69,6 @@ module Lesli
68
69
  end
69
70
  end
70
71
 
71
-
72
-
73
72
  role_actions
74
73
  end
75
74
  end
@@ -74,7 +74,7 @@ module Lesli
74
74
  from lesli_role_actions
75
75
  group by role_id
76
76
  ) actions on actions.role_id = lesli_roles.id
77
- )).where("lesli_roles.permission_level <= ?", current_user.max_object_level_permission)
77
+ )).where("lesli_roles.permission_level <= ?", current_user.max_level_permission)
78
78
  .select(
79
79
  :id,
80
80
  :name,
@@ -82,13 +82,13 @@ module Lesli
82
82
  :isolated,
83
83
  :description,
84
84
  :path_default,
85
- :object_level_permission,
85
+ :permission_level,
86
86
  "users.users",
87
87
  "actions.actions"
88
88
  )
89
89
  .page(query[:pagination][:page])
90
90
  .per(query[:pagination][:perPage])
91
- .order(object_level_permission: :desc, name: :asc)
91
+ .order(permission_level: :desc, name: :asc)
92
92
  end
93
93
 
94
94
  # @overwrite
@@ -20,9 +20,9 @@ html, body, * {
20
20
  background-color: #ffffff;
21
21
  background-position: 0 0,55px 55px;
22
22
  background-image:
23
- radial-gradient(#0d52bf 2px, transparent 2px),
24
- radial-gradient(#0d52bf 2px, #ffffff 2px);
25
- animation: rotateBackground 12s linear infinite;
23
+ radial-gradient(#0d52bf 1px, transparent 2px),
24
+ radial-gradient(#0d52bf 1px, #ffffff 2px);
25
+ animation: rotateBackground 10s linear infinite;
26
26
  }
27
27
 
28
28
  .page-welcome svg {
@@ -118,15 +118,18 @@ html, body, * {
118
118
  The Open Source Ruby on Rails <span>SaaS Development Framework</span>
119
119
  </h1>
120
120
  <div class="buttons">
121
- <a class="doc" target="blank" href="https://www.lesli.dev/">
121
+ <a class="doc" target="blank" href="https://www.lesli.dev/lesli/">
122
122
  Documentation
123
123
  </a>
124
124
  <a class="start" target="blank" href="https://www.lesli.dev/start/">
125
125
  Getting started
126
126
  </a>
127
127
  </div>
128
- <%= link_to("Apps", "/lesli/apps") unless defined?(LesliDashboard) %>
128
+ <% unless defined?(LesliShield) %>
129
+ <%= link_to("Apps", "/lesli/apps") unless defined?(LesliDashboard) %>
130
+ <% end %>
129
131
  <% if defined?(LesliShield) %>
132
+ <%= link_to("Apps", "/lesli/apps") if user_signed_in? && !defined?(LesliDashboard) %>
130
133
  <%= link_to("Dashboard", "/dashboard") if user_signed_in? && defined?(LesliDashboard) %>
131
134
  <%= link_to("Logout", "/logout") if user_signed_in? %>
132
135
  <%= link_to("Login", "/login") unless user_signed_in? %>
@@ -9,40 +9,28 @@ document.addEventListener('turbo:load', () => {
9
9
  })
10
10
  })
11
11
  </script>
12
-
13
- <%= render(LesliView::Layout::Container.new("lesli-apps", dashboard: true)) do %>
14
-
12
+ <%
13
+ @navigation_engines = [
14
+ :dashboard,
15
+ :admin,
16
+ :mailer,
17
+ :bell,
18
+ :calendar,
19
+ :papers,
20
+ :support,
21
+ :shield,
22
+ :security,
23
+ :audit,
24
+ :babel
25
+ ]
26
+ %>
27
+
28
+ <%= render(LesliView::Layout::Container.new("lesli-apps", dashboard: false)) do %>
15
29
  <%= render("lesli_dashboard/dashboards/shared/header") if defined?(LesliDashboard) %>
16
30
 
17
- <section
18
- class="lesli-application-engines">
19
- <div class="engines-container">
20
- <div class="engines">
21
- <%# 01. Administration %>
22
- <%= navigation_engine_admin %>
23
-
24
- <%# 02. Sales & Marketing %>
25
- <%= navigation_engine_mailer %>
26
-
27
- <%# 03. Productivity & Teamwork%>
28
- <%= navigation_engine_calendar %>
29
- <%= navigation_engine_dashboard %>
30
- <%= navigation_engine_bell %>
31
- <%= navigation_engine_papers %>
32
-
33
- <%# 05. Analytics %>
34
- <%= navigation_engine_audit %>
35
-
36
- <%# 07. IT & Help Desk %>
37
- <%= navigation_engine_support %>
38
-
39
- <%# 08. Security & Privacy %>
40
- <%= navigation_engine_shield %>
41
- <%= navigation_engine_security %>
42
-
43
- <%# 09. Integrations %>
44
- <%= navigation_engine_babel %>
45
- </div>
46
- </div>
31
+ <section class="columns is-multiline is-mobile is-centered engines">
32
+ <% @navigation_engines.each do |engine| %>
33
+ <%= public_send("navigation_engine_#{engine}") %>
34
+ <% end %>
47
35
  </section>
48
36
  <% end %>
@@ -0,0 +1,32 @@
1
+ <style>
2
+ .error-404 .material-symbols {
3
+ font-size: 8rem;
4
+ color: rgb(190,190,190);
5
+ }
6
+ .error-404 h2 {
7
+ font-size: 2rem;
8
+ color: #3d211b;
9
+ }
10
+
11
+ .error-404 p {
12
+ font-size: 1.4rem;
13
+ font-weight: 300;
14
+ }
15
+ </style>
16
+ <%= render(LesliView::Layout::Container.new("accounts")) do %>
17
+ <section class="hero is-medium error-404">
18
+ <div class="hero-body has-text-centered">
19
+
20
+ <div class="mb-6">
21
+ <%= render(LesliView::Elements::Empty.new(text:nil)) %>
22
+ </div>
23
+
24
+ <h2 class="mb-4">404 Not found</h2>
25
+
26
+ <p>
27
+ <%= @message %>
28
+ </p>
29
+ </div>
30
+ </section>
31
+ <% end %>
32
+
@@ -0,0 +1,48 @@
1
+ <style>
2
+ .error-401 .material-symbols {
3
+ font-size: 8rem;
4
+ color: rgb(190,190,190);
5
+ }
6
+ .error-401 h2 {
7
+ font-size: 2rem;
8
+ color: #7a0000;
9
+ }
10
+
11
+ .error-401 p {
12
+ font-size: 1.4rem;
13
+ font-weight: 300;
14
+ }
15
+ </style>
16
+ <%= render(LesliView::Layout::Container.new("accounts")) do %>
17
+ <section class="hero is-medium error-401">
18
+ <div class="hero-body has-text-centered">
19
+
20
+ <div class="mb-6">
21
+ <span class="icon">
22
+ <span class="material-symbols">
23
+ shield_lock
24
+ </span>
25
+ </span>
26
+ </div>
27
+
28
+ <h2 class="mb-4">401 Unauthorized</h2>
29
+
30
+ <p>
31
+ We could not validate your privileges.
32
+ Please ask the administrator to send you an invite to see this content.
33
+ </p>
34
+
35
+ <div class="box mt-6">
36
+ <ul>
37
+ <!--li><%= @error_object[:error_message] %></li-->
38
+ <li>
39
+ <%= @error_object.dig(:error_detail, :controller) %>
40
+ (<%= @error_object.dig(:error_detail, :action) %>)
41
+ </li>
42
+ <li><%= @error_object[:error_role] %></li>
43
+ </ul>
44
+ </div>
45
+ </div>
46
+ </section>
47
+ <% end %>
48
+
@@ -36,8 +36,8 @@ Building a better future, one line of code at a time.
36
36
  <html>
37
37
  <head>
38
38
  <script>const Lesli = <%= @lesli.to_json.html_safe %></script>
39
- <%= render partial: "lesli/partials/application-head" %>
40
- <%# render partial: "lesli/partials/application-data" %>
39
+ <%= render(partial: "lesli/partials/application-head") %>
40
+ <%# render(partial: "lesli/partials/application-data") %>
41
41
  <%= stylesheet_link_tag("lesli_shield/#{devise_controller}", media: "all") %>
42
42
  <%# Disable back button in browser after Logout using JavaScript %>
43
43
  <% if flash[:logout] == true %>
@@ -40,14 +40,13 @@ Building a better future, one line of code at a time.
40
40
  </head>
41
41
  <body class="<%= application_body_class %>">
42
42
  <%= render(partial: "lesli/partials/application-lesli-header") %>
43
- <%= render(partial: "lesli/partials/application-lesli-navigation") %>
44
43
  <%= render(partial: "lesli/partials/application-lesli-notifications") %>
45
44
  <main class="lesli-application-app">
46
45
  <%= render(partial: "lesli/partials/application-lesli-sidebar") %>
47
46
  <%= render(partial: "lesli/partials/application-lesli-content") %>
48
47
  </main>
49
48
  <%= render(partial: "lesli_assets/partials/application-lesli-icons-engines") %>
50
- <%#= render(partial: "lesli/partials/application-analytics" %>
49
+ <%= render(partial: "lesli/partials/application-analytics") %>
51
50
  <%= yield(:application_lesli_body_bottom) %>
52
51
  </body>
53
52
  </html>
@@ -36,14 +36,14 @@ Building a better future, one line of code at a time.
36
36
  <% protected_controllers = ["confirmations"] %>
37
37
 
38
38
  <% # Get an specific site tracking id or use the development default %>
39
- <% tracking_id = Rails.application.credentials.dig(:providers, :analytics) %>
39
+ <% tracking_id = Rails.application.credentials.dig(:providers, :google, :tag_manager) || ENV["PROVIDERS_GOOGLE_TAG_MANAGER"] %>
40
40
 
41
41
  <% # check if analytics is enabled in the settings file %>
42
42
  <% enable_analytics = Lesli.config.security[:enable_analytics] %>
43
43
 
44
44
  <% if Rails.env.production? && enable_analytics && tracking_id %>
45
45
 
46
- <% if !protected_controllers.include?(controller_name) %>
46
+ <% unless protected_controllers.include?(controller_name) %>
47
47
 
48
48
  <!-- Google tag (gtag.js) -->
49
49
  <script async src="https://www.googletagmanager.com/gtag/js?id=<%= tracking_id %>"></script>
@@ -32,7 +32,6 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  <%
34
34
 
35
- @lesli[:tickets] = 0
36
35
  @lesli[:notifications] = Lesli::Courier.new(:lesli_bell, 0).from(:notification_service, current_user).call(:count)
37
36
 
38
37
  %>
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2023, Lesli Technologies, S. A.
5
+ Copyright (c) 2025, Lesli Technologies, S. A.
6
6
 
7
7
  This program is free software: you can redistribute it and/or modify
8
8
  it under the terms of the GNU General Public License as published by
@@ -17,9 +17,9 @@ GNU General Public License for more details.
17
17
  You should have received a copy of the GNU General Public License
18
18
  along with this program. If not, see http://www.gnu.org/licenses/.
19
19
 
20
- Lesli · Ruby on Rails SaaS development platform.
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
21
 
22
- Made with ♥ by https://www.lesli.tech
22
+ Made with ♥ by LesliTech
23
23
  Building a better future, one line of code at a time.
24
24
 
25
25
  @contact hello@lesli.tech
@@ -42,7 +42,7 @@ Building a better future, one line of code at a time.
42
42
 
43
43
  <%# rails standard meta tags %>
44
44
  <%= csrf_meta_tags %>
45
- <%#= favicon %>
45
+ <%= favicon %>
46
46
 
47
47
  <%# provide a short description of the page %>
48
48
  <meta name="description" content="<%#= website_meta_description %>">
@@ -30,23 +30,16 @@ Building a better future, one line of code at a time.
30
30
  // ·
31
31
  %>
32
32
 
33
- <%# check if custom navigation partial exists, getting the path from application helper %>
34
- <% custom_navigation_path = "partials/application-lesli-header" %>
33
+ <%# Get the navigation partial for every engine %>
34
+ <% engine_navigation_partial = navigation_partial %>
35
35
 
36
- <%# validate the path to be sure the partial exists when trying to render it %>
37
- <% custom_navigation_exists = lookup_context.exists?(custom_navigation_path, nil, true) %>
38
-
39
- <%# render navigation partial %>
40
- <% if custom_navigation_exists %>
41
-
42
- <%= render partial: custom_navigation_path %>
43
-
44
- <% else %>
45
36
  <header class="lesli-application-header">
46
- <nav class="lesli-navbar navbar" role="navigation" aria-label="main navigation">
47
- <div class="container" x-data="{ navActive: false }">
37
+ <div class="container" x-data="{ navActive: false }">
38
+ <nav class="navbar" role="navigation" aria-label="main navigation">
48
39
  <div class="navbar-brand">
49
- <a href="<%= defined?(LesliDashboard) ? '/dashboard' : '/' %>" class="application-navbar-brand">
40
+ <a
41
+ class="navbar-item p-0"
42
+ href="<%= defined?(LesliDashboard) ? '/dashboard' : '/' %>">
50
43
  <%= customization_instance_logo_tag(logo: "app-logo", options: { alt: "Lesli app logo" }) %>
51
44
  </a>
52
45
  <a
@@ -62,68 +55,55 @@ Building a better future, one line of code at a time.
62
55
  <span aria-hidden="true"></span>
63
56
  </a>
64
57
  </div>
65
- <div class="navbar-menu"
66
- :class="{ 'is-active': navActive }">
67
- <div class="navbar-start">
68
- </div>
69
- <div class="navbar-end">
58
+ <div class="navbar-menu" :class="{ 'is-active': navActive }">
59
+ <div class="navbar-end is-flex is-justify-content-center">
70
60
 
61
+ <!-- notifications -->
71
62
  <div class="navbar-item">
72
- <div class="header-icons field is-grouped is-justify-content-center">
73
- <div class="control">
74
-
75
- <!-- tasks -->
76
- <% if defined?(LesliFocus) %>
77
- <a v-if="props.showFocus" class="header-indicator"
78
- @click="() => { storeLayout.showSuppor = true }">
79
- <span class="ri-list-check-3">
80
- </span>
81
- <span class="count" v-if="storeLayout.header.support > 0">
82
- </span>
83
- </a>
84
- <% end %>
85
-
86
- <!-- tickets -->
87
- <% if defined?(LesliSupport) %>
88
- <%= link_to(
89
- lesli_support.tickets_path,
90
- :class => "header-indicator",
91
- :data => { turbo_frame: '_top' }) do %>
92
- <span class="ri-ticket-2-line"></span>
93
- <% if @lesli[:tickets] > 0 %>
94
- <span class="count"></span>
95
- <% end %>
96
- <% end %>
97
- <% end %>
98
-
99
- <!-- notifications -->
100
- <% if defined?(LesliBell) %>
101
- <%= link_to(
102
- lesli_bell.notifications_path,
103
- :class => "header-indicator",
104
- :data => { turbo_frame: '_top' }) do %>
105
- <% if @lesli[:notifications] > 0 %>
106
- <span class="ri-notification-3-fill has-text-primary"></span>
107
- <% else %>
108
- <span class="ri-notification-3-line"></span>
109
- <% end %>
110
- <% end %>
63
+ <% if defined?(LesliBell) %>
64
+ <%= link_to(
65
+ lesli_bell.notifications_path,
66
+ :class => "header-indicator",
67
+ :data => { turbo_frame: '_top' }) do %>
68
+ <% if @lesli[:notifications] > 0 %>
69
+ <span class="ri-notification-3-fill has-text-primary"></span>
70
+ <% else %>
71
+ <span class="ri-notification-3-line"></span>
111
72
  <% end %>
73
+ <% end %>
74
+ <% end %>
75
+ </div>
112
76
 
113
- <!-- module selector -->
114
- <%= navigation_link(lesli.apps_path, nil, "ri-apps-2-line") %>
77
+ <!-- app selector -->
78
+ <div class="navbar-item">
79
+ <%= navigation_link(lesli.apps_path, nil, "ri-apps-2-line") %>
80
+ </div>
115
81
 
116
- <!-- user profile -->
117
- <%= navigation_link(lesli.apps_path, nil, "ri-user-smile-line") %>
82
+ <!-- user profile -->
83
+ <div class="navbar-item">
84
+ <%= navigation_link(lesli.apps_path, nil, "ri-user-smile-line") %>
85
+ </div>
118
86
 
119
- <!-- logout from session -->
120
- <%= navigation_link(main_app.destroy_user_session_path, nil, "ri-logout-circle-r-line") if defined?(LesliShield) %>
121
- </div>
122
- </div>
87
+ <!-- logout from session -->
88
+ <div class="navbar-item">
89
+ <%= navigation_link(main_app.destroy_user_session_path, nil, "ri-logout-circle-r-line") if defined?(LesliShield) %>
123
90
  </div>
124
91
  </div>
92
+ <div class="navbar-end is-hidden-desktop">
93
+ <%= render(engine_navigation_partial) if engine_navigation_partial %>
94
+ </div>
95
+ </div>
96
+ </nav>
97
+ </div>
98
+ </header>
99
+
100
+ <%# Build the engine navigation %>
101
+ <% if engine_navigation_partial %>
102
+ <nav class="navbar lesli-application-navigation is-hidden-touch">
103
+ <div class="navbar-menu">
104
+ <div class="navbar-start is-flex-grow-1 is-justify-content-center">
105
+ <%= render(engine_navigation_partial) %>
125
106
  </div>
126
107
  </div>
127
108
  </nav>
128
- </header>
129
109
  <% end %>
@@ -48,12 +48,30 @@ Building a better future, one line of code at a time.
48
48
 
49
49
  <%# render navigation partial %>
50
50
  <% if custom_sidebar_exists %>
51
- <nav class="lesli-navbar navbar lesli-application-navigation" role="navigation" aria-label="main navigation">
52
- <div class="navbar-menu">
53
- <div class="navbar-end">
54
- <%= render partial: custom_sidebar_path %>
55
- </div>
51
+ <nav
52
+ class="navbar lesli-application-navigation"
53
+ role="navigation"
54
+ aria-label="main navigation"
55
+ x-data="{ navActive: false }">
56
+ <div class="navbar-brand">
57
+ <a
58
+ class="navbar-burger"
59
+ role="button"
60
+ aria-label="menu"
61
+ aria-expanded="false"
62
+ @click="navActive = !navActive"
63
+ :class="{ 'is-active': navActive }">
64
+ <span aria-hidden="true"></span>
65
+ <span aria-hidden="true"></span>
66
+ <span aria-hidden="true"></span>
67
+ <span aria-hidden="true"></span>
68
+ </a>
69
+ </div>
70
+ <div class="navbar-menu" :class="{ 'is-active': navActive }">
71
+ <div class="navbar-start is-flex-grow-1 is-justify-content-center">
72
+ <%= render partial: custom_sidebar_path %>
56
73
  </div>
74
+ </div>
57
75
  </nav>
58
76
  <% else %>
59
77
  <!-- no navigation found -->
data/config/importmap.rb CHANGED
@@ -2,13 +2,3 @@
2
2
 
3
3
  pin "application", to: "lesli/application.js", preload: true
4
4
  pin "@hotwired/turbo-rails", to: "turbo.min.js"
5
-
6
-
7
-
8
- #pin "chart.js", to: "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"
9
- #pin "chart.js", to: "https://ga.jspm.io/npm:chart.js@4.5.1/dist/chart.esm.js"
10
-
11
-
12
-
13
- # my_engine/config/importmap.rb
14
- #pin_all_from File.expand_path("../app/assets/javascripts", __dir__)
@@ -0,0 +1,8 @@
1
+ require 'devise'
2
+
3
+ module Devise
4
+ def self.mappings
5
+ Rails.application.try(:reload_routes_unless_loaded)
6
+ @@mappings
7
+ end
8
+ end