lesli 5.0.24 → 5.1.1

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/lesli/{item → items}/activities_controller.rb +1 -1
  3. data/app/controllers/lesli/{item → items}/discussions_controller.rb +3 -3
  4. data/app/controllers/lesli/{item → items}/tasks_controller.rb +3 -3
  5. data/app/helpers/lesli/customization_helper.rb +1 -1
  6. data/app/helpers/lesli/html_helper.rb +1 -1
  7. data/app/models/concerns/lesli/{item → items}/activities.rb +2 -2
  8. data/app/models/concerns/lesli/{item → items}/discussions.rb +2 -2
  9. data/app/models/concerns/lesli/{item → items}/tasks.rb +2 -2
  10. data/app/models/lesli/application_lesli_record.rb +1 -1
  11. data/app/models/lesli/{item → items}/activity.rb +1 -1
  12. data/app/models/lesli/{item → items}/discussion.rb +1 -1
  13. data/app/models/lesli/{item → items}/task.rb +1 -1
  14. data/app/views/lesli/partials/_application-lesli-assets.html.erb +2 -0
  15. data/config/brakeman.yml +2 -13
  16. data/lib/generators/lesli/base_generator.rb +172 -0
  17. data/lib/generators/lesli/controller/controller_generator.rb +40 -0
  18. data/lib/generators/lesli/controller/templates/controller.rb.tt +86 -0
  19. data/lib/generators/lesli/model/model_generator.rb +44 -0
  20. data/lib/generators/lesli/model/templates/model.rb.tt +16 -0
  21. data/lib/generators/lesli/scaffold/scaffold_generator.rb +47 -0
  22. data/lib/generators/lesli/service/service_generator.rb +40 -0
  23. data/lib/generators/lesli/service/templates/service.rb.tt +44 -0
  24. data/lib/generators/lesli/views/templates/_form.html.erb.tt +22 -0
  25. data/lib/generators/lesli/views/templates/index.html.erb.tt +17 -0
  26. data/lib/generators/lesli/views/templates/new.html.erb.tt +4 -0
  27. data/lib/generators/lesli/views/templates/show.html.erb.tt +22 -0
  28. data/lib/generators/lesli/views/views_generator.rb +106 -0
  29. data/lib/lesli/engine.rb +1 -23
  30. data/lib/lesli/router.rb +1 -1
  31. data/lib/lesli/version.rb +2 -2
  32. data/lib/migrate/common.rb +2 -2
  33. data/lib/migrate/items/activity_structure.rb +1 -1
  34. data/lib/migrate/items/attachment_structure.rb +1 -1
  35. data/lib/migrate/items/discussion_structure.rb +1 -1
  36. data/lib/migrate/items/subscriber_structure.rb +1 -1
  37. data/lib/migrate/items/task_structure.rb +1 -1
  38. data/lib/migrate/items/version_structure.rb +1 -1
  39. data/lib/tasks/lesli/db.rake +6 -6
  40. data/lib/tasks/lesli_tasks.rake +7 -32
  41. data/readme.md +3 -3
  42. metadata +57 -63
  43. data/app/assets/config/lesli_manifest.js +0 -42
  44. data/app/assets/images/lesli/brand/app-auth.svg +0 -9
  45. data/app/assets/images/lesli/brand/app-icon.svg +0 -48
  46. data/app/assets/images/lesli/brand/app-logo.png +0 -0
  47. data/app/assets/images/lesli/brand/app-logo.svg +0 -4
  48. data/app/assets/images/lesli/brand/favicon.png +0 -0
  49. data/app/assets/images/lesli/brand/favicon.svg +0 -61
  50. data/app/assets/images/lesli/brand/login-background.jpg +0 -0
  51. data/app/assets/images/lesli/brand/register-background.jpg +0 -0
  52. data/app/assets/javascripts/lesli/application.js +0 -1
  53. data/config/importmap.rb +0 -1
  54. data/lib/generators/application_lesli_generator_base.rb +0 -164
  55. data/lib/generators/lesli/spec/USAGE +0 -8
  56. data/lib/generators/lesli/spec/spec_generator.rb +0 -22
  57. data/lib/generators/lesli/spec/templates/spec-factory.template +0 -17
  58. data/lib/generators/lesli/spec/templates/spec-model.template +0 -70
  59. data/lib/generators/lesli/view/USAGE +0 -8
  60. data/lib/generators/lesli/view/templates/spec-factory.template +0 -17
  61. data/lib/generators/lesli/view/templates/spec-model.template +0 -70
  62. data/lib/generators/lesli/view/view_generator.rb +0 -22
  63. data/lib/lesli/r_spec.rb +0 -43
  64. data/lib/scss/_apps.scss +0 -94
  65. data/lib/scss/application.scss +0 -34
