lesli_support 1.2.2 → 1.2.3

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -0
  3. data/app/assets/stylesheets/lesli_support/application.css +180 -8
  4. data/app/controllers/lesli_support/items/attachments_controller.rb +11 -0
  5. data/app/controllers/lesli_support/items/discussions_controller.rb +5 -0
  6. data/app/controllers/lesli_support/items/tasks_controller.rb +5 -0
  7. data/app/controllers/lesli_support/tickets_controller.rb +4 -9
  8. data/app/models/lesli_support/account.rb +4 -1
  9. data/app/models/lesli_support/catalog.rb +1 -1
  10. data/app/models/lesli_support/items/activity.rb +3 -0
  11. data/app/models/lesli_support/items/attachment.rb +9 -0
  12. data/app/models/lesli_support/items/discussion.rb +3 -0
  13. data/app/models/lesli_support/items/task.rb +3 -0
  14. data/app/models/lesli_support/ticket.rb +12 -39
  15. data/app/services/lesli_support/catalog_service.rb +5 -5
  16. data/app/services/lesli_support/ticket_service.rb +85 -16
  17. data/app/views/lesli_support/dashboards/_component-tickets-created.html.erb +3 -3
  18. data/app/views/lesli_support/tickets/_form.html.erb +1 -1
  19. data/app/views/lesli_support/tickets/show.html.erb +12 -10
  20. data/config/locales/translations.en.yml +30 -1
  21. data/config/locales/translations.es.yml +30 -1
  22. data/config/locales/translations.fr.yml +30 -1
  23. data/config/locales/translations.it.yml +30 -1
  24. data/config/locales/translations.pt.yml +30 -1
  25. data/config/routes.rb +0 -1
  26. data/db/migrate/v1/0702000210_create_lesli_support_item_attachments.rb +5 -0
  27. data/lib/lesli_support/engine.rb +0 -4
  28. data/lib/lesli_support/version.rb +2 -2
  29. data/readme.md +14 -2
  30. metadata +9 -8
  31. data/app/assets/config/lesli_support_manifest.js +0 -38
  32. data/app/assets/stylesheets/lesli_support/application.tailwind.css +0 -0
  33. data/app/controllers/lesli_support/ticket/discussions_controller.rb +0 -4
  34. data/app/helpers/lesli_support/ticket/discussions_helper.rb +0 -4
  35. data/app/models/lesli_support/ticket/discussion.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c185b1be1e8d55c119d4f13a78497fde573b7b2dda79537b3c8e4fdd48ff3c4
4
- data.tar.gz: 9afad423911f1dd82442120986a65c002f4e075cfad8eab44177ca8a05432fc6
3
+ metadata.gz: fb316caaf1ac5c3b40150e368dab2210063a280a8cac3185ed200bdd3e473fae
4
+ data.tar.gz: 5bd283f9f7fdf549079f28aa3a80ae5e5026ce7529b8604e6287ece702067767
5
5
  SHA512:
6
- metadata.gz: db5086f6f7adac9828c774d26abfed313bf9342e13a30766e6fcc2520dc1676379d60c445b7a07eb5e384bda8dba953d6af3fdb0fd772603f361790016e4cfdc
7
- data.tar.gz: 5cec3d41602e48cf7dd332ac932a4245b2560a543e15623ecec6da8c483ebdf1ba47b6eed52ece77b78abb3aa74d4eb24c79baae5856302c3eb9d32db3d90cc1
6
+ metadata.gz: 48e6e231469bd7243e48f1910c8d9d4e71f39d6dccde00e5b7c1f1e410d8ef32f2d9de149be46e8434756f4373e93e217ce4230cc354a17d76dd895f75d8fc1b
7
+ data.tar.gz: 559d4befde444da76cc4826b6c8eaaf4003c833725943f60589c4306a7bb6c2a3552c04a33f3689acfe456ab67b75263bc253873b7acf0ef41f79cd7356ca3cc
data/Rakefile CHANGED
@@ -5,3 +5,6 @@ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
5
5
  load "rails/tasks/engine.rake"
6
6
 
7
7
  require "bundler/gem_tasks"
