lesli 5.0.23 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/lesli/application.css +1 -192
  3. data/app/controllers/lesli/abouts_controller.rb +1 -1
  4. data/app/controllers/lesli/{items → item}/activities_controller.rb +1 -1
  5. data/app/controllers/lesli/item/discussions_controller.rb +126 -0
  6. data/app/controllers/lesli/item/tasks_controller.rb +126 -0
  7. data/app/helpers/lesli/customization_helper.rb +1 -1
  8. data/app/helpers/lesli/html_helper.rb +1 -1
  9. data/app/models/concerns/lesli/item/activities.rb +106 -0
  10. data/app/models/concerns/lesli/item/discussions.rb +92 -0
  11. data/app/models/concerns/lesli/item/tasks.rb +95 -0
  12. data/app/models/lesli/account.rb +1 -0
  13. data/app/models/lesli/{items → item}/activity.rb +5 -13
  14. data/app/models/lesli/item/discussion.rb +10 -0
  15. data/{lib/lesli/r_spec.rb → app/models/lesli/item/task.rb} +9 -10
  16. data/app/views/lesli/partials/_application-lesli-header.html.erb +12 -0
  17. data/config/initializers/lesli_migration_helpers.rb +2 -2
  18. data/db/migrate/v1/0000000210_create_lesli_users.rb +1 -1
  19. data/lib/generators/lesli/base_generator.rb +172 -0
  20. data/lib/generators/lesli/controller/controller_generator.rb +40 -0
  21. data/lib/generators/lesli/controller/templates/controller.rb.tt +86 -0
  22. data/lib/generators/lesli/install/install_generator.rb +1 -1
  23. data/lib/generators/lesli/model/model_generator.rb +44 -0
  24. data/lib/generators/lesli/model/templates/model.rb.tt +16 -0
  25. data/lib/generators/lesli/scaffold/scaffold_generator.rb +47 -0
  26. data/lib/generators/lesli/service/service_generator.rb +40 -0
  27. data/lib/generators/lesli/service/templates/service.rb.tt +44 -0
  28. data/lib/generators/lesli/views/templates/_form.html.erb.tt +22 -0
  29. data/lib/generators/lesli/views/templates/index.html.erb.tt +17 -0
  30. data/lib/generators/lesli/views/templates/new.html.erb.tt +4 -0
  31. data/lib/generators/lesli/views/templates/show.html.erb.tt +22 -0
  32. data/lib/generators/lesli/views/views_generator.rb +106 -0
  33. data/lib/lesli/engine.rb +1 -23
  34. data/lib/lesli/router.rb +42 -43
  35. data/lib/lesli/version.rb +2 -2
  36. data/lib/migrate/common.rb +1 -1
  37. data/lib/migrate/items/activity_structure.rb +11 -5
  38. data/lib/migrate/items/discussion_structure.rb +9 -3
  39. data/lib/migrate/items/{action_structure.rb → task_structure.rb} +12 -6
  40. data/lib/migrate/shared/catalog_structure.rb +16 -0
  41. data/lib/tasks/lesli/db.rake +9 -0
  42. data/readme.md +1 -1
  43. metadata +58 -79
  44. data/app/assets/config/lesli_manifest.js +0 -42
  45. data/app/assets/images/lesli/brand/app-auth.svg +0 -9
  46. data/app/assets/images/lesli/brand/app-icon.svg +0 -48
  47. data/app/assets/images/lesli/brand/app-logo.png +0 -0
  48. data/app/assets/images/lesli/brand/app-logo.svg +0 -4
  49. data/app/assets/images/lesli/brand/favicon.png +0 -0
  50. data/app/assets/images/lesli/brand/favicon.svg +0 -61
  51. data/app/assets/images/lesli/brand/login-background.jpg +0 -0
  52. data/app/assets/images/lesli/brand/register-background.jpg +0 -0
  53. data/app/assets/javascripts/lesli/application.js +0 -1
  54. data/app/controllers/lesli/items/actions_controller.rb +0 -122
  55. data/app/controllers/lesli/items/discussions_controller.rb +0 -93
  56. data/app/models/lesli/items/action.rb +0 -15
  57. data/app/models/lesli/items/discussion.rb +0 -15
  58. data/config/importmap.rb +0 -1
  59. data/db/structure/00000000_locations.json +0 -32
  60. data/db/structure/00000020_catalogs.json +0 -0
  61. data/db/structure/00000201_workflows.json +0 -17
  62. data/db/structure/00000202_workflow_statuses.json +0 -24
  63. data/db/structure/00000203_workflow_associations.json +0 -14
  64. data/db/structure/00000204_workflow_actions.json +0 -39
  65. data/db/structure/00000205_workflow_checks.json +0 -27
  66. data/db/structure/00000300_custom_fields.json +0 -8
  67. data/db/structure/00000301_custom_fields.json +0 -38
  68. data/db/structure/00000401_custom_validations.json +0 -14
  69. data/db/structure/00000402_custom_validation_rules.json +0 -23
  70. data/db/structure/00000403_custom_validation_fields.json +0 -14
  71. data/lib/generators/application_lesli_generator_base.rb +0 -164
  72. data/lib/generators/lesli/spec/USAGE +0 -8
  73. data/lib/generators/lesli/spec/spec_generator.rb +0 -22
  74. data/lib/generators/lesli/spec/templates/spec-factory.template +0 -17
  75. data/lib/generators/lesli/spec/templates/spec-model.template +0 -70
  76. data/lib/generators/lesli/view/USAGE +0 -8
  77. data/lib/generators/lesli/view/templates/spec-factory.template +0 -17
  78. data/lib/generators/lesli/view/templates/spec-model.template +0 -70
  79. data/lib/generators/lesli/view/view_generator.rb +0 -22
  80. data/lib/scss/_apps.scss +0 -94
  81. data/lib/scss/application.scss +0 -34
  82. data/lib/tasks/lesli/docs.rake +0 -47
  83. data/lib/tasks/lesli/git.rake +0 -70
  84. data/lib/tasks/lesli/github.rake +0 -89
  85. data/lib/test/config.rb +0 -111
  86. data/lib/test/helpers/response_integration_helper.rb +0 -46
  87. data/lib/test/lesli.rb +0 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd0c72054c9e183cd20bb799ce466d3e7726a169a27d25c74f629dd18456a756
