lesli 5.0.4 → 5.0.5
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/images/lesli/brand/app-logo2.svg +52 -0
- data/app/assets/javascripts/lesli/users/passwords.js +3 -3
- data/app/assets/javascripts/lesli/users/registrations.js +3 -3
- data/app/assets/javascripts/lesli/users/sessions.js +3 -3
- data/app/controllers/lesli/application_controller.rb +3 -3
- data/app/controllers/lesli/application_lesli_controller.rb +2 -2
- data/app/controllers/lesli/interfaces/application/authorization.rb +1 -1
- data/app/controllers/lesli/interfaces/application/requester.rb +1 -1
- data/app/controllers/lesli/shared/dashboards_controller.rb +308 -0
- data/app/controllers/users/confirmations_controller.rb +1 -1
- data/app/controllers/users/passwords_controller.rb +7 -10
- data/app/helpers/lesli/general_helper.rb +1 -1
- data/app/helpers/lesli/navigation_helper.rb +17 -16
- data/app/lib/lesli/system.rb +2 -1
- data/app/mailers/lesli/devise_mailer.rb +1 -1
- data/app/models/concerns/account_initializer.rb +9 -0
- data/app/models/lesli/account.rb +1 -0
- data/app/models/lesli/application_lesli_record.rb +1 -1
- data/app/models/lesli/shared/dashboard.rb +162 -0
- data/app/models/lesli/system_controller.rb +1 -0
- data/app/operators/lesli/controller_operator.rb +148 -0
- data/app/views/devise/passwords/new.html.erb +1 -1
- data/app/views/lesli/partials/_application-lesli-engines.html.erb +1 -1
- data/app/views/lesli/partials/_application-lesli-icons.html.erb +1 -1
- data/config/locales/translations.en.yml +17 -0
- data/config/locales/translations.es.yml +17 -0
- data/config/routes.rb +4 -2
- data/db/seed/development/users.rb +0 -1
- data/db/seeds.rb +16 -29
- data/lib/lesli/version.rb +1 -1
- data/lib/mailer_previews/devise_mailer_preview.rb +7 -0
- data/lib/sass/lesli/layouts/application-navbar.scss +1 -1
- data/lib/tasks/lesli/controllers.rake +1 -91
- data/lib/tasks/lesli/db.rake +36 -6
- data/lib/tasks/lesli/dev.rake +66 -0
- data/lib/tasks/lesli/engine.rake +59 -0
- data/lib/tasks/lesli/{role.rake → privileges.rake} +3 -3
- data/lib/tasks/lesli_tasks.rake +5 -0
- data/lib/vue/application.js +2 -1
- data/lib/vue/devise/passwords.js +8 -8
- data/lib/vue/devise/registrations.js +2 -2
- data/lib/vue/devise/sessions.js +11 -6
- data/lib/vue/layouts/application-header.vue +6 -1
- data/lib/vue/shared/dashboards/apps/edit.vue +215 -0
- data/lib/vue/{apps → shared}/dashboards/apps/index.vue +3 -5
- data/lib/vue/{apps → shared}/dashboards/apps/show.vue +26 -16
- data/lib/vue/{apps → shared}/dashboards/components/form.vue +31 -43
- data/lib/vue/shared/stores/dashboard.js +251 -0
- data/lib/vue/stores/translations.json +24 -72
- data/lib/vue/stores/{user.js → users.js} +1 -1
- data/lib/webpack/base.js +3 -2
- data/readme.md +1 -1
- metadata +46 -52
- data/lib/vue/apps/dashboards/apps/edit.vue +0 -105
- data/lib/vue/apps/dashboards/components/preview.vue +0 -172
- /data/app/assets/icons/lesli/{cloud-vault.svg → cloud-guard.svg} +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/action.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/discussion/content.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/discussion/element.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/discussion/filters.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/discussion/new.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/discussion.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/file/grid.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/file/list.vue +0 -0
- /data/lib/vue/{apps → shared}/cloudobjects/file.vue +0 -0
- /data/lib/vue/{apps → shared}/dashboards/apps/new.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/chatroom-form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/cloud-object-clone-form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/cloud-object-file-form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/email-form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/notification-form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/send-cloud-object-file.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/task-form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/actions/index.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/checks/form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/checks/index.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/index.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/new.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/apps/show.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/components/associations.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/components/chart.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/components/workflow-form.vue +0 -0
- /data/lib/vue/{apps → shared}/workflows2/components/workflow-status-dropdown.vue +0 -0
@@ -0,0 +1,308 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
Lesli
|
4
|
+
|
5
|
+
Copyright (c) 2023, 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 https://www.lesli.tech
|
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
|
+
module Lesli
|
33
|
+
module Shared
|
34
|
+
class DashboardsController < ApplicationLesliController
|
35
|
+
before_action :set_dashboard, only: [:show, :update, :destroy, :options]
|
36
|
+
|
37
|
+
def index
|
38
|
+
respond_to do |format|
|
39
|
+
format.html {}
|
40
|
+
format.json do
|
41
|
+
dynamic_info = self.class.dynamic_info
|
42
|
+
model = dynamic_info[:model]
|
43
|
+
|
44
|
+
dashboards = model.list(current_user, @query)
|
45
|
+
respond_with_successful(dashboards)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def show
|
51
|
+
respond_to do |format|
|
52
|
+
format.html {}
|
53
|
+
format.json do
|
54
|
+
return respond_with_not_found unless @dashboard
|
55
|
+
respond_with_successful(@dashboard.show)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def new
|
61
|
+
end
|
62
|
+
|
63
|
+
def edit
|
64
|
+
end
|
65
|
+
|
66
|
+
# @controller_action_param :name [String] The name of the new dashboard
|
67
|
+
# @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
|
68
|
+
# @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
|
69
|
+
# @controller_action_param :roles_id [Integer] The id of the role that will have access to this dashboard
|
70
|
+
# @controller_action_param :user_main_id [Integer] The id of the user
|
71
|
+
# @controller_action_param :component_attributes [Array] Array of hashes that represent the attributes of the dashboard components
|
72
|
+
# @controller_action_param :component_attributes.name [String] The name of this component given to the user
|
73
|
+
# @controller_action_param :component_attributes.component_id [String] An enum value, that indicates which component is being loaded
|
74
|
+
# @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
|
75
|
+
# @controller_action_param :component_attributes.index [Integer] The position of the component in the layout
|
76
|
+
# @controller_action_param :component_attributes.configuration [Hash] Specific filtering and configuration of the components
|
77
|
+
# @return [Json] Json that contains wheter the creation of the dashboard was successful or not.
|
78
|
+
# If it is not successful, it returns an error message
|
79
|
+
# @description Creates a new dashboard associated to the *current_user*'s *account*
|
80
|
+
# @example
|
81
|
+
# # Executing this controller's action from javascript's frontend
|
82
|
+
# let data = {
|
83
|
+
# dashboard: {
|
84
|
+
# name: "Sales Dashboard",
|
85
|
+
# default: false,
|
86
|
+
# roles_id: 3,
|
87
|
+
# components_attributes: [
|
88
|
+
# {
|
89
|
+
# name: 'Projects Count',
|
90
|
+
# component_id: projects_component,
|
91
|
+
# layout: 4,
|
92
|
+
# index: 3,
|
93
|
+
# configuration: {}
|
94
|
+
# }, {
|
95
|
+
# name: 'New Customers Count',
|
96
|
+
# component_id: new_customers_component,
|
97
|
+
# layout: 4,
|
98
|
+
# index: 3,
|
99
|
+
# configuration: {}
|
100
|
+
# }
|
101
|
+
# ]
|
102
|
+
# }
|
103
|
+
# };
|
104
|
+
# this.http.post('127.0.0.1/help/dashboards', data);
|
105
|
+
def create
|
106
|
+
dynamic_info = self.class.dynamic_info
|
107
|
+
module_name = dynamic_info[:module_name]
|
108
|
+
model = dynamic_info[:model]
|
109
|
+
full_module_name = dynamic_info[:full_module_name].underscore
|
110
|
+
|
111
|
+
dashboard = model.new(dashboard_params)
|
112
|
+
dashboard["#{full_module_name}_account_id".to_sym] = current_user.account.id
|
113
|
+
dashboard.user_creator = current_user
|
114
|
+
|
115
|
+
if dashboard.save
|
116
|
+
respond_with_successful(dashboard)
|
117
|
+
else
|
118
|
+
respond_with_error(dashboard.errors.full_messages.to_sentence)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @controller_action_param :name [String] The name of the new dashboard
|
123
|
+
# @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
|
124
|
+
# @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
|
125
|
+
# @controller_action_param :roles_id [Integer] The id of the role that will have access to this dashboard
|
126
|
+
# @controller_action_param :user_main_id [Integer] The id of the user
|
127
|
+
# @controller_action_param :component_attributes [Array] Array of hashes that represent the attributes of the dashboard components
|
128
|
+
# @controller_action_param :component_attributes.name [String] The name of this component given to the user
|
129
|
+
# @controller_action_param :component_attributes.component_id [String] An enum value, that indicates which component is being loaded
|
130
|
+
# @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
|
131
|
+
# @controller_action_param :component_attributes.index [Integer] The position of the component in the layout
|
132
|
+
# @controller_action_param :component_attributes.configuration [Hash] Specific filtering and configuration of the components
|
133
|
+
# @return [Json] Json that contains wheter the dashboard was successfully updated or not.
|
134
|
+
# If it it not successful, it returns an error message
|
135
|
+
# @description Updates an existing dashboard associated to the *current_user*'s *account*.
|
136
|
+
# @example
|
137
|
+
# # Executing this controller's action from javascript's frontend
|
138
|
+
# let dashboard_id = 4;
|
139
|
+
# let data = {
|
140
|
+
# dashboard: {
|
141
|
+
# name: "Sales Dashboard",
|
142
|
+
# default: false,
|
143
|
+
# roles_id: 3,
|
144
|
+
# components_attributes: [
|
145
|
+
# {
|
146
|
+
# name: 'Projects Count',
|
147
|
+
# component_id: projects_component,
|
148
|
+
# layout: 4,
|
149
|
+
# index: 3,
|
150
|
+
# configuration: {}
|
151
|
+
# }, {
|
152
|
+
# name: 'New Customers Count',
|
153
|
+
# component_id: new_customers_component,
|
154
|
+
# layout: 4,
|
155
|
+
# index: 3,
|
156
|
+
# configuration: {}
|
157
|
+
# }
|
158
|
+
# ]
|
159
|
+
# }
|
160
|
+
# };
|
161
|
+
# this.http.put(`127.0.0.1/help/dashboards/${dashboard_id}`, data);
|
162
|
+
def update
|
163
|
+
return respond_with_not_found unless @dashboard
|
164
|
+
|
165
|
+
if @dashboard.update(dashboard_params)
|
166
|
+
respond_with_successful(@dashboard.show)
|
167
|
+
else
|
168
|
+
respond_with_error(@dashboard.errors.full_messages.to_sentence)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# @return [Json] Json that contains wheter the dashboard was successfully deleted or not.
|
173
|
+
# If it it not successful, it returns an error message
|
174
|
+
# @description Deletes an existing *dashboard* associated to the *current_user*'s *account*.
|
175
|
+
# Since the dashboard has details, these are also deleted. However, if there
|
176
|
+
# is an existing *cloud_object* associated to the *dashboard*, it cannot be deleted
|
177
|
+
# @example
|
178
|
+
# # Executing this controller's action from javascript's frontend
|
179
|
+
# let dashboard_id = 4;
|
180
|
+
# this.http.delete(`127.0.0.1/help/dashboards/${dashboard_id}`);
|
181
|
+
def destroy
|
182
|
+
return respond_with_not_found unless @dashboard
|
183
|
+
|
184
|
+
if @dashboard.destroy
|
185
|
+
respond_with_successful
|
186
|
+
else
|
187
|
+
respond_with_error(@dashboard.errors.full_messages.to_sentence)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def options
|
192
|
+
dynamic_info = self.class.dynamic_info
|
193
|
+
model = dynamic_info[:module_model]
|
194
|
+
|
195
|
+
respond_with_successful(model.options(current_user, @query))
|
196
|
+
end
|
197
|
+
|
198
|
+
def resource_component
|
199
|
+
dynamic_info = self.class.dynamic_info
|
200
|
+
component_model = dynamic_info[:component_model]
|
201
|
+
|
202
|
+
component_id = sanitize(params[:component_id].to_sym)
|
203
|
+
|
204
|
+
# We verify if the method exists, and if it is in the available component list
|
205
|
+
if component_model.respond_to?(component_id) && component_model.component_ids[component_id]
|
206
|
+
respond_with_successful(component_model.public_send(component_id, current_user, @query))
|
207
|
+
else
|
208
|
+
respond_with_not_found()
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
# @return [void]
|
215
|
+
# @description Sets the variable @dashboard. The variable contains the *cloud_object* *dashboard*
|
216
|
+
# to be handled by the controller action that called this method
|
217
|
+
# @example
|
218
|
+
# #suppose params[:id] = 1
|
219
|
+
# puts @dashboard # will display nil
|
220
|
+
# set_dashboard
|
221
|
+
# puts @dashboard # will display an instance of CloudHelp:TicketDashboard
|
222
|
+
def set_dashboard
|
223
|
+
dynamic_info = self.class.dynamic_info
|
224
|
+
|
225
|
+
model = dynamic_info[:module_model]
|
226
|
+
module_name = dynamic_info[:module_name]
|
227
|
+
module_name_full = dynamic_info[:module_name_full].underscore
|
228
|
+
|
229
|
+
# When params[:id] is 'default' order of priority is:
|
230
|
+
# Main dashboard for user goes first
|
231
|
+
# Main dashboard for role goes second
|
232
|
+
# Default dashboard goes third
|
233
|
+
if params[:id] == "default"
|
234
|
+
# Main dashboard for user
|
235
|
+
@dashboard = model.find_by(
|
236
|
+
#"#{full_module_name}_account_id".to_sym => current_user.account.id,
|
237
|
+
account_id: current_user.account.id,
|
238
|
+
main: true,
|
239
|
+
#user_main_id: current_user.id
|
240
|
+
)
|
241
|
+
|
242
|
+
return if @dashboard
|
243
|
+
|
244
|
+
# Main dashboard for role
|
245
|
+
# @dashboard = model.find_by(
|
246
|
+
# :account_id => current_user.account.id,
|
247
|
+
# role_id: current_user.roles.first.id
|
248
|
+
# )
|
249
|
+
# return if @dashboard
|
250
|
+
|
251
|
+
# Default dashboard
|
252
|
+
@dashboard = model.find_by(
|
253
|
+
account_id: current_user.account.id,
|
254
|
+
default: true
|
255
|
+
)
|
256
|
+
else
|
257
|
+
@dashboard = model.find_by(
|
258
|
+
id: params[:id],
|
259
|
+
:account_id => current_user.account.id,
|
260
|
+
)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def dashboard_params
|
265
|
+
params.require(:dashboard).permit(
|
266
|
+
:name,
|
267
|
+
:default,
|
268
|
+
:roles_id,
|
269
|
+
components_attributes: [
|
270
|
+
:id,
|
271
|
+
:name,
|
272
|
+
:component_id,
|
273
|
+
:layout,
|
274
|
+
:index,
|
275
|
+
{query_configuration: {}},
|
276
|
+
{custom_configuration: {}},
|
277
|
+
:_destroy
|
278
|
+
]
|
279
|
+
)
|
280
|
+
end
|
281
|
+
|
282
|
+
private
|
283
|
+
|
284
|
+
# Build the Rails models and engine information for
|
285
|
+
# the current engine implementing the shared dashboards
|
286
|
+
# Example: For the LesliAudit engine
|
287
|
+
# {
|
288
|
+
# :module_name => "audit",
|
289
|
+
# :module_name_full => "LesliAudit",
|
290
|
+
# :module_model => "LesliAudit::Dashboard",
|
291
|
+
# :module_model_component => "LesliAudit::Dashboard::Component"
|
292
|
+
# }
|
293
|
+
def self.dynamic_info
|
294
|
+
|
295
|
+
module_info = self.name.split("::")
|
296
|
+
|
297
|
+
module_name = module_info[0].sub("Lesli", "").downcase
|
298
|
+
|
299
|
+
{
|
300
|
+
module_name: module_name,
|
301
|
+
module_name_full: module_info[0],
|
302
|
+
module_model: "#{ module_info[0] }::Dashboard".constantize,
|
303
|
+
module_model_component: "#{ module_info[0] }::Dashboard::Component".constantize
|
304
|
+
}
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
@@ -25,7 +25,7 @@ class Users::ConfirmationsController < Devise::ConfirmationsController
|
|
25
25
|
# register a log with a validation atempt for the user
|
26
26
|
log = user.logs.create({ description: "confirmation_atempt_successful" })
|
27
27
|
|
28
|
-
registration_operator = Lesli::
|
28
|
+
registration_operator = Lesli::UserRegistrationOperator.new(user)
|
29
29
|
|
30
30
|
# confirm the user
|
31
31
|
registration_operator.confirm
|
@@ -34,16 +34,13 @@ class Users::PasswordsController < Devise::PasswordsController
|
|
34
34
|
|
35
35
|
#user.logs.create({ title: "password_creation_successful" })
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
# respond_with_error(exception.message)
|
45
|
-
# end
|
46
|
-
|
37
|
+
begin
|
38
|
+
Lesli::DeviseMailer.reset_password_instructions(user, token).deliver_now
|
39
|
+
respond_with_successful
|
40
|
+
rescue => exception
|
41
|
+
#Honeybadger.notify(exception)
|
42
|
+
respond_with_error(exception.message)
|
43
|
+
end
|
47
44
|
end
|
48
45
|
|
49
46
|
def update
|
@@ -32,6 +32,14 @@ Building a better future, one line of code at a time.
|
|
32
32
|
|
33
33
|
module Lesli
|
34
34
|
module NavigationHelper
|
35
|
+
|
36
|
+
# Prints a separator line
|
37
|
+
def navigation_separator
|
38
|
+
content_tag(:li) do
|
39
|
+
content_tag(:hr)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
35
43
|
# Prints a html link inside a list item
|
36
44
|
def navigation_item(path, label, icon = nil, reload: false)
|
37
45
|
# default vue router links for single page applications
|
@@ -58,15 +66,9 @@ module Lesli
|
|
58
66
|
end
|
59
67
|
end
|
60
68
|
|
61
|
-
# Prints a separator line
|
62
|
-
def navigation_separator
|
63
|
-
content_tag(:li) do
|
64
|
-
content_tag(:hr)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
69
|
# 00.00 System administration
|
69
70
|
def navigation_engine_admin(title: "Administration", subtitle: "Users, privileges, access roles.")
|
71
|
+
return unless defined? LesliAdmin
|
70
72
|
navigation_engine_item(title, subtitle, "admin", lesli_admin.root_path, controller_path.include?("lesli_admin"))
|
71
73
|
end
|
72
74
|
|
@@ -243,10 +245,10 @@ module Lesli
|
|
243
245
|
|
244
246
|
# 07.02 Help engine
|
245
247
|
def navigation_engine_help(title: "Help", subtitle: "Support Ticket System")
|
246
|
-
return unless defined?
|
248
|
+
return unless defined? LesliHelp
|
247
249
|
|
248
|
-
navigation_engine_item(title, subtitle, "help",
|
249
|
-
controller_path.include?("
|
250
|
+
navigation_engine_item(title, subtitle, "help", lesli_help.root_path,
|
251
|
+
controller_path.include?("lesli_help"))
|
250
252
|
end
|
251
253
|
|
252
254
|
# 07.03 Portal engine
|
@@ -267,12 +269,11 @@ module Lesli
|
|
267
269
|
|
268
270
|
# SECURITY & PRIVACY
|
269
271
|
|
270
|
-
# 08.01
|
271
|
-
def
|
272
|
-
return unless defined?
|
273
|
-
|
274
|
-
|
275
|
-
controller_path.include?("lesli_vault"))
|
272
|
+
# 08.01 Guard engine
|
273
|
+
def navigation_engine_guard(title: "Guard", subtitle: "Users, privileges and access roles.")
|
274
|
+
return unless defined? LesliGuard
|
275
|
+
navigation_engine_item(title, subtitle, "guard", lesli_guard.root_path,
|
276
|
+
controller_path.include?("lesli_guard"))
|
276
277
|
end
|
277
278
|
|
278
279
|
# 08.03 Audit engine
|
data/app/lib/lesli/system.rb
CHANGED
@@ -79,6 +79,15 @@ module AccountInitializer
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
+
# 07.02 LesliHelp - Support Ticket System
|
83
|
+
if defined? LesliHelp
|
84
|
+
if self.help.blank?
|
85
|
+
self.help = LesliHelp::Account.new
|
86
|
+
self.help.account = self
|
87
|
+
self.help.save!
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
82
91
|
# 08.03 LesliAudit - System analytics
|
83
92
|
if defined? LesliAudit
|
84
93
|
if self.audit.blank?
|
data/app/models/lesli/account.rb
CHANGED
@@ -54,6 +54,7 @@ module Lesli
|
|
54
54
|
has_many :currencies
|
55
55
|
has_many :logs
|
56
56
|
|
57
|
+
has_one :help, class_name: "LesliHelp::Account"
|
57
58
|
has_one :audit, class_name: "LesliAudit::Account"
|
58
59
|
has_one :admin, class_name: "LesliAdmin::Account"
|
59
60
|
has_one :driver, class_name: "LesliDriver::Account"
|
@@ -0,0 +1,162 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
Lesli
|
4
|
+
|
5
|
+
Copyright (c) 2023, 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 · Your Smart Business Assistant.
|
21
|
+
|
22
|
+
Made with ♥ by https://www.lesli.tech
|
23
|
+
Building a better future, one line of code at a time.
|
24
|
+
|
25
|
+
@contact hello@lesli.tech
|
26
|
+
@website https://lesli.tech
|
27
|
+
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
28
|
+
|
29
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
30
|
+
// ·
|
31
|
+
|
32
|
+
=end
|
33
|
+
|
34
|
+
module Lesli
|
35
|
+
module Shared
|
36
|
+
class Dashboard < ::Lesli::ApplicationLesliRecord
|
37
|
+
self.abstract_class = true
|
38
|
+
|
39
|
+
belongs_to :user_creator, class_name: "User", foreign_key: "users_id", optional: true
|
40
|
+
|
41
|
+
after_update :verify_default_dashboard
|
42
|
+
after_create :verify_default_dashboard
|
43
|
+
|
44
|
+
enum component_ids: {}
|
45
|
+
|
46
|
+
# @return [void]
|
47
|
+
# @param account [LesliEngine::Account]
|
48
|
+
# @description Initializes a default dummy dashboard for the account. This guarantees that the users
|
49
|
+
# will be able to access the dashboard page. Even if it's empty.
|
50
|
+
# @example
|
51
|
+
# # Imagine you are adding a new engine to your instance (CloudProposal)
|
52
|
+
# # To execute this function, you must only do
|
53
|
+
# my_account = Account.first
|
54
|
+
# my_account.proposal = CloudProposal::Account.new
|
55
|
+
def self.initialize_data(account)
|
56
|
+
self.create!(
|
57
|
+
account: account,
|
58
|
+
name: "Default Dashboard",
|
59
|
+
default: true,
|
60
|
+
main: false
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Hash] Hash of containing the information of the dashboard and its components.
|
65
|
+
# @description Returns a hash with information about the dashboard and all its *components*.
|
66
|
+
# Each component is returned in the configuration view, not the render view. This means that
|
67
|
+
# this method is ment to be used when updating the dashboard
|
68
|
+
# @example
|
69
|
+
# respond_with_successful(CloudHelp::Dashboard.first.show)
|
70
|
+
def show
|
71
|
+
attributes.merge({
|
72
|
+
components: components.order(index: :asc)
|
73
|
+
# components: [{
|
74
|
+
# name: "ticket",
|
75
|
+
# component_id: "ticket"
|
76
|
+
# },{
|
77
|
+
# name: "ticket",
|
78
|
+
# component_id: "ticket"
|
79
|
+
# }]
|
80
|
+
})
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Hash] Hash containing the options to create and manage dashboards
|
84
|
+
# @param current_user [User] The user that made this request
|
85
|
+
# @param query [Hash] Query containing filters. Currently unused, but required
|
86
|
+
# @descriptions Returns a list of options needed to create and manage dashboard components. For now,
|
87
|
+
# the returned options are: A list of roles, the enoun containing the component_ids, generic configuration options
|
88
|
+
# for all dashboad components and a descriptions hash, that contains brief descriptions for each component to help
|
89
|
+
# the user understand what each component does. Any class that inherits from this one can send a block to add extra
|
90
|
+
# functionality. For example, the descriptions must be implemented directly from the engine.
|
91
|
+
# @example
|
92
|
+
# CloudHouse::Dashboard.options(User.find(2), nil)
|
93
|
+
def self.options(current_user, query)
|
94
|
+
dynamic_info = self.dynamic_info
|
95
|
+
component_model = dynamic_info[:module_model_component]
|
96
|
+
|
97
|
+
component_ids = component_model.component_ids.map do |comp|
|
98
|
+
{
|
99
|
+
value: comp,
|
100
|
+
text: comp
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
options = {
|
105
|
+
component_ids: component_ids,
|
106
|
+
#components_configuration_options: component_model.configuration_options,
|
107
|
+
descriptions: {}
|
108
|
+
}
|
109
|
+
|
110
|
+
if block_given?
|
111
|
+
yield(options)
|
112
|
+
else
|
113
|
+
return options
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
# @return [void]
|
120
|
+
# @descriptions This is an after_updated and after_create method that validates that at any moment in time, there is only
|
121
|
+
# one default dashboard in the engine. If there is another default dashboard, it's *default* field is set to false
|
122
|
+
# before committing the changes
|
123
|
+
# @example
|
124
|
+
# CloudFocus::Dasbhoard.where(default: false).first.update!(default: true)
|
125
|
+
# # This will automatically trigger this function and remove the *default* field from the old default dashboard
|
126
|
+
def verify_default_dashboard
|
127
|
+
if default
|
128
|
+
dashboards = self.class.where.not(id: id).where(account: account)
|
129
|
+
self.class.where.not(id: id).where(account: account).update_all(default: false)
|
130
|
+
end
|
131
|
+
|
132
|
+
unless self.class.where(account: account).find_by(default: true)
|
133
|
+
errors.add(:base, I18n.t("core.dashboards.messages_danger_default_dashboard_must_exist"))
|
134
|
+
raise ActiveRecord::Rollback
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Build the Rails models and engine information for
|
139
|
+
# the current engine implementing the shared dashboards
|
140
|
+
# Example: For the LesliAudit engine
|
141
|
+
# {
|
142
|
+
# :module_name => "audit",
|
143
|
+
# :module_name_full => "LesliAudit",
|
144
|
+
# :module_model => "LesliAudit::Dashboard",
|
145
|
+
# :module_model_component => "LesliAudit::Dashboard::Component"
|
146
|
+
# }
|
147
|
+
def self.dynamic_info
|
148
|
+
|
149
|
+
module_info = self.name.split("::")
|
150
|
+
|
151
|
+
module_name = module_info[0].sub("Lesli", "").downcase
|
152
|
+
|
153
|
+
{
|
154
|
+
module_name: module_name,
|
155
|
+
module_name_full: module_info[0],
|
156
|
+
module_model: "#{ module_info[0] }::Dashboard".constantize,
|
157
|
+
module_model_component: "#{ module_info[0] }::Dashboard::Component".constantize
|
158
|
+
}
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|