8
+
9
+ desc "Run engine tests through the dummy Rails application"
10
+ task test: "app:test"
@@ -1,9 +1,181 @@
1
- /*!**************************************************************************************************************************************************************!*\
2
- !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[0].use[1]!./node_modules/sass-loader/dist/cjs.js!../LesliSupport/lib/scss/application.scss ***!
3
- \**************************************************************************************************************************************************************/
4
- .lesli-support-tickets .lesli-form > fieldset {
5
- padding: 3rem 6rem;
6
- }
7
- .lesli-support-tickets .lesli-form > fieldset fieldset {
8
- margin-bottom: 1.5rem;
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties;
3
+ @layer theme, utilities;
4
+ @layer theme {
5
+ :root, :host {
6
+ --color-slate-100: oklch(96.8% 0.007 247.896);
7
+ --color-slate-200: oklch(92.9% 0.013 255.508);
8
+ --color-slate-300: oklch(86.9% 0.022 252.894);
9
+ --color-slate-500: oklch(55.4% 0.046 257.417);
10
+ --spacing: 0.25rem;
11
+ --text-sm: 0.875rem;
12
+ --text-sm--line-height: calc(1.25 / 0.875);
13
+ --radius-lg: 0.5rem;
14
+ }
15
+ }
16
+ @layer utilities {
17
+ .my-6 {
18
+ margin-block: calc(var(--spacing) * 6);
19
+ }
20
+ .mb-3 {
21
+ margin-bottom: calc(var(--spacing) * 3);
22
+ }
23
+ .block {
24
+ display: block;
25
+ }
26
+ .grid {
27
+ display: grid;
28
+ }
29
+ .w-full {
30
+ width: 100%;
31
+ }
32
+ .grid-cols-1 {
33
+ grid-template-columns: repeat(1, minmax(0, 1fr));
34
+ }
35
+ .gap-4 {
36
+ gap: calc(var(--spacing) * 4);
37
+ }
38
+ .rounded-lg {
39
+ border-radius: var(--radius-lg);
40
+ }
41
+ .border {
42
+ border-style: var(--tw-border-style);
43
+ border-width: 1px;
44
+ }
45
+ .border-0 {
46
+ border-style: var(--tw-border-style);
47
+ border-width: 0px;
48
+ }
49
+ .border-t {
50
+ border-top-style: var(--tw-border-style);
51
+ border-top-width: 1px;
52
+ }
53
+ .border-slate-200 {
54
+ border-color: var(--color-slate-200);
55
+ }
56
+ .border-slate-300 {
57
+ border-color: var(--color-slate-300);
58
+ }
59
+ .bg-slate-100 {
60
+ background-color: var(--color-slate-100);
61
+ }
62
+ .px-3 {
63
+ padding-inline: calc(var(--spacing) * 3);
64
+ }
65
+ .py-2 {
66
+ padding-block: calc(var(--spacing) * 2);
67
+ }
68
+ .text-center {
69
+ text-align: center;
70
+ }
71
+ .text-sm {
72
+ font-size: var(--text-sm);
73
+ line-height: var(--tw-leading, var(--text-sm--line-height));
74
+ }
75
+ .text-slate-500 {
76
+ color: var(--color-slate-500);
77
+ }
78
+ .shadow-sm {
79
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
80
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
81
+ }
82
+ .disabled\:cursor-not-allowed:disabled {
83
+ cursor: not-allowed;
84
+ }
85
+ @media (width >= 48rem) {
86
+ .md\:grid-cols-3 {
87
+ grid-template-columns: repeat(3, minmax(0, 1fr));
88
+ }
89
+ }
90
+ }
91
+ @property --tw-border-style {
92
+ syntax: "*";
93
+ inherits: false;
94
+ initial-value: solid;
95
+ }
96
+ @property --tw-shadow {
97
+ syntax: "*";
98
+ inherits: false;
99
+ initial-value: 0 0 #0000;
100
+ }
101
+ @property --tw-shadow-color {
102
+ syntax: "*";
103
+ inherits: false;
104
+ }
105
+ @property --tw-shadow-alpha {
106
+ syntax: "<percentage>";
107
+ inherits: false;
108
+ initial-value: 100%;
109
+ }
110
+ @property --tw-inset-shadow {
111
+ syntax: "*";
112
+ inherits: false;
113
+ initial-value: 0 0 #0000;
114
+ }
115
+ @property --tw-inset-shadow-color {
116
+ syntax: "*";
117
+ inherits: false;
118
+ }
119
+ @property --tw-inset-shadow-alpha {
120
+ syntax: "<percentage>";
121
+ inherits: false;
122
+ initial-value: 100%;
123
+ }
124
+ @property --tw-ring-color {
125
+ syntax: "*";
126
+ inherits: false;
127
+ }
128
+ @property --tw-ring-shadow {
129
+ syntax: "*";
130
+ inherits: false;
131
+ initial-value: 0 0 #0000;
132
+ }
133
+ @property --tw-inset-ring-color {
134
+ syntax: "*";
135
+ inherits: false;
136
+ }
137
+ @property --tw-inset-ring-shadow {
138
+ syntax: "*";
139
+ inherits: false;
140
+ initial-value: 0 0 #0000;
141
+ }
142
+ @property --tw-ring-inset {
143
+ syntax: "*";
144
+ inherits: false;
145
+ }
146
+ @property --tw-ring-offset-width {
147
+ syntax: "<length>";
148
+ inherits: false;
149
+ initial-value: 0px;
150
+ }
151
+ @property --tw-ring-offset-color {
152
+ syntax: "*";
153
+ inherits: false;
154
+ initial-value: #fff;
155
+ }
156
+ @property --tw-ring-offset-shadow {
157
+ syntax: "*";
158
+ inherits: false;
159
+ initial-value: 0 0 #0000;
160
+ }
161
+ @layer properties {
162
+ @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
163
+ *, ::before, ::after, ::backdrop {
164
+ --tw-border-style: solid;
165
+ --tw-shadow: 0 0 #0000;
166
+ --tw-shadow-color: initial;
167
+ --tw-shadow-alpha: 100%;
168
+ --tw-inset-shadow: 0 0 #0000;
169
+ --tw-inset-shadow-color: initial;
170
+ --tw-inset-shadow-alpha: 100%;
171
+ --tw-ring-color: initial;
172
+ --tw-ring-shadow: 0 0 #0000;
173
+ --tw-inset-ring-color: initial;
174
+ --tw-inset-ring-shadow: 0 0 #0000;
175
+ --tw-ring-inset: initial;
176
+ --tw-ring-offset-width: 0px;
177
+ --tw-ring-offset-color: #fff;
178
+ --tw-ring-offset-shadow: 0 0 #0000;
179
+ }
180
+ }
9
181
  }