@@ -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
@@ -71,7 +71,7 @@ module Lesli
71
71
  router.resource :dashboard, only: %i[show edit]
72
72
 
73
73
  # Load Lesli items
74
- router.namespace :item do
74
+ router.namespace :items do
75
75
 
76
76
  # Load item tasks
77
77
  router.resources :tasks, only: %i[index update create]
data/lib/lesli/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Lesli
2
- VERSION = "5.0.24"
3
- BUILD = "1773615963"
2
+ VERSION = "5.1.1"
3
+ BUILD = "1776570122"
4
4
  end
@@ -40,12 +40,12 @@ module MigrationHelpers
40
40
  return [table_name, table_name_account]
41
41
  end
42
42
 
43
- def table_name_for_item(resources, item)
43
+ def table_name_for_items(resources, item)
44
44
 
45
45
  engine = infer_engine_from_namespace
46
46
 
47
47
  resource = resources.to_s.singularize
48
- table_name = "#{resource}_item_#{item}".to_sym
48
+ table_name = "#{resource}_items_#{item}".to_sym
49
49
  foreign_key = resource.sub("#{engine}_","")
50
50
 
51
51
  return [table_name, foreign_key]
@@ -35,7 +35,7 @@ module MigrationHelpers
35
35
  module ActivityStructure
36
36
  def create_table_lesli_item_activities_10(engine)
37
37
 
38
- table_name, foreign_key = table_name_for_item(engine, :activities)
38
+ table_name, foreign_key = table_name_for_items(engine, :activities)
39
39
 
40
40
  create_table table_name do |t|
41
41
 
@@ -35,7 +35,7 @@ module MigrationHelpers
35
35
  module AttachmentStructure
36
36
  def create_table_lesli_item_attachments_10(resources)
37
37
 
38
- table_name, foreign_key = table_name_for_item(resources, :attachments)
38
+ table_name, foreign_key = table_name_for_items(resources, :attachments)
39
39
 
40
40
  create_table table_name do |t|
41
41
  t.string :name
@@ -35,7 +35,7 @@ module MigrationHelpers
35
35
  module DiscussionStructure
36
36
  def create_table_lesli_item_discussions_10(engine)
37
37
 
38
- table_name, foreign_key = table_name_for_item(engine, :discussions)
38
+ table_name, foreign_key = table_name_for_items(engine, :discussions)
39
39
 
40
40
  create_table table_name do |t|
41
41
  t.text :message
@@ -35,7 +35,7 @@ module MigrationHelpers
35
35
  module SubscriberStructure
36
36
  def create_table_lesli_item_subscribers_10(resources)
37
37
 
38
- table_name, foreign_key = table_name_for_item(resources, :subscribers)
38
+ table_name, foreign_key = table_name_for_items(resources, :subscribers)
39
39
 
40
40
  create_table table_name do |t|
41
41
  t.timestamps
@@ -35,7 +35,7 @@ module MigrationHelpers
35
35
  module TaskStructure
36
36
  def create_table_lesli_item_tasks_10(engine)
37
37
 
38
- table_name, foreign_key = table_name_for_item(engine, :tasks)
38
+ table_name, foreign_key = table_name_for_items(engine, :tasks)
39
39
 
40
40
  create_table table_name do |t|
41
41
  t.string :title, null: false
@@ -35,7 +35,7 @@ module MigrationHelpers
35
35
  module VersionStructure
36
36
  def create_table_lesli_item_versions_10(resources)
37
37
 
38
- table_name, foreign_key = table_name_for_item(resources, :versions)
38
+ table_name, foreign_key = table_name_for_items(resources, :versions)
39
39
 
40
40
  create_table table_name do |t|
