lesli 5.0.21 → 5.0.23

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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -0
  3. data/app/assets/config/lesli_manifest.js +2 -2
  4. data/app/assets/images/lesli/brand/register-background.jpg +0 -0
  5. data/app/assets/stylesheets/lesli/application.css +192 -1
  6. data/app/controllers/lesli/abouts_controller.rb +12 -13
  7. data/app/controllers/lesli/application_controller.rb +1 -42
  8. data/app/controllers/lesli/application_lesli_controller.rb +8 -1
  9. data/app/controllers/lesli/apps_controller.rb +25 -0
  10. data/app/controllers/lesli/items/actions_controller.rb +122 -0
  11. data/app/{models/lesli/item/activity.rb → controllers/lesli/items/activities_controller.rb} +2 -2
  12. data/app/controllers/lesli/items/discussions_controller.rb +93 -0
  13. data/app/controllers/lesli/{system_controllers_controller.rb → resources_controller.rb} +3 -3
  14. data/app/controllers/lesli/shared/dashboards_controller.rb +11 -279
  15. data/app/helpers/lesli/customization_helper.rb +3 -3
  16. data/app/helpers/lesli/html_helper.rb +114 -2
  17. data/app/helpers/lesli/navigation_helper.rb +8 -25
  18. data/app/helpers/lesli/system_helper.rb +21 -4
  19. data/app/helpers/lesli/turbo_helper.rb +19 -2
  20. data/app/interfaces/lesli/requester_interface.rb +2 -29
  21. data/app/interfaces/lesli/responder_interface.rb +121 -61
  22. data/app/models/concerns/lesli/account_initializer.rb +13 -13
  23. data/{lib/rspec/factories/lesli_account.rb → app/models/concerns/lesli/account_logs.rb} +23 -9
  24. data/app/models/concerns/lesli/user_extensions.rb +33 -51
  25. data/app/models/lesli/account.rb +6 -5
  26. data/app/models/lesli/application_lesli_record.rb +14 -0
  27. data/app/models/lesli/items/action.rb +15 -0
  28. data/app/models/lesli/items/activity.rb +50 -0
  29. data/app/models/lesli/items/discussion.rb +15 -0
  30. data/app/models/lesli/{user/journal.rb → resource.rb} +9 -4
  31. data/app/models/lesli/role.rb +2 -17
  32. data/app/models/lesli/shared/dashboard.rb +1 -0
  33. data/app/models/lesli/user.rb +23 -77
  34. data/app/services/lesli/application_lesli_service.rb +21 -4
  35. data/app/{operators/lesli/controller_operator.rb → services/lesli/resource_service.rb} +92 -23
  36. data/app/services/lesli/role_service.rb +16 -10
  37. data/app/services/lesli/user_service.rb +28 -27
  38. data/app/views/lesli/abouts/welcome.html.erb +11 -11
  39. data/app/views/lesli/apps/show.html.erb +1 -1
  40. data/app/views/lesli/errors/not_found.html.erb +1 -1
  41. data/app/views/lesli/errors/unauthorized.html.erb +9 -11
  42. data/app/views/lesli/layouts/application-devise.html.erb +6 -9
  43. data/app/views/lesli/layouts/application-lesli.html.erb +9 -9
  44. data/app/views/lesli/layouts/application-public.html.erb +4 -18
  45. data/app/views/lesli/layouts/mailer.html.erb +1 -1
  46. data/app/views/lesli/partials/{_application-analytics.html.erb → _application-lesli-analytics.html.erb} +18 -9
  47. data/app/views/lesli/partials/{_application-lesli-scss.html.erb → _application-lesli-assets.html.erb} +9 -11
  48. data/{db/migrate/v1/0000110310_create_lesli_account_settings.rb → app/views/lesli/partials/_application-lesli-data.html.erb} +11 -7
  49. data/app/views/lesli/partials/{_application-head.html.erb → _application-lesli-head.html.erb} +2 -2
  50. data/app/views/lesli/partials/_application-lesli-header.html.erb +6 -6
  51. data/app/views/lesli/partials/_application-lesli-navigation.html.erb +3 -6
  52. data/app/views/lesli/partials/_application-lesli-notifications.html.erb +0 -1
  53. data/app/views/lesli/partials/turbo/_redirection.html.erb +5 -0
  54. data/app/views/lesli/{partials/_application-data.html.erb → shared/dashboards/edit.html.erb} +2 -6
  55. data/app/views/lesli/shared/dashboards/{_show.html.erb → show.html.erb} +3 -3
  56. data/config/brakeman.yml +55 -0
  57. data/config/importmap.rb +0 -3
  58. data/config/initializers/devise.rb +1 -2
  59. data/config/initializers/lesli.rb +27 -14
  60. data/config/initializers/lesli_migration_helpers.rb +0 -5
  61. data/config/locales/translations.en.yml +6 -2
  62. data/config/locales/translations.es.yml +5 -2
  63. data/config/locales/translations.fr.yml +1 -4
  64. data/config/locales/translations.it.yml +5 -2
  65. data/config/locales/translations.pt.yml +1 -4
  66. data/config/routes.rb +4 -6
  67. data/db/migrate/v1/{0000000310_create_lesli_users.rb → 0000000210_create_lesli_users.rb} +4 -0
  68. data/db/migrate/v1/{0000000210_create_lesli_roles.rb → 0000000310_create_lesli_roles.rb} +6 -0
  69. data/db/migrate/v1/{0000100110_create_lesli_system_controllers.rb → 0000000410_create_lesli_resources.rb} +8 -5
  70. data/db/seed/users.rb +1 -1
  71. data/db/seed/xyz.rb +3 -1
  72. data/lib/generators/lesli/spec/spec_generator.rb +0 -3
  73. data/lib/generators/lesli/view/view_generator.rb +0 -3
  74. data/lib/lesli/configuration.rb +1 -1
  75. data/{app/lib → lib}/lesli/courier.rb +40 -7
  76. data/lib/lesli/engine.rb +4 -5
  77. data/lib/lesli/{routing.rb → router.rb} +3 -2
  78. data/lib/lesli/version.rb +2 -2
  79. data/lib/lesli.rb +3 -2
  80. data/lib/migrate/common.rb +2 -0
  81. data/lib/migrate/items/action_structure.rb +2 -1
  82. data/lib/migrate/items/activity_structure.rb +12 -2
  83. data/lib/migrate/items/discussion_structure.rb +1 -1
  84. data/lib/scss/_apps.scss +1 -0
  85. data/lib/tasks/lesli/db.rake +5 -5
  86. data/lib/tasks/lesli/{controllers.rake → resources.rake} +4 -4
  87. data/lib/tasks/lesli_tasks.rake +13 -3
  88. data/lib/test/config.rb +111 -0
  89. data/{db/migrate/v1/0000130210_create_lesli_user_roles.rb → lib/test/helpers/response_integration_helper.rb} +12 -9
  90. data/{db/migrate/v1/0000100210_create_lesli_system_controller_actions.rb → lib/test/lesli.rb} +28 -9
  91. data/readme.md +61 -68
  92. metadata +49 -121
  93. data/app/helpers/lesli/assets_helper.rb +0 -110
  94. data/app/helpers/lesli/general_helper.rb +0 -96
  95. data/app/mailers/lesli/devise_mailer.rb +0 -67
  96. data/app/models/concerns/lesli/has_activities.rb +0 -29
  97. data/app/models/concerns/lesli/user_activities.rb +0 -163
  98. data/app/models/concerns/lesli/user_security.rb +0 -220
  99. data/app/models/lesli/account/detail.rb +0 -37
  100. data/app/models/lesli/account/log.rb +0 -57
  101. data/app/models/lesli/account/request.rb +0 -37
  102. data/app/models/lesli/descriptor/privilege.rb +0 -39
  103. data/app/models/lesli/descriptor.rb +0 -57
  104. data/app/models/lesli/role/action.rb +0 -73
  105. data/app/models/lesli/role/privilege.rb +0 -38
  106. data/app/models/lesli/system_controller/action.rb +0 -37
  107. data/app/models/lesli/system_controller.rb +0 -104
  108. data/app/models/lesli/user/activity.rb +0 -5
  109. data/app/models/lesli/user/detail.rb +0 -55
  110. data/app/models/lesli/user/request.rb +0 -38
  111. data/app/models/lesli/user/role.rb +0 -39
  112. data/app/models/lesli/user/session.rb +0 -79
  113. data/app/models/lesli/user/setting.rb +0 -46
  114. data/app/operators/lesli/role_operator.rb +0 -153
  115. data/app/services/lesli/role/action_service.rb +0 -75
  116. data/app/services/lesli/user/session_service.rb +0 -78
  117. data/app/validators/lesli/application_lesli_validator.rb +0 -67
  118. data/app/validators/lesli/users_validator.rb +0 -217
  119. data/app/views/lesli/emails/user_mailer/invitation.html.erb +0 -23
  120. data/app/views/lesli/partials/_application-lesli-annoouncements.html.erb +0 -49
  121. data/app/views/lesli/partials/_application-lesli-chatbox.html.erb +0 -35
  122. data/app/views/lesli/partials/_application-lesli-javascript.html.erb +0 -48
  123. data/app/views/lesli/partials/_application-lesli-panels.html.erb +0 -58
  124. data/app/views/lesli/partials/_application-public-footer.html.erb +0 -51
  125. data/app/views/lesli/partials/_application-public-javascript.html.erb +0 -49
  126. data/app/views/lesli/partials/_application-public-scss.html.erb +0 -35
  127. data/app/views/lesli/shared/dashboards/_edit.html.erb +0 -33
  128. data/app/views/lesli/wrappers/_application-devise-simple.erb +0 -59
  129. data/app/views/lesli/wrappers/_application-devise.html.erb +0 -76
  130. data/config/initializers/devise_rails_8_patch.rb +0 -8
  131. data/db/migrate/v1/0000110210_create_lesli_account_details.rb +0 -70
  132. data/db/migrate/v1/0000110410_create_lesli_account_activities.rb +0 -37
  133. data/db/migrate/v1/0000120210_create_lesli_role_actions.rb +0 -45
  134. data/db/migrate/v1/0000120310_create_lesli_role_privileges.rb +0 -45
  135. data/db/migrate/v1/0000130310_create_lesli_user_sessions.rb +0 -56
  136. data/db/migrate/v1/0000130410_create_lesli_user_activities.rb +0 -37
  137. data/db/migrate2/0000100510_create_lesli_account_locations.rb +0 -64
  138. data/db/migrate2/0000100610_create_lesli_account_currencies.rb +0 -48
  139. data/lib/assets/javascripts/lesli/i18n_js +0 -1095
  140. data/lib/migrate/shared/dashboard_structure.rb +0 -54
  141. data/lib/migrate/shared/setting_structure.rb +0 -20
  142. data/lib/rspec/config/spec_coverage.rb +0 -95
  143. data/lib/rspec/factories/lesli_role.rb +0 -62
  144. data/lib/rspec/factories/lesli_user.rb +0 -64
  145. data/lib/rspec/fixtures/files/lesli-icon.png +0 -0
  146. data/lib/rspec/fixtures/files/test_file_1.docx +0 -0
  147. data/lib/rspec/helpers/lesli_helper.rb +0 -54
  148. data/lib/rspec/helpers/rails_helper.rb +0 -134
  149. data/lib/rspec/helpers/response_request_helper.rb +0 -214
  150. data/lib/rspec/helpers/response_service_helper.rb +0 -66
  151. data/lib/rspec/helpers/spec_helper.rb +0 -99
  152. data/lib/rspec/lesli_api_tester.rb +0 -133
  153. data/lib/rspec/lesli_service_tester.rb +0 -46
  154. data/lib/rspec/testers/controller.rb +0 -63
  155. data/lib/rspec/testers/model.rb +0 -36
  156. data/lib/rspec/testers/request.rb +0 -93
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2023, Lesli Technologies, S. A.
5
+ Copyright (c) 2026, 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
@@ -29,288 +29,20 @@ Building a better future, one line of code at a time.
29
29
  // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