@@ -0,0 +1,11 @@
1
+ module LesliSupport
2
+ module Items
3
+ class AttachmentsController < Lesli::Items::AttachmentsController
4
+ private
5
+
6
+ def allowed_attachable_classes
7
+ [LesliSupport::Ticket]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,6 +1,11 @@
1
1
  module LesliSupport
2
2
  module Items
3
3
  class DiscussionsController < Lesli::Items::DiscussionsController
4
+ private
5
+
6
+ def allowed_discussable_classes
7
+ [LesliSupport::Ticket]
8
+ end
4
9
  end
5
10
  end
6
11
  end
@@ -1,6 +1,11 @@
1
1
  module LesliSupport
2
2
  module Items
3
3
  class TasksController < Lesli::Items::TasksController
4
+ private
5
+
6
+ def allowed_taskable_classes
7
+ [LesliSupport::Ticket]
8
+ end
4
9
  end
5
10
  end
6
11
  end
@@ -56,7 +56,6 @@ module LesliSupport
56
56
  if ticket.successful?
57
57
  success('ticket creado de forma exitosass')
58
58
  respond_with_lesli(
59
- #:html => redirect_to(ticket_path(@ticket.id)),
60
59
  :turbo => stream_redirection(ticket_path(@ticket.id))
61
60
  )
62
61
  else
@@ -67,26 +66,22 @@ module LesliSupport
67
66
  end
68
67
 
69
68
  def update
69
+ @ticket.update(ticket_params)
70
70
 
71
- if @ticket.update(ticket_params)
72
- # log(
73
- # subject: @invite,
74
- # description: "Ticket updated successfully"
75
- # )
71
+ if @ticket.successful?
76
72
  respond_with_lesli(
77
73
  :turbo => stream_notification_success("Ticket updated successfully")
78
74
  )
79
75
  else
80
76
  respond_with_lesli(
81
- :turbo => stream_notification_danger(@ticket.errors)
82
- #:turbo => stream_notification_danger(@ticket.errors.full_messages.to_sentence)
77
+ :turbo => stream_notification_danger(@ticket.errors_as_sentence)
83
78
  )
84
79
  end
85
80
  end
86
81
 
87
82
  def destroy
88
83
  return respond_with_not_found unless @ticket
89
- return respond_with_unauthorized unless @ticket.is_editable_by?(current_user)
84
+ return respond_with_forbidden unless @ticket.is_editable_by?(current_user)
90
85
 
91
86
  ticket_destroy_response = TicketServices.destroy(current_user, @ticket)
92
87
 
@@ -32,7 +32,10 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  module LesliSupport
34
34
  class Account < ApplicationRecord
35
- belongs_to :account, class_name: "Lesli::Account"
35
+ belongs_to :account,
36
+ class_name: "Lesli::Account",
37
+ inverse_of: :support
38
+ validates :account_id, uniqueness: true
36
39
  has_many :dashboards
37
40
  has_many :catalogs, class_name: "Catalog"
38
41
  has_many :tickets
@@ -1,6 +1,6 @@
1
1
  module LesliSupport
2
2
  class Catalog < Lesli::Shared::Catalog
3
- belongs_to :account
3
+ belongs_to :account, class_name: "LesliSupport::Account"
4
4
  has_many :items
5
5
  end
6
6
  end
@@ -1,6 +1,9 @@
1
1
  module LesliSupport
2
2
  module Items
3
3
  class Activity < Lesli::Items::Activity
4
+ self.table_name = "lesli_support_items_activities"
5
+
6
+ belongs_to :account, class_name: "LesliSupport::Account"
4
7
  end
5
8
  end
6
9
  end
@@ -0,0 +1,9 @@
1
+ module LesliSupport
2
+ module Items
3
+ class Attachment < Lesli::Items::Attachment
4
+ self.table_name = "lesli_support_items_attachments"
5
+
6
+ belongs_to :account, class_name: "LesliSupport::Account"
7
+ end
8
+ end
9
+ end
@@ -1,6 +1,9 @@
1
1
  module LesliSupport
2
2
  module Items
3
3
  class Discussion < Lesli::Items::Discussion
4
+ self.table_name = "lesli_support_items_discussions"
5
+
6
+ belongs_to :account, class_name: "LesliSupport::Account"
4
7
  end
5
8
  end
6
9
  end
@@ -1,6 +1,9 @@
1
1
  module LesliSupport
2
2
  module Items
3
3
  class Task < Lesli::Items::Task