41
41
  t.string :column_name
@@ -85,12 +85,12 @@ namespace :lesli do
85
85
  L2.m("Drop the Lesli database (development only)")
86
86
 
87
87
  Rake::Task['db:drop'].invoke
88
- L2.info("Databases deleted")
88
+ Termline.info("Databases deleted")
89
89
 
90
90
  schema_file = Rails.root.join('db', 'schema.rb')
91
91
  if File.exist?(schema_file)
92
92
  File.delete(schema_file)
93
- L2.info("Schema.rb file deleted")
93
+ Termline.info("Schema.rb file deleted")
94
94
  end
95
95
  end
96
96
 
@@ -98,7 +98,7 @@ namespace :lesli do
98
98
  def create
99
99
 
100
100
  # print a message to let the users show the action running
101
- L2.m("Create the Lesli database")
101
+ Termline.info("Create the Lesli database")
102
102
 
103
103
  Rake::Task['db:create'].invoke
104
104
  end
@@ -142,15 +142,15 @@ namespace :lesli do
142
142
  end
143
143
 
144
144
  # scan rails routes to build the controllers index
145
- Rake::Task['lesli:shield:privileges'].invoke if defined?(LesliShield)
145
+ Rake::Task['lesli_shield:privileges'].invoke if defined?(LesliShield)
146
146
 
147
147
  if defined?(LesliBabel)
148
148
 
149
149
  # scan rails routes to build the base of translations
150
- Rake::Task['lesli:babel:scan'].invoke
150
+ Rake::Task['lesli_babel:scan'].invoke
151
151
 
152
152
  # import local translations into LesliBabel
153
- Rake::Task['lesli:babel:import'].invoke
153
+ Rake::Task['lesli_babel:import'].invoke
154
154
  end
155
155
  end
156
156
 
@@ -32,31 +32,6 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  # ·
34
34
  namespace :lesli do
35
- namespace :babel do
36
-
37
- desc "Scan and register labels"
38
- task :scan => :environment do |task, args|
39
- Rake::Task['lesli_babel:scan'].invoke
40
- end
41
-
42
- desc "Import local translations into LesliBabel"
43
- task :import => :environment do |task, args|
44
- Rake::Task['lesli_babel:import'].invoke
45
- end
46
-
47
- desc "Export translations to json files"
48
- task :export => :environment do |task, args|
49
- Rake::Task['lesli_babel:export'].invoke
50
- end
51
- end
52
-
53
- namespace :shield do
54
-
55
- desc "Syncing privileges for all the available roles"
56
- task :privileges => :environment do |task, args|
57
- Rake::Task['lesli_shield:privileges'].invoke
58
- end
59
- end
60
35
 
61
36
  desc "Lesli module status"
62
37
  task :status => :environment do |task, args|
@@ -88,18 +63,18 @@ namespace :lesli do
88
63
  end
89
64
 
90
65
  # print pretty instance information
91
- L2.br(2)
66
+ Termline.br(2)
92
67
 
93
68
  # core information
94
- L2.msg(instance)
95
- L2.br()
69
+ Termline.m(instance)
70
+ Termline.br()
96
71
 
97
72
  # print list of engines
98
- L2.table(engines)
99
- L2.br(2)
73
+ Termline.table(engines)
74
+ Termline.br(2)
100
75
 
101
- L2.m "Environment: " + Rails.env
102
- L2.br(2)
76
+ Termline.info "Environment: " + Rails.env
77
+ Termline.br(2)
103
78
 
104
79
  end
105
80
  end
data/readme.md CHANGED
@@ -122,9 +122,9 @@ RAILS_SERVE_STATIC_FILES=true rails s --environment=production
122
122
 
123
123
  ### Connect with Lesli
124
124
 
125
- * [X: @LesliTech](https://x.com/LesliTech)
126
- * [Email: hello@lesli.tech](hello@lesli.tech)
127
- * [Website: https://www.lesli.tech](https://www.lesli.tech)
125
+ * [@LesliTech](https://x.com/LesliTech)
126
+ * [hello@lesli.tech](hello@lesli.tech)
127
+ * [https://www.lesli.tech](https://www.lesli.tech)
128
128
 
129
129
 
130
130
  ### License