30
  // ·
31
31
  =end
32
+
32
33
  module Lesli
33
34
  module Shared
34
- class DashboardsController < ApplicationLesliController
35
- #before_action :set_dashboard, only: [:show, :update, :destroy, :options]
36
-
37
- def edit
38
- end
39
-
40
- def show
41
- builder = LesliSystem::Klass.new(self)
42
- @dashboard = builder.model.dashboard.first
43
- end
44
-
45
- # def index
46
- # respond_to do |format|
47
- # format.html {}
48
- # format.json do
49
- # dynamic_info = self.class.dynamic_info
50
- # model = dynamic_info[:model]
51
-
52
- # dashboards = model.list(current_user, @query)
53
- # respond_with_successful(dashboards)
54
- # end
55
- # end
56
- # end
57
-
58
- # def show
59
- # respond_to do |format|
60
- # format.html {}
61
- # format.json do
62
- # return respond_with_not_found unless @dashboard
63
- # respond_with_successful(@dashboard.show)
64
- # end
65
- # end
66
- # end
67
-
68
- # def new
69
- # end
70
-
71
- # def edit
72
- # end
73
-
74
- # # @controller_action_param :name [String] The name of the new dashboard
75
- # # @controller_action_param :default [Boolean] A flag that marks this dashboard as default or not. The default dashboard is the dashboard all users will have access to on the root page
76
- # # @controller_action_param :main [Boolean] A flag that marks this dashboard as main. Since a user can have multiple dashboards, this is the one they will see on the root page when loging in
77
- # # @controller_action_param :roles_id [Integer] The id of the role that will have access to this dashboard
78
- # # @controller_action_param :user_main_id [Integer] The id of the user
79
- # # @controller_action_param :component_attributes [Array] Array of hashes that represent the attributes of the dashboard components
80
- # # @controller_action_param :component_attributes.name [String] The name of this component given to the user
81
- # # @controller_action_param :component_attributes.component_id [String] An enum value, that indicates which component is being loaded
82
- # # @controller_action_param :component_attributes.layout [Integer] Number from 1 to 12, bigger numbers default to 12, smallest numbers default to 1. The column size that the UI component will use
83
- # # @controller_action_param :component_attributes.index [Integer] The position of the component in the layout
84
- # # @controller_action_param :component_attributes.configuration [Hash] Specific filtering and configuration of the components
85
- # # @return [Json] Json that contains wheter the creation of the dashboard was successful or not.
86
- # # If it is not successful, it returns an error message
87
- # # @description Creates a new dashboard associated to the *current_user*'s *account*
88
- # # @example
89
- # # # Executing this controller's action from javascript's frontend
90
- # # let data = {
91
- # # dashboard: {
92
- # # name: "Sales Dashboard",
93
- # # default: false,
94
- # # roles_id: 3,
95
- # # components_attributes: [
96
- # # {
97
- # # name: 'Projects Count',
98
- # # component_id: projects_component,
99
- # # layout: 4,
100
- # # index: 3,
101
- # # configuration: {}
102
- # # }, {
103
- # # name: 'New Customers Count',
104
- # # component_id: new_customers_component,
105
- # # layout: 4,
106
- # # index: 3,
107
- # # configuration: {}
108
- # # }
109
- # # ]
110
- # # }
111
- # # };
112
- # # this.http.post('127.0.0.1/help/dashboards', data);
113
- # def create
114
- # dynamic_info = self.class.dynamic_info
115
- # module_name = dynamic_info[:module_name]
116
- # model = dynamic_info[:model]
117
- # full_module_name = dynamic_info[:full_module_name].underscore
118
-
119
- # dashboard = model.new(dashboard_params)
120
- # dashboard["#{full_module_name}_account_id".to_sym] = current_user.account.id
121
- # dashboard.user_creator = current_user
122
-
123
- # if dashboard.save
124
- # respond_with_successful(dashboard)
125
- # else
126
- # respond_with_error(dashboard.errors.full_messages.to_sentence)
127
- # end
128
- # end
129
-
130
- # # @controller_action_param :name [String] The name of the new dashboard
131
- # # @controller_action_param :default [Boolean] A flag that marks this dashboard as default or not. The default dashboard is the dashboard all users will have access to on the root page
132
- # # @controller_action_param :main [Boolean] A flag that marks this dashboard as main. Since a user can have multiple dashboards, this is the one they will see on the root page when loging in
133
- # # @controller_action_param :roles_id [Integer] The id of the role that will have access to this dashboard
134
- # # @controller_action_param :user_main_id [Integer] The id of the user
135
- # # @controller_action_param :component_attributes [Array] Array of hashes that represent the attributes of the dashboard components
136
- # # @controller_action_param :component_attributes.name [String] The name of this component given to the user
137
- # # @controller_action_param :component_attributes.component_id [String] An enum value, that indicates which component is being loaded
138
- # # @controller_action_param :component_attributes.layout [Integer] Number from 1 to 12, bigger numbers default to 12, smallest numbers default to 1. The column size that the UI component will use
139
- # # @controller_action_param :component_attributes.index [Integer] The position of the component in the layout
140
- # # @controller_action_param :component_attributes.configuration [Hash] Specific filtering and configuration of the components
141
- # # @return [Json] Json that contains wheter the dashboard was successfully updated or not.
142
- # # If it it not successful, it returns an error message
143
- # # @description Updates an existing dashboard associated to the *current_user*'s *account*.
144
- # # @example
145
- # # # Executing this controller's action from javascript's frontend
146
- # # let dashboard_id = 4;
147
- # # let data = {
148
- # # dashboard: {
149
- # # name: "Sales Dashboard",
150
- # # default: false,
151
- # # roles_id: 3,
152
- # # components_attributes: [
153
- # # {
154
- # # name: 'Projects Count',
155
- # # component_id: projects_component,
156
- # # layout: 4,
157
- # # index: 3,
158
- # # configuration: {}
159
- # # }, {
160
- # # name: 'New Customers Count',
161
- # # component_id: new_customers_component,
162
- # # layout: 4,
163
- # # index: 3,
164
- # # configuration: {}
165
- # # }
166
- # # ]
167
- # # }
168
- # # };
169
- # # this.http.put(`127.0.0.1/help/dashboards/${dashboard_id}`, data);
170
- # def update
171
- # return respond_with_not_found unless @dashboard
172
-
173
- # if @dashboard.update(dashboard_params)
174
- # respond_with_successful(@dashboard.show)
175
- # else
176
- # respond_with_error(@dashboard.errors.full_messages.to_sentence)
177
- # end
178
- # end
179
-
180
- # # @return [Json] Json that contains wheter the dashboard was successfully deleted or not.
181
- # # If it it not successful, it returns an error message
182
- # # @description Deletes an existing *dashboard* associated to the *current_user*'s *account*.
183
- # # Since the dashboard has details, these are also deleted. However, if there
184
- # # is an existing *cloud_object* associated to the *dashboard*, it cannot be deleted
185
- # # @example
186
- # # # Executing this controller's action from javascript's frontend
187
- # # let dashboard_id = 4;
188
- # # this.http.delete(`127.0.0.1/help/dashboards/${dashboard_id}`);
189
- # def destroy
190
- # return respond_with_not_found unless @dashboard
191
-
192
- # if @dashboard.destroy
193
- # respond_with_successful
194
- # else
195
- # respond_with_error(@dashboard.errors.full_messages.to_sentence)
196
- # end
197
- # end
198
35
 