4
+ self.table_name = "lesli_support_items_tasks"
5
+
6
+ belongs_to :account, class_name: "LesliSupport::Account"
4
7
  end
5
8
  end
6
9
  end
@@ -32,7 +32,7 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  module LesliSupport
34
34
  class Ticket < Lesli::ApplicationLesliRecord
35
- belongs_to :account
35
+ belongs_to :account, class_name: "LesliSupport::Account"
36
36
  belongs_to :owner, class_name: "Lesli::User"
37
37
  belongs_to :user, class_name: "Lesli::User"
38
38
 
@@ -44,15 +44,22 @@ module LesliSupport
44
44
  # Items
45
45
  include Lesli::Items::Tasks
46
46
  include Lesli::Items::Activities
47
- include Lesli::Items::Discussions
48
- #has_many :discussions, class_name: "LesliSupport::Item::Discussion"
47
+ include Lesli::Items::Discussions
48
+ include Lesli::Items::Attachments
49
49
 
50
- # include Lesli::Items::Attachments
51
50
  # include Lesli::Items::Subscribers
52
51
 
53
52
  # Hooks
54
53
  before_create :before_create_ticket
55
- after_save :after_save_activities
54
+
55
+ # Shared items belong to the same engine account as the ticket.
56
+ def lesli_item_account
57
+ account
58
+ end
59
+
60
+ def lesli_item_accessible_by?(user)
61
+ user.present? && account.account == user.account
62
+ end
56
63
 
57
64
  private
58
65
 
@@ -65,39 +72,5 @@ module LesliSupport
65
72
  end
66
73
  end
67
74
 
68
- def after_save_activities
69
-
70
- if self.saved_change_to_owner_id?
71
- self.activities_create(
72
- description: "Agent assigned #{self.owner.name}",
73
- activity_code: :owner_id,
74
- metadata: { owner_id: self.owner.id }
75
- )
76
- end
77
-
78
- if self.saved_change_to_type_id?
79
- self.activities_create(
80
- description: "Ticket type updated to #{self.type.name}",
81
- activity_code: :type_id,
82
- metadata: { type_id: self.type.id }
83
- )
84
- end
85
-
86
- if self.saved_change_to_category_id?
87
- self.activities_create(
88
- description: "Ticket category updated to #{self.category.name}",
89
- activity_code: :category_id,
90
- metadata: { category_id: self.category.id }
91
- )
92
- end
93
-
94
- if self.saved_change_to_priority_id?
95
- self.activities_create(
96
- description: "Ticket priority updated to #{self.priority.name}",
97
- activity_code: :priority_id,
98
- metadata: { priority_id: self.priority.id }
99
- )
100
- end
101
- end
102
75
  end
103
76
  end
@@ -34,7 +34,7 @@ module LesliSupport
34
34
  class CatalogService < Lesli::ApplicationLesliService
35
35
 
36
36
  def find ticket_id
37
- super(current_user.account.help.tickets.find_by(id: ticket_id))
37
+ super(current_user.account.support.tickets.find_by(id: ticket_id))
38
38
  end
39
39
 
40
40
  def index
@@ -55,7 +55,7 @@ module LesliSupport
55
55
  .page(query[:pagination][:page])
56
56
  .per(query[:pagination][:perPage])
57
57
 
