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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/lesli/application.css +1 -0
- data/app/helpers/lesli/navigation_helper.rb +6 -0
- data/app/interfaces/lesli/responder_interface.rb +35 -19
- data/app/models/concerns/account_initializer.rb +2 -3
- data/app/models/concerns/user_security.rb +5 -4
- data/app/models/lesli/role/action.rb +3 -2
- data/app/models/lesli/shared/dashboard.rb +2 -2
- data/app/models/lesli/user/session.rb +1 -1
- data/app/operators/lesli/role_operator.rb +9 -4
- data/app/services/lesli/role/action_service.rb +2 -3
- data/app/views/lesli/abouts/welcome.html.erb +8 -5
- data/app/views/lesli/apps/show.html.erb +21 -33
- data/app/views/lesli/errors/not_found.html.erb +32 -0
- data/app/views/lesli/errors/unauthorized.html.erb +48 -0
- data/app/views/lesli/layouts/application-lesli.html.erb +1 -2
- data/app/views/lesli/partials/_application-analytics.html.erb +2 -2
- data/app/views/lesli/partials/_application-lesli-header.html.erb +60 -65
- data/app/views/lesli/partials/_application-lesli-navigation.html.erb +23 -5
- data/config/importmap.rb +0 -10
- data/config/initializers/devise_rails_8_patch.rb +8 -0
- data/config/initializers/lesli.rb +27 -23
- data/db/migrate/v1/0000120310_create_lesli_role_privileges.rb +2 -2
- data/db/seed/users.rb +5 -3
- data/lib/lesli/engine.rb +0 -14
- data/lib/lesli/routing.rb +1 -1
- data/lib/lesli/version.rb +2 -2
- data/lib/rspec/testers/request.rb +15 -6
- data/lib/scss/_apps.scss +93 -0
- data/lib/scss/application.scss +34 -0
- data/lib/tasks/lesli/db.rake +1 -1
- data/lib/tasks/lesli_tasks.rake +3 -0
- data/readme.md +9 -10
- metadata +28 -8
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 126a19d2153659244f65bb4a49db4618786defe3328e86f2d7217bea1fb66ffb
         | 
| 4 | 
            +
              data.tar.gz: 89b09d6eec6bb3e320c2eb09e07ae50011d047cf12668479c1565a117954506f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 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)  | 
| 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 ·  | 
| 20 | 
            +
            Lesli · Ruby on Rails SaaS Development Framework.
         | 
| 21 21 |  | 
| 22 | 
            -
            Made with ♥ by  | 
| 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 | 
            -
             | 
| 77 | 
            -
             | 
| 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 | 
| 86 | 
            -
             | 
| 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 | 
            -
                         | 
| 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 | 
| 92 | 
            -
                            format.html | 
| 93 | 
            -
             | 
| 94 | 
            -
                            # format.xlsx  | 
| 95 | 
            -
                            #  | 
| 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). | 
| 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", " | 
| 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  | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 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 | 
            -
                     | 
| 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. | 
| 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 <  | 
| 43 | 
            +
                    class Dashboard < base_class
         | 
| 44 44 | 
             
                        self.abstract_class = true
         | 
| 45 45 | 
             
                    end
         | 
| 46 46 | 
             
                end
         | 
| @@ -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  | 
| 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 | 
            -
                             | 
| 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  | 
| 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  | 
| 24 | 
            -
                    radial-gradient(#0d52bf  | 
| 25 | 
            -
                    animation: rotateBackground  | 
| 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 | 
            -
                 | 
| 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 | 
            -
             | 
| 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 | 
            -
                     | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 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 | 
            -
                 | 
| 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, : | 
| 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 | 
            -
                <%  | 
| 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 | 
            -
            <%#  | 
| 34 | 
            -
            <%  | 
| 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 | 
            -
                < | 
| 47 | 
            -
                    < | 
| 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  | 
| 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 | 
            -
                             | 
| 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 | 
            -
                                     | 
| 73 | 
            -
                                         | 
| 74 | 
            -
             | 
| 75 | 
            -
                                             | 
| 76 | 
            -
                                             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 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 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 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 | 
            -
             | 
| 114 | 
            -
             | 
| 92 | 
            +
                                <!-- app selector -->
         | 
| 93 | 
            +
                                <div class="navbar-item">
         | 
| 94 | 
            +
                                    <%= navigation_link(lesli.apps_path, nil, "ri-apps-2-line") %>
         | 
| 95 | 
            +
                                </div>
         | 
| 115 96 |  | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 97 | 
            +
                                <!-- user profile -->
         | 
| 98 | 
            +
                                <div class="navbar-item">
         | 
| 99 | 
            +
                                    <%= navigation_link(lesli.apps_path, nil, "ri-user-smile-line") %>
         | 
| 100 | 
            +
                                </div>
         | 
| 118 101 |  | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 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  | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 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__)
         | 
| @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            Lesli
         | 
| 4 4 |  | 
| 5 | 
            -
            Copyright (c)  | 
| 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  | 
| 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 | 
            -
                #  | 
| 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 | 
            -
                #  | 
| 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 | 
            -
                #  | 
| 52 | 
            +
                # List of supported languages (requires `LesliBabel`).
         | 
| 53 53 | 
             
                config.locales = {
         | 
| 54 54 | 
             
                    :en => "English",       # English
         | 
| 55 | 
            -
                    :de => "Deutsch", | 
| 56 | 
            -
                     | 
| 57 | 
            -
                     | 
| 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 | 
            -
                     | 
| 60 | 
            -
                     | 
| 61 | 
            -
                    :it => "Italiano", | 
| 62 | 
            -
                     | 
| 63 | 
            -
                     | 
| 64 | 
            -
                     | 
| 65 | 
            -
                     | 
| 66 | 
            -
                     | 
| 67 | 
            -
                     | 
| 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 | 
            -
                #  | 
| 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 | 
            -
                #  | 
| 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 | 
            -
                #  | 
| 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 | 
            -
                     | 
| 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)  | 
| 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  | 
| 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  | 
| 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
    
    
    
        data/lib/lesli/version.rb
    CHANGED
    
    
| @@ -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 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 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
         | 
    
        data/lib/scss/_apps.scss
    ADDED
    
    | @@ -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";
         | 
    
        data/lib/tasks/lesli/db.rake
    CHANGED
    
    
    
        data/lib/tasks/lesli_tasks.rake
    CHANGED
    
    
    
        data/readme.md
    CHANGED
    
    | @@ -73,20 +73,19 @@ bundle add lesli | |
| 73 73 | 
             
            ```
         | 
| 74 74 |  | 
| 75 75 | 
             
            ```shell
         | 
| 76 | 
            -
            #  | 
| 77 | 
            -
             | 
| 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 | 
            -
             | 
| 84 | 
            -
             | 
| 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  | 
| 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. | 
| 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- | 
| 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:  | 
| 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:  | 
| 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:  | 
| 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 | 
| 412 | 
            +
                  version: '3.2'
         | 
| 393 413 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 394 414 | 
             
              requirements:
         | 
| 395 415 | 
             
              - - ">="
         |