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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/lesli/application.css +1 -192
- data/app/controllers/lesli/abouts_controller.rb +1 -1
- data/app/controllers/lesli/{items → item}/activities_controller.rb +1 -1
- data/app/controllers/lesli/item/discussions_controller.rb +126 -0
- data/app/controllers/lesli/item/tasks_controller.rb +126 -0
- data/app/helpers/lesli/customization_helper.rb +1 -1
- data/app/helpers/lesli/html_helper.rb +1 -1
- data/app/models/concerns/lesli/item/activities.rb +106 -0
- data/app/models/concerns/lesli/item/discussions.rb +92 -0
- data/app/models/concerns/lesli/item/tasks.rb +95 -0
- data/app/models/lesli/account.rb +1 -0
- data/app/models/lesli/{items → item}/activity.rb +5 -13
- data/app/models/lesli/item/discussion.rb +10 -0
- data/{lib/lesli/r_spec.rb → app/models/lesli/item/task.rb} +9 -10
- data/app/views/lesli/partials/_application-lesli-header.html.erb +12 -0
- data/config/initializers/lesli_migration_helpers.rb +2 -2
- data/db/migrate/v1/0000000210_create_lesli_users.rb +1 -1
- data/lib/generators/lesli/base_generator.rb +172 -0
- data/lib/generators/lesli/controller/controller_generator.rb +40 -0
- data/lib/generators/lesli/controller/templates/controller.rb.tt +86 -0
- data/lib/generators/lesli/install/install_generator.rb +1 -1
- data/lib/generators/lesli/model/model_generator.rb +44 -0
- data/lib/generators/lesli/model/templates/model.rb.tt +16 -0
- data/lib/generators/lesli/scaffold/scaffold_generator.rb +47 -0
- data/lib/generators/lesli/service/service_generator.rb +40 -0
- data/lib/generators/lesli/service/templates/service.rb.tt +44 -0
- data/lib/generators/lesli/views/templates/_form.html.erb.tt +22 -0
- data/lib/generators/lesli/views/templates/index.html.erb.tt +17 -0
- data/lib/generators/lesli/views/templates/new.html.erb.tt +4 -0
- data/lib/generators/lesli/views/templates/show.html.erb.tt +22 -0
- data/lib/generators/lesli/views/views_generator.rb +106 -0
- data/lib/lesli/engine.rb +1 -23
- data/lib/lesli/router.rb +42 -43
- data/lib/lesli/version.rb +2 -2
- data/lib/migrate/common.rb +1 -1
- data/lib/migrate/items/activity_structure.rb +11 -5
- data/lib/migrate/items/discussion_structure.rb +9 -3
- data/lib/migrate/items/{action_structure.rb → task_structure.rb} +12 -6
- data/lib/migrate/shared/catalog_structure.rb +16 -0
- data/lib/tasks/lesli/db.rake +9 -0
- data/readme.md +1 -1
- metadata +58 -79
- data/app/assets/config/lesli_manifest.js +0 -42
- data/app/assets/images/lesli/brand/app-auth.svg +0 -9
- data/app/assets/images/lesli/brand/app-icon.svg +0 -48
- data/app/assets/images/lesli/brand/app-logo.png +0 -0
- data/app/assets/images/lesli/brand/app-logo.svg +0 -4
- data/app/assets/images/lesli/brand/favicon.png +0 -0
- data/app/assets/images/lesli/brand/favicon.svg +0 -61
- data/app/assets/images/lesli/brand/login-background.jpg +0 -0
- data/app/assets/images/lesli/brand/register-background.jpg +0 -0
- data/app/assets/javascripts/lesli/application.js +0 -1
- data/app/controllers/lesli/items/actions_controller.rb +0 -122
- data/app/controllers/lesli/items/discussions_controller.rb +0 -93
- data/app/models/lesli/items/action.rb +0 -15
- data/app/models/lesli/items/discussion.rb +0 -15
- data/config/importmap.rb +0 -1
- data/db/structure/00000000_locations.json +0 -32
- data/db/structure/00000020_catalogs.json +0 -0
- data/db/structure/00000201_workflows.json +0 -17
- data/db/structure/00000202_workflow_statuses.json +0 -24
- data/db/structure/00000203_workflow_associations.json +0 -14
- data/db/structure/00000204_workflow_actions.json +0 -39
- data/db/structure/00000205_workflow_checks.json +0 -27
- data/db/structure/00000300_custom_fields.json +0 -8
- data/db/structure/00000301_custom_fields.json +0 -38
- data/db/structure/00000401_custom_validations.json +0 -14
- data/db/structure/00000402_custom_validation_rules.json +0 -23
- data/db/structure/00000403_custom_validation_fields.json +0 -14
- data/lib/generators/application_lesli_generator_base.rb +0 -164
- data/lib/generators/lesli/spec/USAGE +0 -8
- data/lib/generators/lesli/spec/spec_generator.rb +0 -22
- data/lib/generators/lesli/spec/templates/spec-factory.template +0 -17
- data/lib/generators/lesli/spec/templates/spec-model.template +0 -70
- data/lib/generators/lesli/view/USAGE +0 -8
- data/lib/generators/lesli/view/templates/spec-factory.template +0 -17
- data/lib/generators/lesli/view/templates/spec-model.template +0 -70
- data/lib/generators/lesli/view/view_generator.rb +0 -22
- data/lib/scss/_apps.scss +0 -94
- data/lib/scss/application.scss +0 -34
- data/lib/tasks/lesli/docs.rake +0 -47
- data/lib/tasks/lesli/git.rake +0 -70
- data/lib/tasks/lesli/github.rake +0 -89
- data/lib/test/config.rb +0 -111
- data/lib/test/helpers/response_integration_helper.rb +0 -46
- data/lib/test/lesli.rb +0 -61
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module <%= engine_namespace %>
|
|
4
|
+
class <%= resource_class_name %> < ApplicationRecord
|
|
5
|
+
belongs_to :account
|
|
6
|
+
|
|
7
|
+
# Optional user relations
|
|
8
|
+
# belongs_to :owner, class_name: "Lesli::User"
|
|
9
|
+
# belongs_to :user, class_name: "Lesli::User"
|
|
10
|
+
|
|
11
|
+
# Optional item concerns
|
|
12
|
+
# include Lesli::Item::Tasks
|
|
13
|
+
# include Lesli::Item::Activities
|
|
14
|
+
# include Lesli::Item::Discussions
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require_relative "../base_generator"
|
|
5
|
+
|
|
6
|
+
module Lesli
|
|
7
|
+
module Generators
|
|
8
|
+
# Main Lesli scaffold generator.
|
|
9
|
+
#
|
|
10
|
+
# This generator delegates work to the specialized generators.
|
|
11
|
+
class ScaffoldGenerator < BaseGenerator
|
|
12
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
|
13
|
+
|
|
14
|
+
def invoke_model_generator
|
|
15
|
+
invoke "lesli:model", [name, *attributes]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Invokes the custom Lesli controller generator.
|
|
19
|
+
def invoke_controller_generator
|
|
20
|
+
invoke "lesli:controller", [name, *attributes]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Invokes the custom Lesli service generator.
|
|
24
|
+
def invoke_service_generator
|
|
25
|
+
invoke "lesli:service", [name, *attributes]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def invoke_views_generator
|
|
29
|
+
invoke "lesli:views", [name, *attributes]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def invoke_migration_generator
|
|
33
|
+
invoke "active_record:migration", [migration_name, *attributes]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def invoke_route_generator
|
|
37
|
+
invoke "resource_route", [resource_collection_name]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def migration_name
|
|
43
|
+
"create_#{engine_name}_#{resource_collection_name}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require_relative "../base_generator"
|
|
5
|
+
|
|
6
|
+
module Lesli
|
|
7
|
+
module Generators
|
|
8
|
+
# Generates a Lesli-style service object inside the current engine.
|
|
9
|
+
class ServiceGenerator < BaseGenerator
|
|
10
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
|
11
|
+
|
|
12
|
+
source_root File.expand_path("templates", __dir__)
|
|
13
|
+
|
|
14
|
+
# Creates the service file from the template.
|
|
15
|
+
def create_service_file
|
|
16
|
+
template "service.rb.tt", service_file_path
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# Returns the service directory inside the engine namespace.
|
|
22
|
+
#
|
|
23
|
+
# Example:
|
|
24
|
+
# app/services/lesli_support
|
|
25
|
+
# app/services/my_engine
|
|
26
|
+
# app/services/store
|
|
27
|
+
def service_directory
|
|
28
|
+
File.join(ENGINE_ROOT, "app/services", engine_name)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Returns the final service file path.
|
|
32
|
+
#
|
|
33
|
+
# Example:
|
|
34
|
+
# app/services/lesli_support/ticket_service.rb
|
|
35
|
+
def service_file_path
|
|
36
|
+
File.join(service_directory, "#{resource_name}_service.rb")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module <%= engine_namespace %>
|
|
4
|
+
class <%= service_class_name %> < Lesli::ApplicationLesliService
|
|
5
|
+
|
|
6
|
+
def find(id: nil, uid: nil)
|
|
7
|
+
scope = current_user.account.<%= engine_domain_name %>.<%= resource_collection_name %>
|
|
8
|
+
|
|
9
|
+
# Build the search hash using only present values.
|
|
10
|
+
params = { id: id, uid: uid }.compact
|
|
11
|
+
|
|
12
|
+
# Only perform the lookup when at least one filter is present.
|
|
13
|
+
super(scope.find_by(params)) if params.any?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def index
|
|
17
|
+
current_user.account.<%= engine_domain_name %>.<%= resource_collection_name %>.order(id: :desc)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create(<%= params_method_name %>)
|
|
21
|
+
<%= resource_name %> = current_user.account.<%= engine_domain_name %>.<%= resource_collection_name %>.new(<%= params_method_name %>)
|
|
22
|
+
|
|
23
|
+
if <%= resource_name %>.save
|
|
24
|
+
self.resource = <%= resource_name %>
|
|
25
|
+
else
|
|
26
|
+
self.error(<%= resource_name %>.errors.full_messages.to_sentence)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def show
|
|
33
|
+
self.resource
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def update(params)
|
|
37
|
+
self.resource.update(params)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def destroy
|
|
41
|
+
self.resource.destroy
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%%= form_with(model: <%= resource_instance %>, builder: LesliView::Forms::Builder) do |form| %>
|
|
2
|
+
<%%= form.fieldset do %>
|
|
3
|
+
<% form_attributes.each do |attribute| -%>
|
|
4
|
+
<% if attribute == "description" -%>
|
|
5
|
+
<%%= form.field_control_textarea(:<%= attribute %>, label: false) %>
|
|
6
|
+
<% else -%>
|
|
7
|
+
<%%= form.field_control(:<%= attribute %>) %>
|
|
8
|
+
<% end -%>
|
|
9
|
+
<% end -%>
|
|
10
|
+
|
|
11
|
+
<% if select_attributes.any? -%>
|
|
12
|
+
<div class="columns">
|
|
13
|
+
<% select_attributes.each do |attribute| -%>
|
|
14
|
+
<div class="column">
|
|
15
|
+
<%%= form.field_control_select(:<%= attribute %>, []) %>
|
|
16
|
+
</div>
|
|
17
|
+
<% end -%>
|
|
18
|
+
</div>
|
|
19
|
+
<% end -%>
|
|
20
|
+
<%%= form.field_control_submit %>
|
|
21
|
+
<%% end %>
|
|
22
|
+
<%% end %>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%% columns = [
|
|
2
|
+
{
|
|
3
|
+
label: "ID",
|
|
4
|
+
field: "id"
|
|
5
|
+
}
|
|
6
|
+
] %>
|
|
7
|
+
|
|
8
|
+
<%%= render(LesliView::Layout::Container.new("<%= engine_domain_name %> - <%= resource_collection_name %>")) do %>
|
|
9
|
+
<%%= render(LesliView::Components::Header.new("<%= resource_collection_name.humanize %>", new_path: new_<%= resource_name %>_path)) %>
|
|
10
|
+
<%%= render(LesliView::Components::Toolbar.new) %>
|
|
11
|
+
|
|
12
|
+
<%%= render(LesliView::Elements::Table.new(
|
|
13
|
+
columns: columns,
|
|
14
|
+
records: <%= resource_collection_instance %>.dig(:records),
|
|
15
|
+
link: -> (<%= resource_name %>) { <%= resource_name %>_path(<%= resource_name %>.id) }
|
|
16
|
+
)) %>
|
|
17
|
+
<%% end %>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%%= render(LesliView::Layout::Container.new("<%= engine_domain_name %>-<%= resource_collection_name %>")) do %>
|
|
2
|
+
|
|
3
|
+
<%%= render(LesliView::Components::Header.new("<%= resource_class_name %>")) %>
|
|
4
|
+
|
|
5
|
+
<%%= render(LesliView::Components::Tabs.new(active_tab: "<%= resource_name %>-information")) do |tabs| %>
|
|
6
|
+
<%% tabs.with_tab(id:"<%= resource_name %>-information", title:"Information", icon:"info") do %>
|
|
7
|
+
<%%= render("form") %>
|
|
8
|
+
<%% end %>
|
|
9
|
+
|
|
10
|
+
<%% tabs.with_tab(id:"<%= resource_name %>-discussions", title:"Discussions", icon:"forum") do %>
|
|
11
|
+
<%%= render(LesliView::Items::Discussions.new(<%= resource_instance %>)) %>
|
|
12
|
+
<%% end %>
|
|
13
|
+
|
|
14
|
+
<%% tabs.with_tab(id:"<%= resource_name %>-tasks", title:"Tasks", icon:"checklist") do %>
|
|
15
|
+
<%%= render(LesliView::Item::Tasks.new(<%= resource_instance %>)) %>
|
|
16
|
+
<%% end %>
|
|
17
|
+
|
|
18
|
+
<%% tabs.with_tab(id:"<%= resource_name %>-activities", title:"Activities", icon:"search_activity") do %>
|
|
19
|
+
<%%= render(LesliView::Items::Activities.new(<%= resource_instance %>)) %>
|
|
20
|
+
<%% end %>
|
|
21
|
+
<%% end %>
|
|
22
|
+
<%% end %>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require_relative "../base_generator"
|
|
5
|
+
|
|
6
|
+
module Lesli
|
|
7
|
+
module Generators
|
|
8
|
+
# Generates Lesli-style views for a resource inside the current engine.
|
|
9
|
+
#
|
|
10
|
+
# Example:
|
|
11
|
+
# rails generate lesli:views tickets subject:string description:text owner_id:integer
|
|
12
|
+
#
|
|
13
|
+
# Result:
|
|
14
|
+
# app/views/lesli_support/tickets/
|
|
15
|
+
# _form.html.erb
|
|
16
|
+
# index.html.erb
|
|
17
|
+
# show.html.erb
|
|
18
|
+
# new.html.erb
|
|
19
|
+
# edit.html.erb
|
|
20
|
+
class ViewsGenerator < BaseGenerator
|
|
21
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
|
22
|
+
|
|
23
|
+
source_root File.expand_path("templates", __dir__)
|
|
24
|
+
|
|
25
|
+
# Creates the views directory if it does not exist.
|
|
26
|
+
def create_views_directory
|
|
27
|
+
empty_directory views_directory
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Generates the shared form partial.
|
|
31
|
+
def create_form_partial
|
|
32
|
+
template "_form.html.erb.tt", File.join(views_directory, "_form.html.erb")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Generates the index view.
|
|
36
|
+
def create_index_view
|
|
37
|
+
template "index.html.erb.tt", File.join(views_directory, "index.html.erb")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Generates the show view.
|
|
41
|
+
def create_show_view
|
|
42
|
+
template "show.html.erb.tt", File.join(views_directory, "show.html.erb")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Generates the new view.
|
|
46
|
+
def create_new_view
|
|
47
|
+
template "new.html.erb.tt", File.join(views_directory, "new.html.erb")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Returns the target views directory for the current resource.
|
|
53
|
+
#
|
|
54
|
+
# Example:
|
|
55
|
+
# app/views/lesli_support/tickets
|
|
56
|
+
def views_directory
|
|
57
|
+
File.join(ENGINE_ROOT, "app/views", engine_name, resource_collection_name)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Returns only scalar-like attributes that can be rendered
|
|
61
|
+
# as regular text inputs by default.
|
|
62
|
+
def form_attributes
|
|
63
|
+
permitted_attributes.reject do |attribute|
|
|
64
|
+
attribute.end_with?("_id") || attribute == "id"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Returns attributes that look like foreign keys.
|
|
69
|
+
#
|
|
70
|
+
# Example:
|
|
71
|
+
# owner_id, category_id, priority_id
|
|
72
|
+
#
|
|
73
|
+
# These are rendered as generic select controls.
|
|
74
|
+
def select_attributes
|
|
75
|
+
permitted_attributes.select { |attribute| attribute.end_with?("_id") }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns the default columns used for the index table.
|
|
79
|
+
#
|
|
80
|
+
# We prefer to include uid first when it exists.
|
|
81
|
+
def index_columns
|
|
82
|
+
columns = []
|
|
83
|
+
|
|
84
|
+
if permitted_attributes.include?("uid")
|
|
85
|
+
columns << { label: "ID", field: "uid" }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
form_attributes.each do |attribute|
|
|
89
|
+
columns << {
|
|
90
|
+
label: attribute.humanize,
|
|
91
|
+
field: attribute
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
select_attributes.each do |attribute|
|
|
96
|
+
columns << {
|
|
97
|
+
label: attribute.delete_suffix("_id").humanize,
|
|
98
|
+
field: attribute
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
columns
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
data/lib/lesli/engine.rb
CHANGED
|
@@ -36,7 +36,7 @@ require "kaminari"
|
|
|
36
36
|
|
|
37
37
|
# · Tools used to build the Lesli Framework
|
|
38
38
|
require "L2"
|
|
39
|
-
|
|
39
|
+
require "termline"
|
|
40
40
|
require "acts_as_paranoid"
|
|
41
41
|
|
|
42
42
|
# The hole Lesli ecosystem depends on current_user, so we
|
|
@@ -48,26 +48,14 @@ require "lesli_view"
|
|
|
48
48
|
require "lesli_assets"
|
|
49
49
|
require "lesli_system"
|
|
50
50
|
|
|
51
|
-
require "importmap-rails"
|
|
52
51
|
require "turbo-rails"
|
|
53
52
|
|
|
54
53
|
module Lesli
|
|
55
54
|
class Engine < ::Rails::Engine
|
|
56
55
|
isolate_namespace Lesli
|
|
57
56
|
|
|
58
|
-
initializer "lesli.importmap", before: "importmap" do |app|
|
|
59
|
-
app.config.importmap.paths << Engine.root.join("config/importmap.rb")
|
|
60
|
-
end
|
|
61
|
-
|
|
62
57
|
initializer :lesli do |app|
|
|
63
58
|
|
|
64
|
-
|
|
65
|
-
# Lesli standard engine configuration
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# register assets manifest
|
|
69
|
-
config.assets.precompile += %w[lesli_manifest.js]
|
|
70
|
-
|
|
71
59
|
# register engine migrations path
|
|
72
60
|
unless app.root.to_s.match root.to_s
|
|
73
61
|
config.paths["db/migrate"].expanded.each do |expanded_path|
|
|
@@ -75,20 +63,10 @@ module Lesli
|
|
|
75
63
|
end
|
|
76
64
|
end
|
|
77
65
|
|
|
78
|
-
|
|
79
|
-
# Lesli Framework configuration
|
|
80
|
-
|
|
81
|
-
|
|
82
66
|
# Default languages
|
|
83
67
|
config.i18n.default_locale = :en
|
|
84
68
|
config.i18n.available_locales = [:en]
|
|
85
69
|
|
|
86
|
-
# Force to not use digest,
|
|
87
|
-
# if this is not false Rails will fingerprint the assets by default
|
|
88
|
-
# and precompile will be needed, so, donot digest if not production
|
|
89
|
-
#config.assets.digest = false unless Rails.env.production?
|
|
90
|
-
|
|
91
|
-
|
|
92
70
|
# Lesli Framework Mailer configuration
|
|
93
71
|
|
|
94
72
|
|
data/lib/lesli/router.rb
CHANGED
|
@@ -31,58 +31,57 @@ Building a better future, one line of code at a time.
|
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
33
|
# ·
|
|
34
|
-
module Lesli
|
|
35
|
-
module Router
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if !defined?(LesliShield) && defined?(Devise)
|
|
44
|
-
Rails.application.routes.draw do
|
|
45
|
-
devise_for(:users, class_name: "Lesli::User", module: :devise)
|
|
46
|
-
end
|
|
34
|
+
module Lesli
|
|
35
|
+
module Router
|
|
36
|
+
def self.login(router, path = "")
|
|
37
|
+
# Prefer LesliShield’s dedicated routes if installed
|
|
38
|
+
if defined?(LesliShield)
|
|
39
|
+
# Make LesliShield::Router accept router too (recommended)
|
|
40
|
+
LesliShield::Router.mount_login_at(router, path)
|
|
41
|
+
elsif defined?(Devise)
|
|
42
|
+
router.devise_for :users, class_name: "Lesli::User", module: :devise
|
|
47
43
|
end
|
|
48
44
|
end
|
|
49
45
|
|
|
50
|
-
def self.mount
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
46
|
+
def self.mount(router, path = "")
|
|
47
|
+
login(router, path)
|
|
48
|
+
|
|
49
|
+
router.root to: "lesli/abouts#welcome", as: :welcome
|
|
50
|
+
|
|
51
|
+
router.mount Lesli::Engine => "/lesli" if defined?(Lesli)
|
|
52
|
+
router.mount LesliBell::Engine => "/bell" if defined?(LesliBell)
|
|
53
|
+
router.mount LesliAdmin::Engine => "/admin" if defined?(LesliAdmin)
|
|
54
|
+
router.mount LesliAudit::Engine => "/audit" if defined?(LesliAudit)
|
|
55
|
+
router.mount LesliBabel::Engine => "/babel" if defined?(LesliBabel)
|
|
56
|
+
router.mount LesliMailer::Engine => "/mailer" if defined?(LesliMailer)
|
|
57
|
+
router.mount LesliShield::Engine => "/shield" if defined?(LesliShield)
|
|
58
|
+
router.mount LesliPapers::Engine => "/papers" if defined?(LesliPapers)
|
|
59
|
+
router.mount LesliSupport::Engine => "/support" if defined?(LesliSupport)
|
|
60
|
+
router.mount LesliSecurity::Engine => "/security" if defined?(LesliSecurity)
|
|
61
|
+
router.mount LesliCalendar::Engine => "/calendar" if defined?(LesliCalendar)
|
|
62
|
+
router.mount LesliContacts::Engine => "/contacts" if defined?(LesliContacts)
|
|
63
|
+
router.mount LesliDashboard::Engine => "/dashboard" if defined?(LesliDashboard)
|
|
68
64
|
end
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
# Shared default routes for any Lesli engine
|
|
67
|
+
def self.mount_lesli_engine_routes(router)
|
|
68
|
+
router.root to: "dashboards#show"
|
|
69
|
+
|
|
70
|
+
# Load dashboard resources
|
|
71
|
+
router.resource :dashboard, only: %i[show edit]
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
# Load Lesli items
|
|
74
|
+
router.namespace :item do
|
|
75
75
|
|
|
76
|
-
#
|
|
77
|
-
|
|
76
|
+
# Load item tasks
|
|
77
|
+
router.resources :tasks, only: %i[index update create]
|
|
78
78
|
|
|
79
|
-
#
|
|
80
|
-
|
|
79
|
+
# Load item discussions
|
|
80
|
+
router.resources :discussions, only: %i[index update create]
|
|
81
81
|
end
|
|
82
|
-
end
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
# Optional: health check inside engine scope (pick a consistent path)
|
|
84
|
+
router.get "up", to: "/rails/health#show"
|
|
86
85
|
end
|
|
87
|
-
end
|
|
86
|
+
end
|
|
88
87
|
end
|
data/lib/lesli/version.rb
CHANGED
data/lib/migrate/common.rb
CHANGED
|
@@ -45,7 +45,7 @@ module MigrationHelpers
|
|
|
45
45
|
engine = infer_engine_from_namespace
|
|
46
46
|
|
|
47
47
|
resource = resources.to_s.singularize
|
|
48
|
-
table_name = "#{resource}
|
|
48
|
+
table_name = "#{resource}_item_#{item}".to_sym
|
|
49
49
|
foreign_key = resource.sub("#{engine}_","")
|
|
50
50
|
|
|
51
51
|
return [table_name, foreign_key]
|
|
@@ -33,10 +33,10 @@ Building a better future, one line of code at a time.
|
|
|
33
33
|
module MigrationHelpers
|
|
34
34
|
module Items
|
|
35
35
|
module ActivityStructure
|
|
36
|
-
def create_table_lesli_item_activities_10(
|
|
36
|
+
def create_table_lesli_item_activities_10(engine)
|
|
37
|
+
|
|
38
|
+
table_name, foreign_key = table_name_for_item(engine, :activities)
|
|
37
39
|
|
|
38
|
-
table_name, foreign_key = table_name_for_item(resources, :activities)
|
|
39
|
-
|
|
40
40
|
create_table table_name do |t|
|
|
41
41
|
|
|
42
42
|
# Contenido
|
|
@@ -51,11 +51,17 @@ module MigrationHelpers
|
|
|
51
51
|
# Metadatos opcionales (JSON)
|
|
52
52
|
t.json :metadata, default: {}
|
|
53
53
|
|
|
54
|
+
# Polymorphic target
|
|
55
|
+
t.string :subject_type, null: false
|
|
56
|
+
t.bigint :subject_id, null: false
|
|
57
|
+
|
|
54
58
|
t.timestamps
|
|
59
|
+
t.datetime :deleted_at, index: true
|
|
55
60
|
end
|
|
56
61
|
|
|
57
|
-
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
58
|
-
add_reference(table_name,
|
|
62
|
+
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
63
|
+
add_reference(table_name, :account, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
64
|
+
add_index(table_name, [:account_id, :subject_type, :subject_id], name: "#{table_name}_activities_type_id")
|
|
59
65
|
end
|
|
60
66
|
end
|
|
61
67
|
end
|
|
@@ -33,17 +33,23 @@ Building a better future, one line of code at a time.
|
|
|
33
33
|
module MigrationHelpers
|
|
34
34
|
module Items
|
|
35
35
|
module DiscussionStructure
|
|
36
|
-
def create_table_lesli_item_discussions_10(
|
|
36
|
+
def create_table_lesli_item_discussions_10(engine)
|
|
37
37
|
|
|
38
|
-
table_name, foreign_key = table_name_for_item(
|
|
38
|
+
table_name, foreign_key = table_name_for_item(engine, :discussions)
|
|
39
39
|
|
|
40
40
|
create_table table_name do |t|
|
|
41
41
|
t.text :message
|
|
42
|
+
|
|
43
|
+
# Polymorphic target
|
|
44
|
+
t.string :discussable_type, null: false
|
|
45
|
+
t.bigint :discussable_id, null: false
|
|
46
|
+
|
|
42
47
|
t.timestamps
|
|
48
|
+
t.datetime :deleted_at, index: true
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
46
|
-
add_reference(table_name,
|
|
52
|
+
add_reference(table_name, :account, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
47
53
|
end
|
|
48
54
|
end
|
|
49
55
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Lesli
|
|
4
4
|
|
|
5
|
-
Copyright (c)
|
|
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,20 +32,26 @@ Building a better future, one line of code at a time.
|
|
|
32
32
|
|
|
33
33
|
module MigrationHelpers
|
|
34
34
|
module Items
|
|
35
|
-
module
|
|
36
|
-
def
|
|
35
|
+
module TaskStructure
|
|
36
|
+
def create_table_lesli_item_tasks_10(engine)
|
|
37
37
|
|
|
38
|
-
table_name, foreign_key = table_name_for_item(
|
|
38
|
+
table_name, foreign_key = table_name_for_item(engine, :tasks)
|
|
39
39
|
|
|
40
40
|
create_table table_name do |t|
|
|
41
41
|
t.string :title, null: false
|
|
42
42
|
t.boolean :done, default: false, null: false
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
# Polymorphic target
|
|
45
|
+
t.string :taskable_type, null: false
|
|
46
|
+
t.bigint :taskable_id, null: false
|
|
47
|
+
|
|
44
48
|
t.timestamps
|
|
49
|
+
t.datetime :deleted_at, index: true
|
|
45
50
|
end
|
|
46
51
|
|
|
47
52
|
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
48
|
-
add_reference(table_name,
|
|
53
|
+
add_reference(table_name, :account, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
54
|
+
add_index(table_name, [:account_id, :taskable_type, :taskable_id], name: "#{table_name}_taskable_type_id".to_sym)
|
|
49
55
|
end
|
|
50
56
|
end
|
|
51
57
|
end
|
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
module MigrationHelpers
|
|
3
3
|
module Shared
|
|
4
4
|
module CatalogStructure
|
|
5
|
+
# def create_table_lesli_shared_catalogs_10(engine)
|
|
6
|
+
|
|
7
|
+
# table_name, table_name_account = table_name_for_shared(engine, :catalogs)
|
|
8
|
+
|
|
9
|
+
# create_table table_name do |t|
|
|
10
|
+
# t.string :key, index: true
|
|
11
|
+
# t.string :name
|
|
12
|
+
# t.integer :order
|
|
13
|
+
# t.boolean :default, default: false
|
|
14
|
+
# t.timestamps
|
|
15
|
+
# end
|
|
16
|
+
# add_reference(table_name, :parent, null: true, foreign_key: { to_table: table_name }, index: true)
|
|
17
|
+
# add_reference(table_name, :catalog, null: true, foreign_key: { to_table: table_name }, index: true)
|
|
18
|
+
# add_reference(table_name, :account, null: false, foreign_key: { to_table: table_name_account }, index: true)
|
|
19
|
+
|
|
20
|
+
# end
|
|
5
21
|
def create_table_lesli_shared_catalogs_10(engine)
|
|
6
22
|
|
|
7
23
|
table_name, table_name_account = table_name_for_shared(engine, :catalogs)
|
data/lib/tasks/lesli/db.rake
CHANGED
|
@@ -44,6 +44,15 @@ namespace :lesli do
|
|
|
44
44
|
status()
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
desc "Create, migrate, seed & prepare the Lesli database (development only)"
|
|
48
|
+
task :dev => :environment do |task, args|
|
|
49
|
+
create()
|
|
50
|
+
migrate()
|
|
51
|
+
seed()
|
|
52
|
+
prepare()
|
|
53
|
+
status()
|
|
54
|
+
end
|
|
55
|
+
|
|
47
56
|
desc "Migrate, prepare && user the Lesli database"
|
|
48
57
|
task :deploy => :environment do |task, args|
|
|
49
58
|
create()
|
data/readme.md
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
## Introduction
|
|
36
36
|
|
|
37
|
-
Lesli is an open-source
|
|
37
|
+
Lesli is an open-source framework built to create scalable, secure, and modular software products.
|
|
38
38
|
|
|
39
39
|
Built on top of **Ruby on Rails, PostgreSQL, Hotwire, and modern frontend tooling**, Lesli provides the infrastructure, architecture, and reusable components needed to build production-ready SaaS platforms faster.
|
|
40
40
|
|