58
- current_user.account.help.tickets.left_joins(
58
+ current_user.account.support.tickets.left_joins(
59
59
  :priority,
60
60
  :type,
61
61
  :workspace,
@@ -79,8 +79,8 @@ module LesliSupport
79
79
 
80
80
  def create(ticket_params)
81
81
 
82
- ticket = current_user.account.help.tickets.new(ticket_params)
83
- #ticket.source = Catalog::TicketSource.cloud_help_source(current_user.account.help)
82
+ ticket = current_user.account.support.tickets.new(ticket_params)
83
+ #ticket.source = Catalog::TicketSource.cloud_help_source(current_user.account.support)
84
84
  ticket.creator = current_user
85
85
  ticket.user = current_user
86
86
 
@@ -102,7 +102,7 @@ module LesliSupport
102
102
  end
103
103
 
104
104
  def show()
105
- return current_user.account.help.tickets.left_joins(
105
+ return current_user.account.support.tickets.left_joins(
106
106
  :user, :creator
107
107
  ).select(
108
108
  :id,
@@ -63,26 +63,28 @@ module LesliSupport
63
63
  end
64
64
 
65
65
  def create(ticket_params)
66
-
67
66
  ticket = current_user.account.support.tickets.new(ticket_params)
68
- #ticket.source = Catalog::TicketSource.cloud_help_source(current_user.account.help)
69
67
  ticket.owner = current_user
70
68
  ticket.user = current_user
71
69
 
72
- unless ticket_params.dig(:started_at)
73
- #ticket.started_at = LC::Date2.new(Time.current).date.get
74
- end
75
-
76
- if ticket.save
77
- #Ticket.log_activity_create(current_user, ticket)
78
- #Ticket::Subscriber.add_subscriber(ticket, current_user, "discussion_created", "email")
79
- #Workflow::Action.execute_actions(current_user, ticket, {}, ticket.attributes)
80
- self.resource = ticket
81
- else
82
- pp ticket.errors.full_messages
83
- self.error(ticket.errors.full_messages.to_sentence)
70
+ Ticket.transaction do
71
+ ticket.save!
72
+ ticket.record_activity!(
73
+ actor: current_user,
74
+ code: :ticket_created,
75
+ description: "Ticket created",
76
+ metadata: {
77
+ from: nil,
78
+ to: ticket_snapshot(ticket)
79
+ }
80
+ )
84
81
  end
85
82
 
83
+ self.resource = ticket
84
+ self
85
+ rescue ActiveRecord::RecordInvalid => exception
86
+ self.resource = ticket
87
+ error(exception.record.errors.full_messages.to_sentence)
86
88
  self
87
89
  end
88
90
 
@@ -112,8 +114,18 @@ module LesliSupport
112
114
  end
113
115
 
114
116
  def update(params)
115
- self.resource.update(params)
116
- end
117
+ Ticket.transaction do
118
+ resource.update!(params)
119
+ record_update_activities
120
+ end
121
+
122
+ self
123
+ rescue ActiveRecord::RecordInvalid => exception
124
+ message = exception.record.errors.full_messages.to_sentence
125
+ resource.reload if resource.persisted?
126
+ error(message)
127
+ self
128
+ end
117
129
 
118
130
  def with_deadline()
119
131
  current_user.account.support.tickets
@@ -125,5 +137,62 @@ module LesliSupport
125
137
  #.where("cloud_help_tickets.users_id = ? or cloud_help_tickets.user_main_id = ? or chta.users_id = ?", current_user.id, current_user.id, current_user.id)
126
138
  .order(:deadline)
127
139
  end
140
+
141
+ private
142
+
143
+ def record_update_activities
144
+ record_relation_change(:owner, :owner_changed, "Ticket owner")
145
+ record_relation_change(:type, :type_changed, "Ticket type")
146
+ record_relation_change(:category, :category_changed, "Ticket category")
147
+ record_relation_change(:priority, :priority_changed, "Ticket priority")
148
+ end
149
+
150
+ def record_relation_change(association_name, code, label)
151
+ change = resource.saved_changes["#{association_name}_id"]
152
+ return unless change
153
+
154
+ model = resource.class.reflect_on_association(association_name).klass
155
+ metadata = {
156
+ from: relation_snapshot(model, change.first),
157
+ to: relation_snapshot(model, change.last)
158
+ }
159
+
160
+ resource.record_activity!(
161
+ actor: current_user,
162
+ code: code,
163
+ description: relation_change_description(label, metadata),
164
+ metadata: metadata
165
+ )
166
+ end
167
+
168
+ def relation_snapshot(model, id)
169
+ return if id.nil?
170
+
171
+ record = model.find_by(id: id)
172
+ {
173
+ id: id,
174
+ name: record&.name
175
+ }
176
+ end
177
+
178
+ def relation_change_description(label, metadata)
179
+ return "#{label} removed" unless metadata[:to]
180
+ return "#{label} set to #{snapshot_name(metadata[:to])}" unless metadata[:from]
181
+
182
+ "#{label} changed from #{snapshot_name(metadata[:from])} " \
183
+ "to #{snapshot_name(metadata[:to])}"
184
+ end
185
+
186
+ def snapshot_name(snapshot)
187
+ snapshot[:name].presence || "##{snapshot[:id]}"
188
+ end
189
+
190
+ def ticket_snapshot(ticket)
191
+ {
192
+ id: ticket.id,
193
+ uid: ticket.uid,
194
+ subject: ticket.subject
195
+ }
196
+ end
128
197
  end
129
198
  end
@@ -1,8 +1,8 @@
1
1
  <%
2
- group = Date2.new.date.db_column(:created_at)
2
+ group = Date2.new.date.db_column(:created_at, as: false)
3
3
  tickets = current_user.account.support.tickets
4
- .group(group.sub('as created_at_string',''))
5
- .order(created_at: :asc)
4
+ .group(Arel.sql(group))
5
+ .order(Arel.sql('MIN(created_at) ASC'))
6
6
  .limit(10)
7
7
  .count
8
8
  %>
@@ -25,7 +25,7 @@
25
25
 
26
26
  <%= form.field_control_select(:owner_id, current_user.account.users.pluck(:first_name, :id)) %>
27
27
 
28
- <%= form.field_control_textarea(:description, label:false) %>
28
+ <%= form.field_control_textarea_rich(:description, label: false) %>
29
29
 
30
30
  <hr class="my-6 border-0 border-t border-slate-200">
31
31
 
@@ -17,19 +17,21 @@
17
17
  <% end %>
18
18
 
19
19
  <% tabs.with_tab(id:"ticket-activities", title:"Activities", icon:"search_activity") do %>
20
- <%= render(LesliView::Items::Activities.new(@ticket, icons: {
21
- type_id: 'star',
22
- owner_id: 'favorite',
23
- priority_id: 'sunny',
24
- category_id: 'search'
25
- })) %>
20
+ <%= render LesliView::Items::Activities.new(
21
+ @ticket,
22
+ i18n_scope: "lesli_support.items.activities",
23
+ icons: {
24
+ ticket_created: "add_circle",
25
+ owner_changed: "manage_accounts",
26
+ type_changed: "label",
27
+ category_changed: "category",
28
+ priority_changed: "priority_high"
29
+ }
30
+ ) %>
26
31
  <% end %>
27
32
 
28
33
  <% tabs.with_tab(id:"ticket-attachments", title:"Attachments", icon:"attach_file") do %>
29
- <%#= render(LesliView::Items::Attachments.new(@ticket,
30
- path_to_create:ticket_actions_path(@ticket),
31
- path_to_update:->(action) {ticket_action_path(@ticket, action)}
32
- )) %>
34
+ <%= render LesliView::Items::Attachments.new(@ticket) %>
33
35
  <% end %>
34
36
  <% end %>
35
37
  <% end %>
@@ -1,2 +1,31 @@
1
1
  ---
2
- :en: {}
2
+ :en:
3
+ lesli_support:
4
+ items:
5
+ activities:
6
+ empty: No activities have been recorded yet.
7
+ unknown_actor: Unknown user
8
+ events:
9
+ ticket_created:
10
+ operation: Ticket created
11
+ set: Ticket %{to} was created.
12
+ owner_changed:
13
+ operation: Owner changed
14
+ set: Assigned to %{to}.
15
+ changed: Changed from %{from} to %{to}.
16
+ removed: Removed %{from} as owner.
17
+ type_changed:
18
+ operation: Type changed
19
+ set: Set to %{to}.
20
+ changed: Changed from %{from} to %{to}.
21
+ removed: Removed %{from}.
22
+ category_changed:
23
+ operation: Category changed
24
+ set: Set to %{to}.
25
+ changed: Changed from %{from} to %{to}.
26
+ removed: Removed %{from}.
27
+ priority_changed:
28
+ operation: Priority changed
29
+ set: Set to %{to}.
30
+ changed: Changed from %{from} to %{to}.
31
+ removed: Removed %{from}.
@@ -1,2 +1,31 @@
1
1
  ---
2
- :es: {}
2
+ :es:
3
+ lesli_support:
4
+ items:
5
+ activities:
6
+ empty: Todavía no se ha registrado actividad.
7
+ unknown_actor: Usuario desconocido
8
+ events:
9
+ ticket_created:
10
+ operation: Ticket creado
11
+ set: Se creó el ticket %{to}.
12
+ owner_changed:
13
+ operation: Responsable actualizado
14
+ set: Se asignó a %{to}.
15
+ changed: Se cambió de %{from} a %{to}.
16
+ removed: Se removió a %{from} como responsable.
17
+ type_changed:
18
+ operation: Tipo actualizado
19
+ set: Se estableció como %{to}.
20
+ changed: Se cambió de %{from} a %{to}.
21
+ removed: Se removió %{from}.
22
+ category_changed:
23
+ operation: Categoría actualizada
24
+ set: Se estableció como %{to}.
25
+ changed: Se cambió de %{from} a %{to}.
26
+ removed: Se removió %{from}.
27
+ priority_changed:
28
+ operation: Prioridad actualizada
29
+ set: Se estableció como %{to}.
30
+ changed: Se cambió de %{from} a %{to}.
31
+ removed: Se removió %{from}.
@@ -1,2 +1,31 @@
1
1
  ---
2
- :fr: {}
2
+ :fr:
3
+ lesli_support:
4
+ items:
5
+ activities:
6
+ empty: Aucune activité n'a encore été enregistrée.
7
+ unknown_actor: Utilisateur inconnu
8
+ events:
9
+ ticket_created:
10
+ operation: Ticket créé
11
+ set: Le ticket %{to} a été créé.
12
+ owner_changed:
13
+ operation: Responsable modifié
14
+ set: Assigné à %{to}.
15
+ changed: Modifié de %{from} à %{to}.
16
+ removed: "%{from} n'est plus responsable."
17
+ type_changed:
18
+ operation: Type modifié
19
+ set: Défini sur %{to}.
20
+ changed: Modifié de %{from} à %{to}.
21
+ removed: "%{from} a été supprimé."
22
+ category_changed:
23
+ operation: Catégorie modifiée
24
+ set: Définie sur %{to}.
25
+ changed: Modifiée de %{from} à %{to}.
26
+ removed: "%{from} a été supprimée."
27
+ priority_changed:
28
+ operation: Priorité modifiée
29
+ set: Définie sur %{to}.
30
+ changed: Modifiée de %{from} à %{to}.
31
+ removed: "%{from} a été supprimée."
@@ -1,2 +1,31 @@
1
1
  ---
2
- :it: {}
2
+ :it:
3
+ lesli_support:
4
+ items:
5
+ activities:
6
+ empty: Non è stata ancora registrata alcuna attività.
7
+ unknown_actor: Utente sconosciuto
8
+ events:
9
+ ticket_created:
10
+ operation: Ticket creato
11
+ set: Il ticket %{to} è stato creato.
12
+ owner_changed:
13
+ operation: Responsabile modificato
14
+ set: Assegnato a %{to}.
15
+ changed: Modificato da %{from} a %{to}.
16
+ removed: "%{from} non è più responsabile."
17
+ type_changed:
18
+ operation: Tipo modificato
19
+ set: Impostato su %{to}.
20
+ changed: Modificato da %{from} a %{to}.
21
+ removed: "%{from} è stato rimosso."
22
+ category_changed:
23
+ operation: Categoria modificata
24
+ set: Impostata su %{to}.
25
+ changed: Modificata da %{from} a %{to}.
26
+ removed: "%{from} è stata rimossa."
27
+ priority_changed:
28
+ operation: Priorità modificata
29
+ set: Impostata su %{to}.
30
+ changed: Modificata da %{from} a %{to}.
31
+ removed: "%{from} è stata rimossa."
@@ -1,2 +1,31 @@
1
1
  ---
2
- :pt: {}
2
+ :pt:
3
+ lesli_support:
4
+ items:
5
+ activities:
6
+ empty: Ainda não foi registrada nenhuma atividade.
7
+ unknown_actor: Usuário desconhecido
8
+ events:
9
+ ticket_created:
10
+ operation: Ticket criado
11
+ set: O ticket %{to} foi criado.
12
+ owner_changed:
13
+ operation: Responsável alterado
14
+ set: Atribuído a %{to}.
15
+ changed: Alterado de %{from} para %{to}.
16
+ removed: "%{from} não é mais responsável."
17
+ type_changed:
18
+ operation: Tipo alterado
19
+ set: Definido como %{to}.
20
+ changed: Alterado de %{from} para %{to}.
21
+ removed: "%{from} foi removido."
22
+ category_changed:
23
+ operation: Categoria alterada
24
+ set: Definida como %{to}.
25
+ changed: Alterada de %{from} para %{to}.
26
+ removed: "%{from} foi removida."
27
+ priority_changed:
28
+ operation: Prioridade alterada
29
+ set: Definida como %{to}.
30
+ changed: Alterada de %{from} para %{to}.
31
+ removed: "%{from} foi removida."
data/config/routes.rb CHANGED
@@ -36,6 +36,5 @@ LesliSupport::Engine.routes.draw do
36
36
 
37
37
  resources :tickets, only: [:show, :index, :new, :create, :edit, :update] do
38
38
  resources :actions, module: :ticket, only: [:create, :update]
39
- resources :discussions, module: :ticket, only: [:create]
40
39
  end
41
40
  end
@@ -0,0 +1,5 @@
1
+ class CreateLesliSupportItemAttachments < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table_lesli_item_attachments_10(:lesli_support)
4
+ end
5
+ end
@@ -35,10 +35,6 @@ module LesliSupport
35
35
  isolate_namespace LesliSupport
36
36
 
37
37
  initializer :lesli_support do |app|
38
-
39
- # register assets manifest
40
- config.assets.precompile += %w[lesli_support_manifest.js]
41
-
42
38
  # register engine migrations path
43
39
  unless app.root.to_s.match root.to_s
44
40
  config.paths["db/migrate"].expanded.each do |expanded_path|
@@ -1,4 +1,4 @@
1
1
  module LesliSupport
2
- VERSION = "1.2.2"
3
- BUILD = "1791607001"
2
+ VERSION = "1.2.3"
3
+ BUILD = "1792716699"
4
4
  end
data/readme.md CHANGED
@@ -8,8 +8,8 @@
8
8
  <br />
9
9
 
10
10
  <div align="center">
11
- <a target="_blank" href="https://github.com/LesliTech/LesliSupport/actions/workflows/lesli-ci-tests.yaml">
12
- <img alt="LesliSupport test status" src="https://img.shields.io/github/actions/workflow/status/LesliTech/LesliSupport/lesli-ci-tests.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
11
+ <a target="_blank" href="https://github.com/LesliTech/LesliSupport/actions/workflows/lesli-ci-engine.yaml">
12
+ <img alt="LesliSupport test status" src="https://img.shields.io/github/actions/workflow/status/LesliTech/LesliSupport/lesli-ci-engine.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
13
13
  </a>
14
14
  <a target="_blank" href="https://rubygems.org/gems/lesli_support">
15
15
  <img alt="Gem Version" src="https://img.shields.io/gem/v/lesli_support?style=for-the-badge&logo=ruby">
@@ -49,6 +49,7 @@ It provides account-scoped tools for receiving, organizing, discussing, and reso
49
49
  - Ticket assignment and status workflows
50
50
  - Internal and customer-facing discussions
51
51
  - Ticket activity history
52
+ - Private ticket attachments backed by Rails Active Storage
52
53
  - Service catalog and account-scoped organization
53
54
 
54
55
  <br />
@@ -76,6 +77,17 @@ bundle add lesli_support
76
77
  bin/rails lesli:db:prepare
77
78
  ```
78
79
 
80
+ Ticket attachments require the host application's shared Active Storage
81
+ tables. Install them once if they are not already present:
82
+
83
+ ```shell
84
+ bin/rails active_storage:install
85
+ bin/rails db:migrate
86
+ ```
87
+
88
+ AWS S3 and Cloudflare R2 require `aws-sdk-s3` in the host application. See the
89
+ [attachment setup guide](docs/tickets/attachments.md) for provider examples.
90
+
79
91
  ### Mount the engine
80
92
 
81
93
  Applications using Lesli's standard router mount LesliSupport automatically at `/support`:
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lesli_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Lesli Development Team
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-10-23 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: lesli
@@ -33,20 +34,18 @@ extensions: []
33
34
  extra_rdoc_files: []
34
35
  files:
35
36
  - Rakefile
36
- - app/assets/config/lesli_support_manifest.js
37
37
  - app/assets/images/lesli_support/support-logo.svg
38
38
  - app/assets/javascripts/lesli_support/application.js
39
39
  - app/assets/stylesheets/lesli_support/application.css
40
- - app/assets/stylesheets/lesli_support/application.tailwind.css
41
40
  - app/controllers/lesli_support/accounts_controller.rb
42
41
  - app/controllers/lesli_support/application_controller.rb
43
42
  - app/controllers/lesli_support/catalog/items_controller.rb
44
43
  - app/controllers/lesli_support/catalogs_controller.rb
45
44
  - app/controllers/lesli_support/dashboards_controller.rb
45
+ - app/controllers/lesli_support/items/attachments_controller.rb
46
46
  - app/controllers/lesli_support/items/discussions_controller.rb
47
47
  - app/controllers/lesli_support/items/tasks_controller.rb
48
48
  - app/controllers/lesli_support/ticket/activities_controller.rb
49
- - app/controllers/lesli_support/ticket/discussions_controller.rb
50
49
  - app/controllers/lesli_support/tickets_controller.rb
51
50
  - app/helpers/lesli_support/accounts_helper.rb
52
51
  - app/helpers/lesli_support/application_helper.rb
@@ -54,7 +53,6 @@ files:
54
53
  - app/helpers/lesli_support/catalogs_helper.rb
55
54
  - app/helpers/lesli_support/dashboards_helper.rb
56
55
  - app/helpers/lesli_support/ticket/activities_helper.rb
57
- - app/helpers/lesli_support/ticket/discussions_helper.rb
58
56
  - app/jobs/lesli_support/application_job.rb
59
57
  - app/mailers/lesli_support/application_mailer.rb
60
58
  - app/models/lesli_support/account.rb
@@ -63,11 +61,11 @@ files:
63
61
  - app/models/lesli_support/catalog/item.rb
64
62
  - app/models/lesli_support/dashboard.rb
65
63
  - app/models/lesli_support/items/activity.rb
64
+ - app/models/lesli_support/items/attachment.rb
66
65
  - app/models/lesli_support/items/discussion.rb
67
66
  - app/models/lesli_support/items/task.rb
68
67
  - app/models/lesli_support/ticket.rb
69
68
  - app/models/lesli_support/ticket/activity.rb
70
- - app/models/lesli_support/ticket/discussion.rb
71
69
  - app/services/lesli_support/catalog_service.rb
72
70
  - app/services/lesli_support/ticket_service.rb
73
71
  - app/views/lesli_support/accounts/_account.html.erb
@@ -105,6 +103,7 @@ files:
105
103
  - config/locales/translations.pt.yml
106
104
  - config/routes.rb
107
105
  - db/migrate/v1/0702000110_create_lesli_support_accounts.rb
106
+ - db/migrate/v1/0702000210_create_lesli_support_item_attachments.rb
108
107
  - db/migrate/v1/0702002010_create_lesli_support_catalogs.rb
109
108
  - db/migrate/v1/0702100110_create_lesli_support_slas.rb
110
109
  - db/migrate/v1/0702110110_create_lesli_support_tickets.rb
@@ -151,6 +150,7 @@ metadata:
151
150
  homepage_uri: https://www.lesli.dev/
152
151
  changelog_uri: https://github.com/LesliTech/LesliSupport
153
152
  source_code_uri: https://github.com/LesliTech/LesliSupport
153
+ post_install_message:
154
154
  rdoc_options: []
155
155
  require_paths:
156
156
  - lib
@@ -165,7 +165,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  requirements: []
168
- rubygems_version: 3.7.1
168
+ rubygems_version: 3.5.16
169
+ signing_key:
169
170
  specification_version: 4
170
171
  summary: Support ticket management for the Lesli Framework.
171
172
  test_files: []
@@ -1,38 +0,0 @@
1
- /*
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 platform.
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
- */
32
-
33
- //= link_tree ../images/lesli_support .png
34
- //= link_tree ../images/lesli_support .jpg
35
- //= link_tree ../images/lesli_support .svg
36
-
37
- //= link lesli_support/application.css
38
- //= link lesli_support/application.js
@@ -1,4 +0,0 @@
1
- module LesliSupport
2
- class Ticket::DiscussionsController < Lesli::Items::DiscussionsController
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module LesliSupport
2
- module Ticket::DiscussionsHelper
3
- end
4
- end
@@ -1,6 +0,0 @@
1
- module LesliSupport
2
- class Ticket::Discussion < Lesli::Items::Discussion
3
- belongs_to :item, class_name: "LesliSupport::Ticket", foreign_key: "ticket_id"
4
- belongs_to :user, class_name: "Lesli::User"
5
- end
6
- end