4
- data.tar.gz: 4a06f9ec53949acea25626f80a57c2f7a200949847c1588263ed501b4e8958e3
3
+ metadata.gz: 8e75a2365623cbc3a027ab7f7d3369b889e4338329abc2d2c0a6c1a02d13e85c
4
+ data.tar.gz: 16b78e83a7728bc919a99cba8ab98cbd3fecd3b399181c5c702eeba86e9a2331
5
5
  SHA512:
6
- metadata.gz: 4cb0333bce69463e0b9d5a5087fb132176b8e8824f1d743788325cf42d4b3accb076fb9e6b47336a7601569b7914a052bf19cc98350e28eb9e473e1b93b286f6
7
- data.tar.gz: 52b5932c2c4467fe81cbf7c882be73127f8d8ad55df48f837b79b38bbbee00d6a64cc5a52c4be72d6551434264b8fe3197eb29bddb60775e5b024f61e1fb09c2
6
+ metadata.gz: 63ad9a17d31d1d42da5559882dcd5148af37930159becd88023937ae25a08d53f213795e371d6a970412863c85e838c4c3a0f620e0d51836a3d13a93a5ab4fd5
7
+ data.tar.gz: ec30a9449b36d01f07777f793bcff6993ace743fd3f9b015d07dd1403c01d11eb439d4822aaf8625a34dc87c4b8cb8a5014bc6b3764b65e6a3ed76dd028eb2b9
@@ -1,192 +1 @@
1
- @charset "UTF-8";
2
- /*
3
- Lesli
4
-
5
- Copyright (c) 2025, 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
- */
32
- /*
33
- Lesli
34
-
35
- Copyright (c) 2025, Lesli Technologies, S. A.
36
-
37
- This program is free software: you can redistribute it and/or modify
38
- it under the terms of the GNU General Public License as published by
39
- the Free Software Foundation, either version 3 of the License, or
40
- (at your option) any later version.
41
-
42
- This program is distributed in the hope that it will be useful,
43
- but WITHOUT ANY WARRANTY; without even the implied warranty of
44
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45
- GNU General Public License for more details.
46
-
47
- You should have received a copy of the GNU General Public License
48
- along with this program. If not, see http://www.gnu.org/licenses/.
49
-
50
- Lesli · Ruby on Rails SaaS Development Framework.
51
-
52
- Made with ♥ by LesliTech
53
- Building a better future, one line of code at a time.
54
-
55
- @contact hello@lesli.tech
56
- @website https://www.lesli.tech
57
- @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
58
-
59
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
60
- // ·
61
- */
62
- /**
63
- Lesli
64
-
65
- Copyright (c) 2025, Lesli Technologies, S. A.
66
-
67
- This program is free software: you can redistribute it and/or modify
68
- it under the terms of the GNU General Public License as published by
69
- the Free Software Foundation, either version 3 of the License, or
70
- (at your option) any later version.
71
-
72
- This program is distributed in the hope that it will be useful,
73
- but WITHOUT ANY WARRANTY; without even the implied warranty of
74
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75
- GNU General Public License for more details.
76
-
77
- You should have received a copy of the GNU General Public License
78
- along with this program. If not, see http://www.gnu.org/licenses/.
79
-
80
- Lesli - SCSS Utilities for websites, apps and web applications
81
-
82
- Made with ♥ by LesliTech
83
- Building a better future, one line of code at a time.
84
-
85
- @contact hello@lesli.tech
86
- @website https://www.lesli.tech
87
- @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
88
-
89
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
90
- // ·
91
- */
92
- /*
93
- Lesli
94
-
95
- Copyright (c) 2025, Lesli Technologies, S. A.
96
-
97
- This program is free software: you can redistribute it and/or modify
98
- it under the terms of the GNU General Public License as published by
99
- the Free Software Foundation, either version 3 of the License, or
100
- (at your option) any later version.
101
-
102
- This program is distributed in the hope that it will be useful,
103
- but WITHOUT ANY WARRANTY; without even the implied warranty of
104
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
105
- GNU General Public License for more details.
106
-
107
- You should have received a copy of the GNU General Public License
108
- along with this program. If not, see http://www.gnu.org/licenses/.
109
-
110
- Lesli - SCSS Utilities for websites, apps and web applications
111
-
112
- Made with ♥ by LesliTech
113
- Building a better future, one line of code at a time.
114
-
115
- @contact hello@lesli.tech
116
- @website https://www.lesli.tech
117
- @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
118
-
119
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
120
- // ·
121
- */
122
- /**
123
- Lesli
124
-
125
- Copyright (c) 2025, Lesli Technologies, S. A.
126
-
127
- This program is free software: you can redistribute it and/or modify
128
- it under the terms of the GNU General Public License as published by
129
- the Free Software Foundation, either version 3 of the License, or
130
- (at your option) any later version.
131
-
132
- This program is distributed in the hope that it will be useful,
133
- but WITHOUT ANY WARRANTY; without even the implied warranty of
134
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
135
- GNU General Public License for more details.
136
-
137
- You should have received a copy of the GNU General Public License
138
- along with this program. If not, see http://www.gnu.org/licenses/.
139
-
140
- Lesli - SCSS Utilities for websites, apps and web applications
141
-
142
- Made with ♥ by LesliTech
143
- Building a better future, one line of code at a time.
144
-
145
- @contact hello@lesli.tech
146
- @website https://www.lesli.tech
147
- @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
148
-
149
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
150
- // ·
151
- */
152
- body.lesli.apps.show .lesli-element-header {
153
- margin-bottom: 5rem !important;
154
- }
155
- body.lesli.apps.show .engines {
156
- gap: 24px;
157
- margin-inline-end: auto;
158
- margin-inline-start: auto;
159
- }
160
- body.lesli.apps.show .engines a {
161
- flex-basis: 318px;
162
- text-align: center;
163
- padding: 2rem 0.4rem 2.8rem;
164
- border: white 1px solid;
165
- border-radius: 6px;
166
- background-color: white;
167
- transition: all ease-in-out 0.2s;
168
- box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px;
169
- }
170
- body.lesli.apps.show .engines a:hover {
171
- border-color: var(--lesli-color-primary);
172
- transform: translateY(-2px);
173
- }
174
- body.lesli.apps.show .engines a.is-active {
175
- background-color: #F0F4FF;
176
- border-color: var(--lesli-color-primary);
177
- }
178
- body.lesli.apps.show .engines a svg {
179
- margin-right: 0.4rem;
180
- fill: var(--lesli-color-primary);
181
- }
182
- body.lesli.apps.show .engines a p {
183
- font-size: 14;
184
- font-family: "OpenSans";
185
- }
186
- body.lesli.apps.show .engines a span {
187
- font-weight: 600;
188
- font-size: 20px;
189
- }
190
- body.lesli.apps.show .engines a span, body.lesli.apps.show .engines a p {
191
- color: var(--lesli-color-primary);
192
- }
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;font-family:"OpenSans"}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)}
@@ -50,7 +50,7 @@ module Lesli
50
50
  respond_to do |format|