199
- # def options
200
- # dynamic_info = self.class.dynamic_info
201
- # model = dynamic_info[:module_model]
36
+ # Try to create an instance of the main controller from the engine
37
+ DASH = "::LesliDashboard::Shared::DashboardsController".safe_constantize
202
38
 
203
- # respond_with_successful(model.options(current_user, @query))
204
- # end
205
-
206
- # def resource_component
207
- # dynamic_info = self.class.dynamic_info
208
- # component_model = dynamic_info[:component_model]
209
-
210
- # component_id = sanitize(params[:component_id].to_sym)
211
-
212
- # # We verify if the method exists, and if it is in the available component list
213
- # if component_model.respond_to?(component_id) && component_model.component_ids[component_id]
214
- # respond_with_successful(component_model.public_send(component_id, current_user, @query))
215
- # else
216
- # respond_with_not_found()
217
- # end
218
- # end
219
-
220
- # private
221
-
222
- # # @return [void]
223
- # # @description Sets the variable @dashboard. The variable contains the *cloud_object* *dashboard*
224
- # # to be handled by the controller action that called this method
225
- # # @example
226
- # # #suppose params[:id] = 1
227
- # # puts @dashboard # will display nil
228
- # # set_dashboard
229
- # # puts @dashboard # will display an instance of CloudHelp:TicketDashboard
230
- # def set_dashboard
231
- # dynamic_info = self.class.dynamic_info
232
-
233
- # model = dynamic_info[:module_model]
234
- # module_name = dynamic_info[:module_name]
235
- # module_name_full = dynamic_info[:module_name_full].underscore
236
-
237
- # # When params[:id] is 'default' order of priority is:
238
- # # Main dashboard for user goes first
239
- # # Main dashboard for role goes second
240
- # # Default dashboard goes third
241
- # if params[:id] == "default"
242
- # # Main dashboard for user
243
- # @dashboard = model.find_by(
244
- # #"#{full_module_name}_account_id".to_sym => current_user.account.id,
245
- # account_id: current_user.account.id,
246
- # main: true,
247
- # #user_main_id: current_user.id
248
- # )
249
-
250
- # return if @dashboard
251
-
252
- # # Main dashboard for role
253
- # # @dashboard = model.find_by(
254
- # # :account_id => current_user.account.id,
255
- # # role_id: current_user.roles.first.id
256
- # # )
257
- # # return if @dashboard
258
-
259
- # # Default dashboard
260
- # @dashboard = model.find_by(
261
- # account_id: current_user.account.id,
262
- # default: true
263
- # )
264
- # else
265
- # @dashboard = model.find_by(
266
- # id: params[:id],
267
- # :account_id => current_user.account.id,
268
- # )
269
- # end
270
- # end
271
-
272
- # def dashboard_params
273
- # params.require(:dashboard).permit(
274
- # :name,
275
- # :default,
276
- # :roles_id,
277
- # components_attributes: [
278
- # :id,
279
- # :name,
280
- # :component_id,
281
- # :layout,
282
- # :index,
283
- # {query_configuration: {}},
284
- # {custom_configuration: {}},
285
- # :_destroy
286
- # ]
287
- # )
288
- # end
289
-
290
- # private
291
-
292
- # # Build the Rails models and engine information for
293
- # # the current engine implementing the shared dashboards
294
- # # Example: For the LesliAudit engine
295
- # # {
296
- # # :module_name => "audit",
297
- # # :module_name_full => "LesliAudit",
298
- # # :module_model => "LesliAudit::Dashboard",
299
- # # :module_model_component => "LesliAudit::Dashboard::Component"
300
- # # }
301
- # def self.dynamic_info
302
-
303
- # module_info = self.name.split("::")
39
+ # Create a dummy contoller if the LesliDashboard controller is not installed
40
+ class DashboardsFallbackController < ApplicationLesliController
41
+ end
304
42
 
