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.
- checksums.yaml +4 -4
- data/Rakefile +3 -0
- data/app/assets/stylesheets/lesli_support/application.css +180 -8
- data/app/controllers/lesli_support/items/attachments_controller.rb +11 -0
- data/app/controllers/lesli_support/items/discussions_controller.rb +5 -0
- data/app/controllers/lesli_support/items/tasks_controller.rb +5 -0
- data/app/controllers/lesli_support/tickets_controller.rb +4 -9
- data/app/models/lesli_support/account.rb +4 -1
- data/app/models/lesli_support/catalog.rb +1 -1
- data/app/models/lesli_support/items/activity.rb +3 -0
- data/app/models/lesli_support/items/attachment.rb +9 -0
- data/app/models/lesli_support/items/discussion.rb +3 -0
- data/app/models/lesli_support/items/task.rb +3 -0
- data/app/models/lesli_support/ticket.rb +12 -39
- data/app/services/lesli_support/catalog_service.rb +5 -5
- data/app/services/lesli_support/ticket_service.rb +85 -16
- data/app/views/lesli_support/dashboards/_component-tickets-created.html.erb +3 -3
- data/app/views/lesli_support/tickets/_form.html.erb +1 -1
- data/app/views/lesli_support/tickets/show.html.erb +12 -10
- data/config/locales/translations.en.yml +30 -1
- data/config/locales/translations.es.yml +30 -1
- data/config/locales/translations.fr.yml +30 -1
- data/config/locales/translations.it.yml +30 -1
- data/config/locales/translations.pt.yml +30 -1
- data/config/routes.rb +0 -1
- data/db/migrate/v1/0702000210_create_lesli_support_item_attachments.rb +5 -0
- data/lib/lesli_support/engine.rb +0 -4
- data/lib/lesli_support/version.rb +2 -2
- data/readme.md +14 -2
- metadata +9 -8
- data/app/assets/config/lesli_support_manifest.js +0 -38
- data/app/assets/stylesheets/lesli_support/application.tailwind.css +0 -0
- data/app/controllers/lesli_support/ticket/discussions_controller.rb +0 -4
- data/app/helpers/lesli_support/ticket/discussions_helper.rb +0 -4
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fb316caaf1ac5c3b40150e368dab2210063a280a8cac3185ed200bdd3e473fae
|
|
4
|
+
data.tar.gz: 5bd283f9f7fdf549079f28aa3a80ae5e5026ce7529b8604e6287ece702067767
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 48e6e231469bd7243e48f1910c8d9d4e71f39d6dccde00e5b7c1f1e410d8ef32f2d9de149be46e8434756f4373e93e217ce4230cc354a17d76dd895f75d8fc1b
|
|
7
|
+
data.tar.gz: 559d4befde444da76cc4826b6c8eaaf4003c833725943f60589c4306a7bb6c2a3552c04a33f3689acfe456ab67b75263bc253873b7acf0ef41f79cd7356ca3cc
|
data/Rakefile
CHANGED
|
@@ -1,9 +1,181 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
}
|
|
@@ -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.
|
|
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.
|
|
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
|
|
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,
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
83
|
-
#ticket.source = Catalog::TicketSource.cloud_help_source(current_user.account.
|
|
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.
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
116
|
-
|
|
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(
|
|
5
|
-
.order(created_at
|
|
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.
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
data/lib/lesli_support/engine.rb
CHANGED
|
@@ -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|
|
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-
|
|
12
|
-
<img alt="LesliSupport test status" src="https://img.shields.io/github/actions/workflow/status/LesliTech/LesliSupport/lesli-ci-
|
|
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.
|
|
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:
|
|
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.
|
|
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
|
|
File without changes
|