51
51
  format.html {}
52
52
  format.json do
53
- lesli_engines = LesliSystem.engines.map do |engine, engine_info|
53
+ lesli_engines = ::LesliSystem.engines.map do |engine, engine_info|
54
54
  {
55
55
  :name => engine_info[:name],
56
56
  :code => engine_info[:code],
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Items
34
+ module Item
35
35
  class ActivitiesController < ApplicationLesliController
36
36
  end
37
37
  end
@@ -0,0 +1,126 @@
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
32
+
33
+ module Lesli
34
+ module Item
35
+ class DiscussionsController < ApplicationLesliController
36
+ before_action :set_discussion, only: %i[show update]
37
+ before_action :set_discussable, only: %i[index create]
38
+
39
+ def index
40
+ @discussions = discussion_class
41
+ .where(account: current_user.account)
42
+ .order(created_at: :desc)
43
+ respond_with_lesli(json: @discussions)
44
+ end
45
+
46
+ def show
47
+ end
48
+
49
+ def create
50
+ discussion = discussion_class.new(discussion_params)
51
+
52
+ discussion.user = current_user
53
+ discussion.account = current_user.account
54
+ discussion.discussable = @discussable if @discussable
55
+
56
+ if discussion.save
57
+ respond_with_lesli(:turbo => [
58
+ stream_notification_success("Discussion created"),
59
+ turbo_stream.prepend("#{scope_key}-lesli-items-discussions-list") do
60
+ LesliView::Item::Discussion.new(discussion).render_in(view_context)
61
+ end
62
+ ])
63
+ else
64
+ respond_with_lesli(
65
+ :turbo => stream_notification_danger(discussion.errors.full_messages)
66
+ )
67
+ end
68
+ end
69
+
70
+ def update
71
+ @discussion.done = true
72
+ @discussion.save
73
+ respond_with_lesli(:turbo => [
74
+ stream_notification_success("Discussion updated #{@discussable}"),
75
+ turbo_stream.replace(helpers.dom_id(@discussion, scope_key)) do
76
+ LesliView::Item::Discussion.new(@discussion, scope_key).render_in(view_context)
77
+ end
78
+ ])
79
+ end
80
+
81
+ private
82
+
83
+ # return a key to identify the engine where the tasks are running
84
+ def scope_key = ActiveSupport::Inflector.underscore(discussion_class.name).tr("/", "_")
85
+
86
+ # return the discussion class including the engine where the tasks are running
87
+ def discussion_class = self.class.module_parent.const_get("Discussion")
88
+
89
+ # validate we invoke only models that implements Lesli::Item::Discussions concern
90
+ def validate_discussable discussable
91
+
92
+ # 1. Attempt to resolve the class safely
93
+ klass = discussable.safe_constantize
94
+
95
+ # 2. VALIDATION: Check if the class is allowed to be discussable
96
+ # We check if the class exists AND if it includes your specific discussable trait
97
+ unless klass && klass.respond_to?(:is_lesli_taskable?) && klass.is_lesli_commentable?
98
+ render json: { error: "Unauthorized discussable type" }, status: :forbidden and return
99
+ end
100
+
101
+ klass
102
+ end
103
+
104
+ def set_discussion
105
+ @discussion = discussion_class.where(account: current_user.account).find(params[:id])
106
+ end
107
+
108
+ # Permite filtrar/crear para un actionable específico:
109
+ # params: actionable_type=LesliSupport::Ticket&actionable_id=123
110
+ def set_discussable
111
+ type = params[:discussable_type].presence
112
+ id = params[:discussable_id].presence
113
+ return if type.blank? || id.blank?
114
+
115
+ discussable = validate_discussable(type)
116
+
117
+ # 3. Execution: Now it is safe to query
118
+ @discussable = discussable.where(account: current_user.account).find_by(id: id)
119
+ end
120
+
121
+ def discussion_params
122
+ params.require(scope_key.to_sym).permit(:message)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,126 @@
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
32
+
33
+ module Lesli
34
+ module Item
35
+ class TasksController < ApplicationLesliController
36
+ before_action :set_task, only: %i[show update]
37
+ before_action :set_taskable, only: %i[index create]
38
+
39
+ def index
40
+ @tasks = task_class
41
+ .where(account: current_user.account)
42
+ .order(created_at: :desc)
43
+ respond_with_lesli(json: @tasks)
44
+ end
45
+
46
+ def show
47
+ end
48
+
49
+ def create
50
+ task = task_class.new(task_params)
51
+
52
+ task.user = current_user
53
+ task.account = current_user.account
54
+ task.taskable = @taskable if @taskable
55
+
56
+ if task.save
57
+ respond_with_lesli(:turbo => [
58
+ stream_notification_success("Task created"),
59
+ turbo_stream.prepend("#{scope_key}-lesli-items-tasks-list") do
60
+ LesliView::Item::Task.new(task, scope_key).render_in(view_context)
61
+ end
62
+ ])
63
+ else
64
+ respond_with_lesli(
65
+ :turbo => stream_notification_danger(task.errors.full_messages)
66
+ )
67
+ end
68
+ end
69
+
70
+ def update
71
+ @task.done = true
72
+ @task.save
73
+ respond_with_lesli(:turbo => [
74
+ stream_notification_success("Task updated #{@taskable}"),
75
+ turbo_stream.replace(helpers.dom_id(@task, scope_key)) do
76
+ LesliView::Item::Task.new(@task, scope_key).render_in(view_context)
77
+ end
78
+ ])
79
+ end
80
+
81
+ private
82
+
83
+ # return a key to identify the engine where the tasks are running
84
+ def scope_key = ActiveSupport::Inflector.underscore(task_class.name).tr("/", "_")
85
+
86
+ # return the task class including the engine where the tasks are running
87
+ def task_class = self.class.module_parent.const_get("Task")
88
+
89
+ # validate we invoke only models that implements Lesli::Item::Tasks concern
90
+ def validate_taskable taskable
91
+
92
+ # 1. Attempt to resolve the class safely
93
+ klass = taskable.safe_constantize
94
+
95
+ # 2. VALIDATION: Check if the class is allowed to be taskable
96
+ # We check if the class exists AND if it includes your specific taskable trait
97
+ unless klass && klass.respond_to?(:is_lesli_taskable?) && klass.is_lesli_taskable?
98
+ render json: { error: "Unauthorized taskable type" }, status: :forbidden and return
99
+ end
100
+
101
+ klass
102
+ end
103
+
104
+ def set_task
105
+ @task = task_class.where(account: current_user.account).find(params[:id])
106
+ end
107
+
108
+ # Permite filtrar/crear para un actionable específico:
109
+ # params: actionable_type=LesliSupport::Ticket&actionable_id=123
110
+ def set_taskable
111
+ type = params[:taskable_type].presence
112
+ id = params[:taskable_id].presence
113
+ return if type.blank? || id.blank?
114
+
115
+ taskable = validate_taskable(type)
116
+
117
+ # 3. Execution: Now it is safe to query
118
+ @taskable = taskable.where(account: current_user.account).find_by(id: id)
119
+ end
120
+
121
+ def task_params
122
+ params.require(scope_key.to_sym).permit(:title)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -45,7 +45,7 @@ module Lesli
45
45
  def customization_instance_logo(tag: false, logo: "app-logo", variant: "light", mode: "web",
46
46
  options: { alt: "Logo" })
47
47
  # loading logo from builder assets
48
- logo_path = "#{lesli_instance_code}/brand/#{logo}.svg"
48
+ logo_path = "lesli_assets/brand/#{logo}.svg"
49
49
 
50
50
  # load favicon as PNG for better compatibility between web browsers
51
51
  #logo_path = "#{lesli_instance_code}/brand/#{logo}.png" if logo == "favicon"
@@ -35,7 +35,7 @@ module Lesli
35
35
 
36
36
  # Prints link tags to add favicon to websites
37
37
  def lesli_favicon
38
- icon_path = image_url("lesli/brand/favicon.svg")
38
+ icon_path = image_url("lesli_assets/brand/favicon.svg")
39
39
  safe_join([
40
40
  tag.link(href: icon_path, rel: "alternate icon"),
41
41
  tag.link(href: icon_path, rel: "icon", type: "image/svg+xml"),
@@ -0,0 +1,106 @@
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
32
+
33
+ module Lesli
34
+ module Item
35
+ module Activities
36
+ extend ActiveSupport::Concern
37
+
38
+ included do
39
+ class_attribute :lesli_activities_class, instance_accessor: false
40
+ lesli_activities_setup
41
+ end
42
+
43
+ class_methods do
44
+
45
+ # Automatically sets the associations to the
46
+ # engine model that is implementing the task items
47
+ def lesli_activities_setup(use: nil, as: :subject, association_name: :activities)
48
+ klass = if use
49
+ use.to_s.constantize
50
+ else
51
+ "#{name.deconstantize}::Item::Activity".constantize
52
+ end
53
+
54
+ self.lesli_activities_class = klass
55
+
56
+ # ✅ Auto-fix table name (works even when engine defines table_name_prefix)
57
+ expected_table = lesli_expected_activity_table_name_for(klass)
58
+
59
+ if klass.table_name != expected_table
60
+ klass.table_name = expected_table
61
+ end
62
+
63
+ # Set associations
64
+ # Example:
65
+ # class LesliSupport::Ticket
66
+ # has_many :activities, class_name: "LesliSupport::Items::Activity"
67
+ # end
68
+ has_many(association_name,
69
+ -> { where(deleted_at: nil).order(created_at: :desc) },
70
+ as: as,
71
+ class_name: klass.name,
72
+ dependent: :destroy
73
+ )
74
+
75
+ # rescue NameError
76
+ # raise NameError,
77
+ # "Task class not found for #{name}. Expected #{name.deconstantize}::Activity or pass `use:`"
78
+ end
79
+
80
+ private
81
+
82
+ # Build: "lesli_support_item_activities" from "LesliSupport::Item::Activity"
83
+ #
84
+ # We DO NOT rely on ActiveRecord's table_name_prefix, because that’s what breaks your case.
85
+ def lesli_expected_activity_table_name_for(klass)
86
+ parts = klass.name.split("::").map(&:underscore) # ["lesli_support", "item", "activity"]
87
+ "#{parts.join('_').pluralize}" # "lesli_support_item_activities"
88
+ end
89
+ end
90
+
91
+ def after_save_activities
92
+ L2.warn "You need to define your activity methods in your model"
93
+ end
94
+
95
+ def activities_create **resource
96
+ self.activities.create(
97
+ subject_type: self.class.name,
98
+ subject_id: self.id,
99
+ user_id:self.user_id,
100
+ account_id:self.account_id,
101
+ **resource
102
+ )
103
+ end
104
+ end
105
+ end
106
+ end