305
- # module_name = module_info[0].sub("Lesli", "").downcase
306
-
307
- # {
308
- # module_name: module_name,
309
- # module_name_full: module_info[0],
310
- # module_model: "#{ module_info[0] }::Dashboard".constantize,
311
- # module_model_component: "#{ module_info[0] }::Dashboard::Component".constantize
312
- # }
313
- # end
43
+ # Inherit from the available controller from
44
+ # LesliDashboard if installed or use dummy controller to avoid any error
45
+ class DashboardsController < DASH || DashboardsFallbackController
314
46
  end
315
47
  end
316
48
  end
@@ -48,13 +48,13 @@ module Lesli
48
48
  logo_path = "#{lesli_instance_code}/brand/#{logo}.svg"
49
49
 
50
50
  # load favicon as PNG for better compatibility between web browsers
51
- logo_path = "#{lesli_instance_code}/brand/#{logo}.png" if logo == "favicon"
51
+ #logo_path = "#{lesli_instance_code}/brand/#{logo}.png" if logo == "favicon"
52
52
 
53
53
  # loading logo from core, only if builder engine was not installed
54
- logo_path = "lesli/brand/#{logo}.svg" if lesli_instance_code == "lesli"
54
+ #logo_path = "lesli/brand/#{logo}.svg" if lesli_instance_code == "lesli"
55
55
 
