lesli 5.0.19 → 5.0.20

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/lesli/application.css +1 -0
  3. data/app/helpers/lesli/navigation_helper.rb +6 -0
  4. data/app/interfaces/lesli/responder_interface.rb +35 -19
  5. data/app/models/concerns/account_initializer.rb +2 -3
  6. data/app/models/concerns/user_security.rb +5 -4
  7. data/app/models/lesli/role/action.rb +3 -2
  8. data/app/models/lesli/shared/dashboard.rb +2 -2
  9. data/app/models/lesli/user/session.rb +1 -1
  10. data/app/operators/lesli/role_operator.rb +9 -4
  11. data/app/services/lesli/role/action_service.rb +2 -3
  12. data/app/views/lesli/abouts/welcome.html.erb +8 -5
  13. data/app/views/lesli/apps/show.html.erb +21 -33
  14. data/app/views/lesli/errors/not_found.html.erb +32 -0
  15. data/app/views/lesli/errors/unauthorized.html.erb +48 -0
  16. data/app/views/lesli/layouts/application-lesli.html.erb +1 -2
  17. data/app/views/lesli/partials/_application-analytics.html.erb +2 -2
  18. data/app/views/lesli/partials/_application-lesli-header.html.erb +60 -65
  19. data/app/views/lesli/partials/_application-lesli-navigation.html.erb +23 -5
  20. data/config/importmap.rb +0 -10
  21. data/config/initializers/devise_rails_8_patch.rb +8 -0
  22. data/config/initializers/lesli.rb +27 -23
  23. data/db/migrate/v1/0000120310_create_lesli_role_privileges.rb +2 -2
  24. data/db/seed/users.rb +5 -3
  25. data/lib/lesli/engine.rb +0 -14
  26. data/lib/lesli/routing.rb +1 -1
  27. data/lib/lesli/version.rb +2 -2
  28. data/lib/rspec/testers/request.rb +15 -6
  29. data/lib/scss/_apps.scss +93 -0
  30. data/lib/scss/application.scss +34 -0
  31. data/lib/tasks/lesli/db.rake +1 -1
  32. data/lib/tasks/lesli_tasks.rake +3 -0
  33. data/readme.md +9 -10
  34. metadata +28 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21f07e22ae016cc4db12b194daef6db2502a475c076e06f72cc27435412595e5
4
- data.tar.gz: c302aae46f34a045d07fc498b90f7c4edbc71f6f5d562091a75379231e83ff1c
3
+ metadata.gz: 126a19d2153659244f65bb4a49db4618786defe3328e86f2d7217bea1fb66ffb
4
+ data.tar.gz: 89b09d6eec6bb3e320c2eb09e07ae50011d047cf12668479c1565a117954506f
5
5
  SHA512:
6
- metadata.gz: 9024ac084f83df2ebb86cc65b2633dd81e3d93d6993760d9439b622b947f11a4cb72551514306e808f40b0ce7c39e709a10fb0aefbcd22449bdf7d4df20a027c
7
- data.tar.gz: 299e0707fd1998f384e698b053a6f98f46d97222ff95e97e0a8c9f024e1fce607bb5f9d50684dce10e9c1c9cc27bc6e0af6307589d1480df99ce078e513afbc2
6
+ metadata.gz: 7c51533de90a1b6ac70ed9d41f5b329fbbbb35660a348f1ce37aebf1cd29ead7ccaf94e5884c6389c1939c7e62a8b72a48317322b2c010f57a2bbb6a9f98cb3c
7
+ data.tar.gz: b1aec4ddf728cdd79d7a44ec0b2d5836773cf53d31ed09ceecbb068daeeadba185d6661063aaa1769a1beaf12748b21236ecbede30f032f268b8750cddf6a417
@@ -0,0 +1 @@
1
+ body.lesli.apps.show .lesli-element-header{margin-bottom:5rem !important}body.lesli.apps.show .engines{gap:24px;margin-inline-end:auto;margin-inline-start:auto}body.lesli.apps.show .engines a{flex-basis:318px;text-align:center;padding:2rem .4rem 2.8rem;border:#fff 1px solid;border-radius:6px;background-color:#fff;transition:all ease-in-out .2s;box-shadow:rgba(9,30,66,.25) 0px 4px 8px -2px,rgba(9,30,66,.08) 0px 0px 0px 1px}body.lesli.apps.show .engines a:hover{border-color:var(--lesli-color-primary);transform:translateY(-2px)}body.lesli.apps.show .engines a.is-active{background-color:#f0f4ff;border-color:var(--lesli-color-primary)}body.lesli.apps.show .engines a svg{margin-right:.4rem;fill:var(--lesli-color-primary)}body.lesli.apps.show .engines a p{font-size:14}body.lesli.apps.show .engines a span{font-weight:600;font-size:20px}body.lesli.apps.show .engines a span,body.lesli.apps.show .engines a p{color:var(--lesli-color-primary)}
@@ -33,6 +33,12 @@ Building a better future, one line of code at a time.
33
33
  module Lesli
34
34
  module NavigationHelper
35
35
 
36
+ def navigation_partial
37
+ engine = lesli_engine[:code]
38
+ path = engine == "root" ? "partials/navigation" : "#{engine}/partials/navigation"
39
+ lookup_context.exists?(path, [], true) ? path : nil
40
+ end
41
+
36
42
  # Prints a separator line
37
43
  def navigation_separator
38
44
  content_tag(:li) do
@@ -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,17 +17,17 @@ 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 · Your Smart Business Assistant.
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
26
- @website https://lesli.tech
26
+ @website https://www.lesli.tech
27
27
  @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
28
 
29
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
- // ·
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
31
  =end
32
32
 
33
33
  module Lesli
@@ -72,27 +72,43 @@ module Lesli
72
72
  end
73
73
 
74
74
  # JSON not found response
75
- def respond_with_not_found
76
- respond_with_http(404, {
77
- message: I18n.t("core.shared.messages_danger_not_found")
78
- })
75
+ def respond_with_not_found message=nil
76
+
77
+ @message = message || I18n.t("core.shared.messages_danger_not_found")
78
+ respond_to do |format|
79
+ format.json{ respond_with_http(404, { message: @message }) }
80
+ format.html{ render('lesli/errors/not_found', status: :not_found) }
81
+ end
79
82
  end
80
83
 
81
84
  # JSON not found response
82
85
  def respond_with_unauthorized(detail = {})
83
- error_object = {}
84
86
 
85
- error_object[:message] = I18n.t("core.shared.view_text_unauthorized_request")
86
- error_object[:detail] = detail if Rails.env == "development"
87
+ @error_object = {
88
+ error_role: nil,
89
+ error_detail: nil,
90
+ error_message: I18n.t("core.shared.view_text_unauthorized_request")
91
+ }
87
92
 
88
- error_object[:role] = "( #{current_user.lesliroles.map(&:name).join(', ')} )" if (Rails.env == "development") && !current_user.blank?
93
+ unless Rails.env.production?
94
+ @error_object[:error_detail] = detail unless detail.empty?
95
+ if current_user.present?
96
+ @error_object[:error_role] = "( #{current_user.lesliroles.map(&:name).join(', ')} )"
97
+ end
98
+ end
89
99
 
90
100
  respond_to do |format|
91
- format.json { render status: 401, json: error_object.to_json }
92
- format.html { redirect_to "/401" } if Rails.env == "production"
93
- format.html { render status: 401, json: error_object.to_json }
94
- # format.xlsx { redirect_to "/401" } if Rails.env == "production"
95
- # format.xlsx { render status: 401, json: error_object.to_json }
101
+ format.json{ render(status: :unauthorized, json: @error_object) }
102
+ format.html{ render('lesli/errors/unauthorized', status: :unauthorized) }
103
+
104
+ # format.xlsx do
105
+ # if Rails.env.production?
106
+ # redirect_to "/401" # Or a specific Excel error download if applicable
107
+ # else
108
+ # # For development, you might still want a JSON response for debugging
109
+ # render status: :unauthorized, json: error_object.to_json
110
+ # end
111
+ # end
96
112
  end
97
113
  end
98
114
 
@@ -58,8 +58,7 @@ module AccountInitializer
58
58
  # Add base privileges to roles
59
59
  Lesli::RoleOperator.new(owner).add_owner_actions
60
60
  Lesli::RoleOperator.new(admin).add_owner_actions
61
- Lesli::RoleOperator.new(limited).add_profile_privileges
62
-
61
+ Lesli::RoleOperator.new(limited).add_profile_actions
63
62
 
64
63
  end
65
64
 
@@ -69,7 +68,7 @@ module AccountInitializer
69
68
 
70
69
  LesliSystem.engines.each do |engine, data|
71
70
 
72
- next if ["Lesli", "LesliBabel", "LesliShield", "Root"].include?(engine)
71
+ next if ["Lesli", "LesliBabel", "Root"].include?(engine)
73
72
 
74
73
  # Skip if the engine is not defined
75
74
  next unless Object.const_defined?(engine)
@@ -73,10 +73,11 @@ module UserSecurity
73
73
  # current_user.has_privileges?(controllers, actions)
74
74
  def has_privileges_for?(controller, action)
75
75
  begin
76
- return !self.privileges
77
- .where("lesli_role_privileges.controller = ?", controller)
78
- .where("lesli_role_privileges.action = ?", action)
79
- .first.blank?
76
+ return self.privileges.where(
77
+ controller: controller,
78
+ action: action,
79
+ active: true
80
+ ).exists?
80
81
  rescue => exception
81
82
  return false
82
83
  end
@@ -34,14 +34,15 @@ module Lesli
34
34
  class Role::Action < ApplicationLesliRecord
35
35
  belongs_to :role
36
36
 
37
- after_save :synchronize_privileges
37
+ after_create :synchronize_privileges
38
+ after_update :synchronize_privileges
38
39
  after_destroy :synchronize_privileges
39
40
 
40
41
  belongs_to :action, class_name: "SystemController::Action"
41
42
  belongs_to :system_controller_action, class_name: "SystemController::Action", foreign_key: "action_id"
42
43
 
43
44
  def synchronize_privileges
44
- Lesli::RoleOperator.new(self).synchronize
45
+ Lesli::RoleOperator.new(self.role, self).synchronize
45
46
  end
46
47
 
47
48
  def self.index current_user, query, role
@@ -34,13 +34,13 @@ module Lesli
34
34
  module Shared
35
35
  class DashboardFallback < ::Lesli::ApplicationLesliRecord
36
36
  self.abstract_class = true
37
- def self.initialize_dashboard(account)
37
+ def self.initialize_account(account)
38
38
  end
39
39
  end
40
40
 
41
41
  base_class = "::LesliDashboard::Shared::Dashboard".safe_constantize || DashboardFallback
42
42
 
43
- class Dashboard < DashboardFallback
43
+ class Dashboard < base_class
44
44
  self.abstract_class = true
45
45
  end
46
46
  end
@@ -36,7 +36,7 @@ module Lesli
36
36
 
37
37
  after_create :set_session_token
38
38
 
39
- enum session_source: {
39
+ enum :session_source, {
40
40
  :dispatcher_standard_session => "dispatcher_standard_session",
41
41
  :devise_standard_session => "devise_standard_session"
42
42
  }
@@ -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
@@ -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 credentials.
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
+
@@ -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>
@@ -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,70 @@ 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
+ <!-- tickets -->
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 %>
63
+ <% if defined?(LesliSupport) %>
64
+ <%= link_to(
65
+ lesli_support.tickets_path,
66
+ :class => "header-indicator",
67
+ :data => { turbo_frame: '_top' }) do %>
68
+ <span class="ri-ticket-2-line"></span>
69
+ <% if @lesli[:tickets] > 0 %>
70
+ <span class="count"></span>
97
71
  <% end %>
72
+ <% end %>
73
+ <% end %>
74
+ </div>
98
75
 
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 %>
76
+ <!-- notifications -->
77
+ <div class="navbar-item">
78
+ <% if defined?(LesliBell) %>
79
+ <%= link_to(
80
+ lesli_bell.notifications_path,
81
+ :class => "header-indicator",
82
+ :data => { turbo_frame: '_top' }) do %>
83
+ <% if @lesli[:notifications] > 0 %>
84
+ <span class="ri-notification-3-fill has-text-primary"></span>
85
+ <% else %>
86
+ <span class="ri-notification-3-line"></span>
111
87
  <% end %>
88
+ <% end %>
89
+ <% end %>
90
+ </div>
112
91
 
113
- <!-- module selector -->
114
- <%= navigation_link(lesli.apps_path, nil, "ri-apps-2-line") %>
92
+ <!-- app selector -->
93
+ <div class="navbar-item">
94
+ <%= navigation_link(lesli.apps_path, nil, "ri-apps-2-line") %>
95
+ </div>
115
96
 
116
- <!-- user profile -->
117
- <%= navigation_link(lesli.apps_path, nil, "ri-user-smile-line") %>
97
+ <!-- user profile -->
98
+ <div class="navbar-item">
99
+ <%= navigation_link(lesli.apps_path, nil, "ri-user-smile-line") %>
100
+ </div>
118
101
 
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>
102
+ <!-- logout from session -->
103
+ <div class="navbar-item">
104
+ <%= navigation_link(main_app.destroy_user_session_path, nil, "ri-logout-circle-r-line") if defined?(LesliShield) %>
123
105
  </div>
124
106
  </div>
107
+ <div class="navbar-end is-hidden-desktop">
108
+ <%= render(engine_navigation_partial) if engine_navigation_partial %>
109
+ </div>
110
+ </div>
111
+ </nav>
112
+ </div>
113
+ </header>
114
+
115
+ <%# Build the engine navigation %>
116
+ <% if engine_navigation_partial %>
117
+ <nav class="navbar lesli-application-navigation is-hidden-touch">
118
+ <div class="navbar-menu">
119
+ <div class="navbar-start is-flex-grow-1 is-justify-content-center">
120
+ <%= render(engine_navigation_partial) %>
125
121
  </div>
126
122
  </div>
127
123
  </nav>
128
- </header>
129
124
  <% 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
@@ -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
@@ -19,7 +19,7 @@ along with this program. If not, see http://www.gnu.org/licenses/.
19
19
 
20
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
@@ -33,7 +33,7 @@ Building a better future, one line of code at a time.
33
33
  Lesli.configure do |config|
34
34
 
35
35
 
36
- # Start Lesli as demo
36
+ # Enable or disable demo mode.
37
37
  config.demo = false
38
38
 
39
39
 
@@ -41,7 +41,7 @@ Lesli.configure do |config|
41
41
  config.instance = "Lesli"
42
42
 
43
43
 
44
- # Information about the main account in the platform
44
+ # Provides organization details displayed throughout the system.
45
45
  config.company = {
46
46
  name: "Lesli",
47
47
  email: "hello@lesli.tech",
@@ -49,26 +49,26 @@ Lesli.configure do |config|
49
49
  }
50
50
 
51
51
 
52
- # Available languages globally (Requires LesliBabel)
52
+ # List of supported languages (requires `LesliBabel`).
53
53
  config.locales = {
54
54
  :en => "English", # English
55
- :de => "Deutsch", # Deutsch/German
56
- # :pl => "Polski", # Polski/Polish/Poland
57
- # :nl => "Dutch", # Dutch/Nederlands/Netherlands
55
+ :de => "Deutsch", # Deutsch/German
56
+ :pl => "Polski", # Polski/Polish/Poland
57
+ :nl => "Dutch", # Dutch/Nederlands/Netherlands
58
58
  :es => "Español", # Español/Spanish
59
- # :uk => "украї́нська", # украї́нська/Ukrainian
60
- # :sr => "Српски", # Српски/Srpski/Serbian
61
- :it => "Italiano", # Italiano/Italian
62
- # :hr => "Hrvatski", # Hrvatski/Croatian
63
- #:fr => "Français", # French
64
- #:pt => "Português", # Portuguese
65
- # :tr => "Türkçe", # Turkish
66
- # :ro => "Română", # Romanian
67
- # :bg => "български" # Bulgarian
59
+ :uk => "украї́нська", # украї́нська/Ukrainian
60
+ :sr => "Српски", # Српски/Srpski/Serbian
61
+ :it => "Italiano", # Italiano/Italian
62
+ :hr => "Hrvatski", # Hrvatski/Croatian
63
+ :fr => "Français", # French
64
+ :pt => "Português", # Portuguese
65
+ :tr => "Türkçe", # Turkish
66
+ :ro => "Română", # Romanian
67
+ :bg => "български" # Bulgarian
68
68
  }
69
69
 
70
70
 
71
- # Time localization
71
+ # Define time zone, week start day, and custom date/time formats.
72
72
  config.datetime = {
73
73
  :time_zone => "America/Guatemala",
74
74
  :start_week_on => "monday",
@@ -84,9 +84,9 @@ Lesli.configure do |config|
84
84
  }
85
85
 
86
86
 
87
- # Instance security settings
87
+ # Customize system-wide security behavior.
88
88
  config.security = {
89
- password: "Test123!",
89
+ password: "Test123!", # Default password for development, test & demo environments
90
90
  enable_debug: false,
91
91
  enable_becoming: false,
92
92
  enable_analytics: true,
@@ -97,7 +97,7 @@ Lesli.configure do |config|
97
97
  }
98
98
 
99
99
 
100
- # Main color palette for Lesli
100
+ # Customize the color palette and layout.
101
101
  config.theme = {
102
102
  color_primary: "#193d8d",
103
103
  color_sidebar: "#ffffff",
@@ -110,15 +110,19 @@ Lesli.configure do |config|
110
110
 
111
111
  #
112
112
  config.layout = {
113
- locale: false
113
+ tasks: true,
114
+ babel: false,
115
+ profile: true,
116
+ notifications: true
114
117
  }
115
118
 
116
119
 
117
- #
120
+ # Specify default paths for email templates.
118
121
  config.mailer = {
119
122
  templates: "lesli_mailer/emails/lesli"
120
123
  }
121
124
 
125
+ # Control redirection paths after login.
122
126
  config.path_after_login = "/"
123
127
  config.path_after_login = "/dashboard" if defined?(LesliDashboard)
124
128
  end
@@ -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
@@ -19,7 +19,7 @@ along with this program. If not, see http://www.gnu.org/licenses/.
19
19
 
20
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
data/db/seed/users.rb CHANGED
@@ -53,12 +53,14 @@ passguest = passowner
53
53
 
54
54
 
55
55
  # build a random password for the owner, admin and guest users
56
- # only for production and only when LesliShield is installed
57
- if Rails.env.production? && defined?(LesliShield)
56
+ # only for production and only when LesliShield is installed and
57
+ # only if the "demo mode" is not active in the
58
+ # config/initializers/lesli.rb file
59
+ if Rails.env.production? && defined?(LesliShield) && !Lesli.config.demo
58
60
  passowner = LesliShield::Tokens.friendly_token
59
61
  passadmin = LesliShield::Tokens.friendly_token
60
62
  passguest = LesliShield::Tokens.friendly_token
61
- end
63
+ end
62
64
 
63
65
 
64
66
  # create the owner user for the account,
data/lib/lesli/engine.rb CHANGED
@@ -93,23 +93,9 @@ module Lesli
93
93
  # Lesli Framework Mailer configuration
94
94
 
95
95
 
96
- # Development mailer by default
97
- config.action_mailer.delivery_method ||= :letter_opener
98
-
99
96
  # Add the Lesli root folder for email development tempaltes
100
97
  config.action_mailer.preview_paths << root.join("lib", "mailer_previews")
101
98
 
102
- #
103
- config.action_mailer.default_options ||= {
104
-
105
- # Use the main email in the lesli settings as email sender
106
- from: Lesli.config.company.dig(:email)
107
- }
108
-
109
- # Mailer url options for development
110
- config.action_mailer.default_url_options ||= {
111
- host: "http://0.0.0.0:3000"
112
- }
113
99
 
114
100
  # Does not work too well
115
101
  # if Lesli.config.security.dig(:enable_debug)
data/lib/lesli/routing.rb CHANGED
@@ -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
data/lib/lesli/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Lesli
2
- VERSION = "5.0.19"
3
- BUILD = "1752589521"
2
+ VERSION = "5.0.20"
3
+ BUILD = "1754023334"
4
4
  end
@@ -36,12 +36,21 @@ require Lesli::Engine.root.join("lib/rspec/helpers/rails_helper")
36
36
  require Lesli::Engine.root.join("lib/rspec/helpers/lesli_helper")
37
37
  require Lesli::Engine.root.join("lib/rspec/helpers/response_request_helper")
38
38
 
39
- # ·
40
- LESLI_ENGINE_MOUNTED_PATH = Lesli::Engine.routes.find_script_name({}) if defined?(Lesli)
41
- LESLI_ADMIN_ENGINE_MOUNTED_PATH = LesliAdmin::Engine.routes.find_script_name({}) if defined?(LesliAdmin)
42
- LESLI_BABEL_ENGINE_MOUNTED_PATH = LesliBabel::Engine.routes.find_script_name({}) if defined?(LesliBabel)
43
- LESLI_CALENDAR_ENGINE_MOUNTED_PATH = LesliCalendar::Engine.routes.find_script_name({}) if defined?(LesliCalendar)
44
- LESLI_DASHBOARD_ENGINE_MOUNTED_PATH = LesliDashboard::Engine.routes.find_script_name({}) if defined?(LesliDashboard)
39
+
40
+ # · Dynamically build a path where the engine is mounted
41
+ def build_engine_path(engine_name, path)
42
+
43
+ # get the engine information
44
+ engine = LesliSystem.engine(engine_name)
45
+
46
+ # return the path if no engine found
47
+ return path unless engine
48
+
49
+ engine_constant = engine[:name].constantize
50
+
51
+ # build the path inside the engine mounted path
52
+ "#{engine_constant::Engine.routes.find_script_name({})}/#{path}"
53
+ end
45
54
 
46
55
 
47
56
  # · Authentication context
@@ -0,0 +1,93 @@
1
+ /*
2
+ Lesli
3
+
4
+ Copyright (c) 2025, Lesli Technologies, S. A.
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see http://www.gnu.org/licenses/.
18
+
19
+ Lesli · Ruby on Rails SaaS Development Framework.
20
+
21
+ Made with ♥ by LesliTech
22
+ Building a better future, one line of code at a time.
23
+
24
+ @contact hello@lesli.tech
25
+ @website https://www.lesli.tech
26
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
27
+
28
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
29
+ // ·
30
+ */
31
+
32
+
33
+ // ·
34
+ @use "lesli-css/sass/helpers/shadow";
35
+ @use "lesli-css/sass/helpers/breakpoint";
36
+
37
+
38
+ // ·
39
+ body.lesli.apps.show {
40
+
41
+ .lesli-element-header {
42
+ margin-bottom: 5rem !important;
43
+ }
44
+
45
+ .engines {
46
+ gap: 24px;
47
+ margin-inline-end: auto;
48
+ margin-inline-start: auto;
49
+
50
+ a {
51
+ flex-basis: 318px;
52
+ text-align: center;
53
+ padding: 2rem .4rem 2.8rem;
54
+ border: white 1px solid;
55
+ border-radius: 6px;
56
+ background-color: white;
57
+ transition: all ease-in-out .2s;
58
+
59
+ @include shadow.lesli-shadow();
60
+
61
+ &:hover {
62
+ border-color: var(--lesli-color-primary);
63
+ transform: translateY(-2px);
64
+ }
65
+
66
+ &.is-active {
67
+ background-color: #F0F4FF;
68
+ border-color: var(--lesli-color-primary);
69
+ }
70
+
71
+ // engine logo
72
+ svg {
73
+ margin-right: .4rem;
74
+ fill: var(--lesli-color-primary);
75
+ }
76
+
77
+ // engine description
78
+ p {
79
+ font-size: 14;
80
+ }
81
+
82
+ // engine name
83
+ span {
84
+ font-weight: 600;
85
+ font-size: 20px;
86
+ }
87
+
88
+ span, p {
89
+ color: var(--lesli-color-primary);
90
+ }
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,34 @@
1
+ /*
2
+ Lesli
3
+
4
+ Copyright (c) 2025, Lesli Technologies, S. A.
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see http://www.gnu.org/licenses/.
18
+
19
+ Lesli · Ruby on Rails SaaS Development Framework.
20
+
21
+ Made with ♥ by LesliTech
22
+ Building a better future, one line of code at a time.
23
+
24
+ @contact hello@lesli.tech
25
+ @website https://www.lesli.tech
26
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
27
+
28
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
29
+ // ·
30
+ */
31
+
32
+
33
+ // ·
34
+ @use "apps";
@@ -67,7 +67,7 @@ namespace :lesli do
67
67
  status()
68
68
  end
69
69
 
70
- desc "Seed & prepare Lesli database (development only)"
70
+ desc "Seed & prepare Lesli database"
71
71
  task :seed => :environment do |task, args|
72
72
  seed()
73
73
  status()
@@ -88,5 +88,8 @@ namespace :lesli do
88
88
  L2.table(engines)
89
89
  L2.br(2)
90
90
 
91
+ L2.m Rails.env
92
+ L2.br(2)
93
+
91
94
  end
92
95
  end
data/readme.md CHANGED
@@ -73,20 +73,19 @@ bundle add lesli
73
73
  ```
74
74
 
75
75
  ```shell
76
- # Setup database for production
77
- rake lesli:db:setup
78
-
76
+ # Add Lesli to your app
77
+ rails generate lesli:install
78
+ ```
79
+ ```shell
79
80
  # Setup database for development
80
81
  rake lesli:db:dev
81
82
  ```
82
-
83
- ```ruby
84
- # mount lesli platform
85
- Rails.application.routes.draw do
86
- Lesli::Routing.mount
87
- end
83
+ ```shell
84
+ # Start your app
85
+ rails server
88
86
  ```
89
87
 
88
+
90
89
  <br />
91
90
 
92
91
 
@@ -107,7 +106,7 @@ bundle install
107
106
  ```
108
107
  ```shell
109
108
  # Generate Lesli initializer
110
- rails g lesli:install
109
+ rails generate lesli:install
111
110
  ```
112
111
  ```shell
113
112
  # Hard reset Database for development:
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lesli
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.19
4
+ version: 5.0.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Lesli Development Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-15 00:00:00.000000000 Z
11
+ date: 2025-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '8.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '8.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: i18n-js
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -28,16 +42,16 @@ dependencies:
28
42
  name: importmap-rails
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - ">="
45
+ - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '0'
47
+ version: 2.2.0
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - ">="
52
+ - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '0'
54
+ version: 2.2.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: turbo-rails
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -164,7 +178,8 @@ dependencies:
164
178
  - - "~>"
165
179
  - !ruby/object:Gem::Version
166
180
  version: '0.6'
167
- description: Ruby on Rails SaaS Development Framework.
181
+ description: Lesli is a SaaS development framework designed to build highly scalable,
182
+ secure and customizable software products.
168
183
  email:
169
184
  - hello@lesli.tech
170
185
  executables: []
@@ -248,6 +263,8 @@ files:
248
263
  - app/views/lesli/abouts/welcome.html.erb
249
264
  - app/views/lesli/apps/show.html.erb
250
265
  - app/views/lesli/emails/user_mailer/invitation.html.erb
266
+ - app/views/lesli/errors/not_found.html.erb
267
+ - app/views/lesli/errors/unauthorized.html.erb
251
268
  - app/views/lesli/layouts/application-devise.html.erb
252
269
  - app/views/lesli/layouts/application-lesli.html.erb
253
270
  - app/views/lesli/layouts/application-public.html.erb
@@ -276,6 +293,7 @@ files:
276
293
  - app/views/lesli/wrappers/_application-devise.html.erb
277
294
  - config/importmap.rb
278
295
  - config/initializers/devise.rb
296
+ - config/initializers/devise_rails_8_patch.rb
279
297
  - config/initializers/lesli.rb
280
298
  - config/initializers/lesli_migration_helpers.rb
281
299
  - config/locales/devise.en.yml
@@ -362,6 +380,8 @@ files:
362
380
  - lib/rspec/testers/controller.rb
363
381
  - lib/rspec/testers/model.rb
364
382
  - lib/rspec/testers/request.rb
383
+ - lib/scss/_apps.scss
384
+ - lib/scss/application.scss
365
385
  - lib/tasks/lesli/controllers.rake
366
386
  - lib/tasks/lesli/db.rake
367
387
  - lib/tasks/lesli/dev.rake
@@ -389,7 +409,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
389
409
  requirements:
390
410
  - - ">="
391
411
  - !ruby/object:Gem::Version
392
- version: '2.7'
412
+ version: '3.2'
393
413
  required_rubygems_version: !ruby/object:Gem::Requirement
394
414
  requirements:
395
415
  - - ">="