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
@@ -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,4 @@
1
+ <%%= render(LesliView::Layout::Container.new("new-<%= resource_name %>")) do %>
2
+ <%%= render(LesliView::Components::Header.new("New <%= resource_class_name %>")) %>
3
+ <%%= render("form") %>
4
+ <%% 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
- #require "useragent"
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
- def self.login path=""
38
-
39
- # Load dedicated mounting routes for devise from the LesliShield engine
40
- LesliShield::Router.mount_login_at(path) if defined?(LesliShield);
41
-
42
- # Load generic yet standard routes if LesliShield is not installed
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
- self.login
52
- Rails.application.routes.draw do
53
- root to: "lesli/abouts#welcome", as: :welcome
54
- mount Lesli::Engine => "/lesli" if defined?(Lesli)
55
- mount LesliBell::Engine => "/bell" if defined?(LesliBell)
56
- mount LesliAdmin::Engine => "/admin" if defined?(LesliAdmin)
57
- mount LesliAudit::Engine => "/audit" if defined?(LesliAudit)
58
- mount LesliBabel::Engine => "/babel" if defined?(LesliBabel)
59
- mount LesliMailer::Engine => "/mailer" if defined?(LesliMailer)
60
- mount LesliShield::Engine => "/shield" if defined?(LesliShield)
61
- mount LesliPapers::Engine => "/papers" if defined?(LesliPapers)
62
- mount LesliSupport::Engine => "/support" if defined?(LesliSupport)
63
- mount LesliSecurity::Engine => "/security" if defined?(LesliSecurity)
64
- mount LesliCalendar::Engine => "/calendar" if defined?(LesliCalendar)
65
- mount LesliContacts::Engine => "/contacts" if defined?(LesliContacts)
66
- mount LesliDashboard::Engine => "/dashboard" if defined?(LesliDashboard)
67
- end
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
- def self.mount_routes_for lesli_engine
71
- lesli_engine::Engine.routes.draw do
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
- # Dashboard alias
74
- root to: "dashboards#show"
73
+ # Load Lesli items
74
+ router.namespace :item do
75
75
 
76
- # Dashboard management
77
- resource :dashboard, only: [:show, :edit]
76
+ # Load item tasks
77
+ router.resources :tasks, only: %i[index update create]
78
78
 
79
- #
80
- get "up" => "/rails/health#show"
79
+ # Load item discussions
80
+ router.resources :discussions, only: %i[index update create]
81
81
  end
82
- end
83
82
 
84
- def self.mount_dashboard_for lesli_engine
85
- self.mount_routes_for(lesli_engine)
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
@@ -1,4 +1,4 @@
1
1
  module Lesli
2
- VERSION = "5.0.23"
3
- BUILD = "1771707881"
2
+ VERSION = "5.1.0"
3
+ BUILD = "1774678451"
4
4
  end
@@ -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}_#{item}".to_sym
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(resources)
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 }) unless resources == :lesli_users
58
- add_reference(table_name, foreign_key, foreign_key: { to_table: resources })
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(resources)
36
+ def create_table_lesli_item_discussions_10(engine)
37
37
 
38
- table_name, foreign_key = table_name_for_item(resources, :discussions)
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, foreign_key, foreign_key: { to_table: resources })
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) 2025, 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,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 ActionStructure
36
- def create_table_lesli_item_actions_10(resources)
35
+ module TaskStructure
36
+ def create_table_lesli_item_tasks_10(engine)
37
37
 
38
- table_name, foreign_key = table_name_for_item(resources, :actions)
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
- t.datetime :deleted_at, index: true
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, foreign_key, foreign_key: { to_table: resources })
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)
@@ -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 SaaS development framework built to create scalable, secure, and modular software products.
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