56
56
  # custom logo from settings
57
- logo_path = @lesli[:customization][:logos][logo.to_sym] if @lesli.dig(:customization, :logos, logo.to_sym)
57
+ #logo_path = @lesli[:customization][:logos][logo.to_sym] if @lesli.dig(:customization, :logos, logo.to_sym)
58
58
 
59
59
  if mode == "pdf"
60
60
  wicked_pdf_image_tag(logo_path, options)
@@ -1,8 +1,120 @@
1
+ =begin
2
+
3
+ Lesli
4
+
5
+ Copyright (c) 2026, Lesli Technologies, S. A.
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see http://www.gnu.org/licenses/.
19
+
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
+
22
+ Made with ♥ by LesliTech
23
+ Building a better future, one line of code at a time.
24
+
25
+ @contact hello@lesli.tech
26
+ @website https://www.lesli.tech
27
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
+
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
+ =end
1
32
 
2
33
  module Lesli
3
34
  module HtmlHelper
4
- def turbo_link_to body, url, html_options = {}
5
- link_to(body, url, class: "link", data: { turbo_frame: '_top' })
35
+
36
+ # Prints link tags to add favicon to websites
37
+ def lesli_favicon
38
+ icon_path = image_url("lesli/brand/favicon.svg")
39
+ safe_join([
40
+ tag.link(href: icon_path, rel: "alternate icon"),
41
+ tag.link(href: icon_path, rel: "icon", type: "image/svg+xml"),
42
+ tag.link(href: icon_path, rel: "mask-icon", color: "#ff8a01")
43
+ ])
44
+ end
45
+
46
+ # build the text for the html document title
47
+ # this helper works only for rails pages, for vue apps the title must be handled with JS
48
+ def lesli_website_title
49
+ # Use instance variable if set, otherwise construct a dynamic title
50
+ title = @application_html_title || controller_path.delete_prefix("lesli_")
51
+
52
+ # Append action name unless it's "index"
53
+ title += "/#{action_name}" unless action_name == "index"
54
+
55
+ # Append company name if present
56
+ title += " · #{Lesli.config.company.dig(:name)}"
57
+
58
+ title
59
+ end
60
+
61
+ # build description using custom data from controller or engine gem description
62
+ def lesli_website_meta_description
63
+ # if want to get description from gem you can use:
64
+ # Gem::Specification.find_by_name(engine_name).description
65
+ # Gem::Specification.find_by_name(engine_name).summary
66
+ @application_html_description || ""
67
+ end
68
+
69
+ # return a string with a css class to identify the body
70
+ # example: builder engine-controller action
71
+ def lesli_application_body_class
72
+ [lesli_instance_code, controller_path.sub("_","-").split("/"), action_name].join(" ")
73
+ end
74
+
75
+ # Return a string path to load the template stylesheet
76
+ # by default we always return the latest version of the template
77
+ #
78
+ # stylesheet from main App
79
+ # lesli_stylesheet_path()
80
+ # /assets/application.css
81
+ #
82
+ # Specific stylesheet from Engine
83
+ # lesli_stylesheet_path(:lesli, 'application')
84
+ # /assets/lesli/application.css
85
+ #
86
+ # Specific stylesheet from gem
87
+ # lesli_stylesheet_path(:lesli_assets, 'templates/application')
88
+ # /assets/lesli_assets/templates/application.css
89
+ def lesli_stylesheet_path(engine = nil, stylesheet = 'application')
90
+
91
+ # Stylesheets from specific engine
92
+ return "#{engine}/#{stylesheet}" if engine.present?
93
+
94
+ # Get current engine information
95
+ engine_code = lesli_engine(:code)
96
+
97
+ # Rails main host app stylesheets
98
+ return 'application' if engine_code == 'root'
99
+
100
+ # Rails engines stylesheets
101
+ "#{engine_code}/#{stylesheet}"
102
+ end
103
+
104
+ # print a custom icon for lesli
105
+ def lesli_svg(name)
106
+ content_tag("svg", width: "64px", height: "64px") do
107
+ "<use xlink:href='##{name}'></use>".html_safe
108
+ end
109
+ end
110
+
111
+ # Prints objects as JSON code
112
+ def dd object
113
+ content_tag(:pre) do
114
+ content_tag(:code) do
115
+ ERB::Util.html_escape JSON.pretty_generate(object.as_json)
116
+ end
117
+ end
6
118
  end
7
119
  end
8
120
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2023, Lesli Technologies, S. A.
5
+ Copyright (c) 2026, 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
@@ -68,29 +68,6 @@ module Lesli
68
68
  end
69
69
  end
70
70
 
71
- def navigation_link_vue(path, label, icon = nil, reload: false)
72
- # default vue router links for single page applications
73
- html_element = "router-link"
74
- html_options = { to: path, 'active-class': "navigation-link-active" }
75
-
76
- # if reload is nedeed, we use a standard "a" tag
77
- if reload
78
- html_element = "a"
79
- html_options = { href: path }
80
- end
81
-
82
- content_tag(html_element, html_options) do
83
- # print a simple menu item (without icon)
84
- concat content_tag(:span, label, class: "text iconless") unless icon
85
-
86
- # print a full menu item if icon was requested
87
- if icon
88
- concat content_tag(:span, nil, class: icon)
89
- concat content_tag(:span, label, class: "text")
90
- end
91
- end
92
- end
93
-
94
71
  # ADMINISTRATION
95
72
 
96
73
  # 01.01 Admin engine
@@ -107,6 +84,12 @@ module Lesli
107
84
 
108
85
  # SALES & MARKETING
109
86
 
87
+ # 02.02 Contacts engine
88
+ def navigation_engine_contacts(title: "Contacts", subtitle: "Customer Relationship Management")
89
+ return unless defined? LesliContacts
90
+ navigation_engine_item(title,subtitle,"contacts",lesli_contacts.root_path,controller_path.include?("lesli_contacts"))
91
+ end
92
+
110
93
  # 02.04 House engine
111
94
  def navigation_engine_house(title: "House", subtitle: "cloud_house/house-logo.svg")
112
95
  return unless defined? CloudHouse
@@ -266,7 +249,7 @@ module Lesli
266
249
  # SECURITY & PRIVACY
267
250
 
268
251
  # 08.01 Shield engine
269
- def navigation_engine_shield(title: "Shield", subtitle: "Authentication & Authorization")
252
+ def navigation_engine_shield(title: "Shield", subtitle: "Users & Security Management")
270
253
  return unless defined? LesliShield
271
254
  navigation_engine_item(title, subtitle, "shield", lesli_shield.root_path, controller_path.include?("lesli_shield"))
272
255
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2023, Lesli Technologies, S. A.
5
+ Copyright (c) 2026, 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,19 +19,36 @@ 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
26
- @website https://www.lesli.dev
26
+ @website https://www.lesli.tech
27
27
  @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
28
 
29
29
  // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
- // ·
30
+ // ·
31
31
  =end
32
32
 
33
33
  module Lesli
34
34
  module SystemHelper
35
+
36
+ # build a url path to change locales
37
+ def language_url(locale)
38
+ "/lesli/language?locale=#{locale}"
39
+ end
40
+
41
+ # return flag code according to locale code
42
+ def language_flag(locale)
43
+ locale = "gb" if locale.to_s == "en"
44
+ locale
45
+ end
46
+
47
+ # return the name of the language
48
+ def language_name(locale)
49
+ Lesli.config.locales.dig(locale) || "undefined"
50
+ end
51
+
35
52
  # return the engine code of the controller that is handling the http request
36
53
  def lesli_controller
37
54
  controller_path.split("/")[0]
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2023, Lesli Technologies, S. A.
5
+ Copyright (c) 2026, 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
@@ -32,7 +32,24 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  module Lesli
34
34
  module TurboHelper
35
- def render_notifications_stream
35
+
36
+ def turbo_link_to body, url, html_options = {}
37
+ link_to(body, url, class: "link", data: { turbo_frame: '_top' })
38
+ end
39
+
40
+ # Meta-programming to define flash setter methods dynamically
41
+ # success("Everything worked!")
42
+ # danger("Oops, there was an error.")
43
+ # info("Just an informational message.")
44
+ # warning("This is a warning.")
45
+ [:info, :success, :warning, :danger].each do |flash_type|
46
+ define_method(flash_type) do |message|
47
+ flash[flash_type] = message
48
+ end
49
+ end
50
+
51
+ def stream_notification_success(message)
52
+ success(message)
36
53
  turbo_stream.replace("application-lesli-notifications") do
37
54
  render("lesli/partials/application-lesli-notifications")
38
55
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2023, Lesli Technologies, S. A.
5
+ Copyright (c) 2026, 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,10 +33,6 @@ Building a better future, one line of code at a time.
33
33
  module Lesli
34
34
  module RequesterInterface
35
35
 
36
- def set_path
37
- @@engine_path = Lesli::Engine.routes.find_script_name({})
38
- end
39
-
40
36
  # Set the user language based on user_settings, session configuration or instance default locale
41
37
  def set_locale
42
38
  # get saved language in session, browser language or the default in config
@@ -76,28 +72,5 @@ module Lesli
76
72
  }
77
73
  }
78
74
  end
79
-
80
- def get_user_agent(as_string=true)
81
-
82
- http_user_agent = request.env["HTTP_USER_AGENT"]
83
-
84
- # parse user agent
85
- user_agent = UserAgent.parse(http_user_agent)
86
-
87
- user_agent_version = user_agent.version.to_a.first(2).join(".")
88
-
89
- # return user agent as object
90
- if as_string == false
91
- return {
92
- platform: user_agent.platform,
93
- os: user_agent.os,
94
- browser: user_agent.browser,
95
- version: user_agent_version
96
- }
97
- end
98
-
99
- # return user agent info as string
100
- "#{user_agent.platform} #{user_agent.os} - #{user_agent.browser} #{user_agent_version}"
101
- end
102
75
  end
103
76
  end