@escalated-dev/escalated 0.5.0 → 0.7.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.
- package/README.md +102 -0
- package/package.json +37 -6
- package/src/components/ActivityTimeline.stories.js +55 -0
- package/src/components/ActivityTimeline.vue +83 -66
- package/src/components/AdminDashboard.stories.js +1095 -0
- package/src/components/AgentLoadIndicator.stories.js +37 -0
- package/src/components/AgentLoadIndicator.vue +49 -0
- package/src/components/AgentPerformanceCard.vue +44 -0
- package/src/components/ArticleEditor.vue +82 -0
- package/src/components/AssigneeSelect.vue +37 -23
- package/src/components/AttachmentList.vue +53 -37
- package/src/components/AuditLogEntry.vue +95 -0
- package/src/components/BulkActionBar.vue +99 -30
- package/src/components/CategoryTree.vue +89 -0
- package/src/components/ChartWidget.vue +46 -0
- package/src/components/CollisionWarning.stories.js +30 -0
- package/src/components/CollisionWarning.vue +68 -0
- package/src/components/ConditionalFieldRules.vue +135 -0
- package/src/components/ContextPanel.vue +66 -0
- package/src/components/ContextPanelSection.vue +65 -0
- package/src/components/CustomFieldRenderer.vue +159 -0
- package/src/components/EscalatedLayout.vue +400 -69
- package/src/components/FileDropzone.vue +57 -41
- package/src/components/FollowButton.stories.js +30 -0
- package/src/components/FollowButton.vue +53 -28
- package/src/components/KeyboardShortcutHelp.vue +129 -39
- package/src/components/KnowledgePanel.vue +122 -0
- package/src/components/KpiCard.stories.js +32 -0
- package/src/components/KpiCard.vue +88 -0
- package/src/components/MacroDropdown.vue +95 -35
- package/src/components/PermissionMatrix.vue +107 -0
- package/src/components/PinnedNotes.vue +75 -33
- package/src/components/PresenceIndicator.vue +93 -27
- package/src/components/PriorityBadge.stories.js +33 -0
- package/src/components/PriorityBadge.vue +46 -39
- package/src/components/QuickFilters.vue +65 -49
- package/src/components/ReplyComposer.vue +273 -159
- package/src/components/ReplyThread.vue +78 -23
- package/src/components/SatisfactionRating.vue +98 -46
- package/src/components/ScheduleEditor.vue +104 -0
- package/src/components/SideConversation.vue +165 -0
- package/src/components/SideConversationList.vue +147 -0
- package/src/components/SkillTagManager.vue +79 -0
- package/src/components/SlaComplianceChart.vue +53 -0
- package/src/components/SlaTimer.stories.js +35 -0
- package/src/components/SlaTimer.vue +62 -49
- package/src/components/StatsCard.stories.js +24 -0
- package/src/components/StatsCard.vue +58 -46
- package/src/components/StatusBadge.stories.js +53 -0
- package/src/components/StatusBadge.vue +78 -46
- package/src/components/TagSelect.vue +84 -53
- package/src/components/TicketFilters.vue +225 -69
- package/src/components/TicketLinkPanel.vue +193 -0
- package/src/components/TicketList.vue +594 -193
- package/src/components/TicketMergeDialog.vue +157 -0
- package/src/components/TicketSidebar.vue +167 -99
- package/src/components/TicketTypeSelector.vue +21 -0
- package/src/components/TotpInput.stories.js +9 -0
- package/src/components/TotpInput.vue +81 -0
- package/src/components/TwoFactorSetup.vue +113 -0
- package/src/composables/useDebouncedSearch.js +38 -0
- package/src/composables/useI18n.js +80 -0
- package/src/composables/usePluginExtensions.js +95 -3
- package/src/composables/usePluginHooks.js +65 -0
- package/src/defineEscalatedPlugin.js +34 -8
- package/src/index.js +72 -35
- package/src/locales/de.json +442 -0
- package/src/locales/en.json +467 -0
- package/src/locales/es.json +442 -0
- package/src/locales/fr.json +442 -0
- package/src/locales/index.js +6 -0
- package/src/pages/Admin/ApiTokens/Index.vue +231 -67
- package/src/pages/Admin/AuditLog/Index.vue +154 -0
- package/src/pages/Admin/Automations/Form.vue +184 -0
- package/src/pages/Admin/Automations/Index.vue +129 -0
- package/src/pages/Admin/BusinessHours/Form.vue +172 -0
- package/src/pages/Admin/BusinessHours/Index.vue +113 -0
- package/src/pages/Admin/CannedResponses/Index.vue +127 -70
- package/src/pages/Admin/Capacity/Index.vue +134 -0
- package/src/pages/Admin/CustomFields/Form.vue +195 -0
- package/src/pages/Admin/CustomFields/Index.vue +134 -0
- package/src/pages/Admin/CustomObjects/Form.vue +202 -0
- package/src/pages/Admin/CustomObjects/Index.vue +127 -0
- package/src/pages/Admin/CustomObjects/Records.vue +228 -0
- package/src/pages/Admin/Departments/Form.vue +75 -51
- package/src/pages/Admin/Departments/Index.vue +109 -57
- package/src/pages/Admin/EscalationRules/Form.vue +157 -96
- package/src/pages/Admin/EscalationRules/Index.vue +178 -57
- package/src/pages/Admin/Import/Connect.vue +96 -0
- package/src/pages/Admin/Import/Index.vue +102 -0
- package/src/pages/Admin/Import/Mapping.vue +110 -0
- package/src/pages/Admin/Import/Progress.vue +153 -0
- package/src/pages/Admin/Import/Review.vue +76 -0
- package/src/pages/Admin/KnowledgeBase/Articles/Form.vue +142 -0
- package/src/pages/Admin/KnowledgeBase/Articles/Index.vue +195 -0
- package/src/pages/Admin/KnowledgeBase/Categories/Index.vue +193 -0
- package/src/pages/Admin/Macros/Index.vue +250 -89
- package/src/pages/Admin/Plugins/Index.vue +205 -75
- package/src/pages/Admin/Reports/AgentMetrics.vue +115 -0
- package/src/pages/Admin/Reports/CsatReport.vue +127 -0
- package/src/pages/Admin/Reports/Dashboard.vue +211 -0
- package/src/pages/Admin/Reports/SlaReport.vue +166 -0
- package/src/pages/Admin/Reports.vue +139 -34
- package/src/pages/Admin/Roles/Form.vue +71 -0
- package/src/pages/Admin/Roles/Index.vue +122 -0
- package/src/pages/Admin/Settings/CsatSettings.vue +165 -0
- package/src/pages/Admin/Settings/DataRetention.vue +182 -0
- package/src/pages/Admin/Settings/EmailSettings.vue +243 -0
- package/src/pages/Admin/Settings/Sandbox.vue +135 -0
- package/src/pages/Admin/Settings/SsoSettings.vue +218 -0
- package/src/pages/Admin/Settings/TwoFactor.vue +110 -0
- package/src/pages/Admin/Settings.vue +468 -260
- package/src/pages/Admin/Skills/Form.vue +53 -0
- package/src/pages/Admin/Skills/Index.vue +94 -0
- package/src/pages/Admin/SlaPolicies/Form.vue +118 -75
- package/src/pages/Admin/SlaPolicies/Index.vue +120 -59
- package/src/pages/Admin/Statuses/Form.vue +114 -0
- package/src/pages/Admin/Statuses/Index.vue +153 -0
- package/src/pages/Admin/Tags/Index.vue +191 -105
- package/src/pages/Admin/Tickets/Index.vue +91 -39
- package/src/pages/Admin/Tickets/Show.vue +101 -37
- package/src/pages/Admin/Webhooks/DeliveryLog.vue +120 -0
- package/src/pages/Admin/Webhooks/Form.vue +110 -0
- package/src/pages/Admin/Webhooks/Index.vue +136 -0
- package/src/pages/Agent/Dashboard.vue +311 -186
- package/src/pages/Agent/TicketIndex.vue +88 -38
- package/src/pages/Agent/TicketShow.vue +258 -51
- package/src/pages/Customer/Create.vue +36 -9
- package/src/pages/Customer/Index.vue +31 -24
- package/src/pages/Customer/KnowledgeBase/Article.vue +127 -0
- package/src/pages/Customer/KnowledgeBase/Index.vue +151 -0
- package/src/plugin.js +86 -1
- package/src/utils/constants.js +30 -0
- package/src/utils/formatting.js +35 -0
- package/src/utils/sanitizeHtml.js +64 -0
- package/src/pages/Admin/Plugins.vue +0 -129
|
@@ -1,260 +1,468 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import EscalatedLayout from '../../components/EscalatedLayout.vue';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
<
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
</
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
<
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
</
|
|
1
|
+
<script setup>
|
|
2
|
+
import EscalatedLayout from '../../components/EscalatedLayout.vue';
|
|
3
|
+
import PluginSlot from '../../components/PluginSlot.vue';
|
|
4
|
+
import { useForm, usePage } from '@inertiajs/vue3';
|
|
5
|
+
import { computed } from 'vue';
|
|
6
|
+
import { usePluginExtensions } from '../../composables/usePluginExtensions';
|
|
7
|
+
|
|
8
|
+
const props = defineProps({ settings: Object });
|
|
9
|
+
const page = usePage();
|
|
10
|
+
|
|
11
|
+
const form = useForm({
|
|
12
|
+
guest_tickets_enabled: props.settings.guest_tickets_enabled,
|
|
13
|
+
allow_customer_close: props.settings.allow_customer_close,
|
|
14
|
+
auto_close_resolved_after_days: props.settings.auto_close_resolved_after_days,
|
|
15
|
+
max_attachments_per_reply: props.settings.max_attachments_per_reply,
|
|
16
|
+
max_attachment_size_kb: props.settings.max_attachment_size_kb,
|
|
17
|
+
ticket_reference_prefix: props.settings.ticket_reference_prefix,
|
|
18
|
+
inbound_email_enabled: props.settings.inbound_email_enabled ?? false,
|
|
19
|
+
inbound_email_adapter: props.settings.inbound_email_adapter ?? 'mailgun',
|
|
20
|
+
inbound_email_address: props.settings.inbound_email_address ?? '',
|
|
21
|
+
mailgun_signing_key: props.settings.mailgun_signing_key ?? '',
|
|
22
|
+
postmark_inbound_token: props.settings.postmark_inbound_token ?? '',
|
|
23
|
+
ses_region: props.settings.ses_region ?? '',
|
|
24
|
+
ses_topic_arn: props.settings.ses_topic_arn ?? '',
|
|
25
|
+
imap_host: props.settings.imap_host ?? '',
|
|
26
|
+
imap_port: props.settings.imap_port ?? 993,
|
|
27
|
+
imap_encryption: props.settings.imap_encryption ?? 'ssl',
|
|
28
|
+
imap_username: props.settings.imap_username ?? '',
|
|
29
|
+
imap_password: props.settings.imap_password ?? '',
|
|
30
|
+
imap_mailbox: props.settings.imap_mailbox ?? 'INBOX',
|
|
31
|
+
show_powered_by: props.settings.show_powered_by ?? true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const webhookBaseUrl = computed(() => {
|
|
35
|
+
const prefix = page.props.escalated?.prefix || 'support';
|
|
36
|
+
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
|
37
|
+
return `${origin}/${prefix}/inbound`;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const { getPageComponents } = usePluginExtensions();
|
|
41
|
+
|
|
42
|
+
function submit() {
|
|
43
|
+
form.post(route('escalated.admin.settings.update'));
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<template>
|
|
48
|
+
<EscalatedLayout title="Settings">
|
|
49
|
+
<form class="mx-auto max-w-2xl space-y-6" @submit.prevent="submit">
|
|
50
|
+
<!-- General -->
|
|
51
|
+
<div class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6">
|
|
52
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">General</h3>
|
|
53
|
+
<div class="space-y-5">
|
|
54
|
+
<label class="flex items-center justify-between">
|
|
55
|
+
<div>
|
|
56
|
+
<span class="text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
57
|
+
>Guest Tickets</span
|
|
58
|
+
>
|
|
59
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
60
|
+
Allow visitors to submit tickets without signing in
|
|
61
|
+
</p>
|
|
62
|
+
</div>
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
:class="[
|
|
66
|
+
'relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors',
|
|
67
|
+
form.guest_tickets_enabled ? 'bg-emerald-500' : 'bg-neutral-700',
|
|
68
|
+
]"
|
|
69
|
+
@click="form.guest_tickets_enabled = !form.guest_tickets_enabled"
|
|
70
|
+
>
|
|
71
|
+
<span
|
|
72
|
+
:class="[
|
|
73
|
+
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition-transform',
|
|
74
|
+
form.guest_tickets_enabled ? 'translate-x-5' : 'translate-x-0',
|
|
75
|
+
]"
|
|
76
|
+
/>
|
|
77
|
+
</button>
|
|
78
|
+
</label>
|
|
79
|
+
|
|
80
|
+
<label class="flex items-center justify-between">
|
|
81
|
+
<div>
|
|
82
|
+
<span class="text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
83
|
+
>Allow Customer Close</span
|
|
84
|
+
>
|
|
85
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
86
|
+
Let customers close their own tickets
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
:class="[
|
|
92
|
+
'relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors',
|
|
93
|
+
form.allow_customer_close ? 'bg-emerald-500' : 'bg-neutral-700',
|
|
94
|
+
]"
|
|
95
|
+
@click="form.allow_customer_close = !form.allow_customer_close"
|
|
96
|
+
>
|
|
97
|
+
<span
|
|
98
|
+
:class="[
|
|
99
|
+
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition-transform',
|
|
100
|
+
form.allow_customer_close ? 'translate-x-5' : 'translate-x-0',
|
|
101
|
+
]"
|
|
102
|
+
/>
|
|
103
|
+
</button>
|
|
104
|
+
</label>
|
|
105
|
+
|
|
106
|
+
<div>
|
|
107
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
108
|
+
>Auto-close resolved tickets after</label
|
|
109
|
+
>
|
|
110
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
111
|
+
Days after resolution before auto-closing (0 to disable)
|
|
112
|
+
</p>
|
|
113
|
+
<div class="mt-2 flex items-center gap-2">
|
|
114
|
+
<input
|
|
115
|
+
v-model.number="form.auto_close_resolved_after_days"
|
|
116
|
+
type="number"
|
|
117
|
+
min="0"
|
|
118
|
+
max="365"
|
|
119
|
+
class="w-24 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
120
|
+
/>
|
|
121
|
+
<span class="text-sm text-[var(--esc-panel-text-muted)]">days</span>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<!-- Limits -->
|
|
128
|
+
<div class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6">
|
|
129
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Limits</h3>
|
|
130
|
+
<div class="space-y-5">
|
|
131
|
+
<div>
|
|
132
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
133
|
+
>Max attachments per reply</label
|
|
134
|
+
>
|
|
135
|
+
<input
|
|
136
|
+
v-model.number="form.max_attachments_per_reply"
|
|
137
|
+
type="number"
|
|
138
|
+
min="1"
|
|
139
|
+
max="20"
|
|
140
|
+
class="mt-2 w-24 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
141
|
+
/>
|
|
142
|
+
</div>
|
|
143
|
+
<div>
|
|
144
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
145
|
+
>Max attachment size</label
|
|
146
|
+
>
|
|
147
|
+
<div class="mt-2 flex items-center gap-2">
|
|
148
|
+
<input
|
|
149
|
+
v-model.number="form.max_attachment_size_kb"
|
|
150
|
+
type="number"
|
|
151
|
+
min="512"
|
|
152
|
+
max="102400"
|
|
153
|
+
step="512"
|
|
154
|
+
class="w-32 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
155
|
+
/>
|
|
156
|
+
<span class="text-sm text-[var(--esc-panel-text-muted)]"
|
|
157
|
+
>KB ({{ Math.round(form.max_attachment_size_kb / 1024) }} MB)</span
|
|
158
|
+
>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<!-- Tickets -->
|
|
165
|
+
<div class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6">
|
|
166
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Tickets</h3>
|
|
167
|
+
<div class="space-y-5">
|
|
168
|
+
<div>
|
|
169
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
170
|
+
>Reference Prefix</label
|
|
171
|
+
>
|
|
172
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
173
|
+
Prefix for ticket references (e.g. ESC produces ESC-00001)
|
|
174
|
+
</p>
|
|
175
|
+
<input
|
|
176
|
+
v-model="form.ticket_reference_prefix"
|
|
177
|
+
type="text"
|
|
178
|
+
maxlength="10"
|
|
179
|
+
class="mt-2 w-32 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] uppercase focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<!-- Inbound Email -->
|
|
186
|
+
<div class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6">
|
|
187
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Inbound Email</h3>
|
|
188
|
+
<div class="space-y-5">
|
|
189
|
+
<label class="flex items-center justify-between">
|
|
190
|
+
<div>
|
|
191
|
+
<span class="text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
192
|
+
>Inbound Email</span
|
|
193
|
+
>
|
|
194
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
195
|
+
Allow creating and replying to tickets via email
|
|
196
|
+
</p>
|
|
197
|
+
</div>
|
|
198
|
+
<button
|
|
199
|
+
type="button"
|
|
200
|
+
:class="[
|
|
201
|
+
'relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors',
|
|
202
|
+
form.inbound_email_enabled ? 'bg-emerald-500' : 'bg-neutral-700',
|
|
203
|
+
]"
|
|
204
|
+
@click="form.inbound_email_enabled = !form.inbound_email_enabled"
|
|
205
|
+
>
|
|
206
|
+
<span
|
|
207
|
+
:class="[
|
|
208
|
+
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition-transform',
|
|
209
|
+
form.inbound_email_enabled ? 'translate-x-5' : 'translate-x-0',
|
|
210
|
+
]"
|
|
211
|
+
/>
|
|
212
|
+
</button>
|
|
213
|
+
</label>
|
|
214
|
+
|
|
215
|
+
<template v-if="form.inbound_email_enabled">
|
|
216
|
+
<div>
|
|
217
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
218
|
+
>Email Provider</label
|
|
219
|
+
>
|
|
220
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
221
|
+
How inbound emails are received
|
|
222
|
+
</p>
|
|
223
|
+
<select
|
|
224
|
+
v-model="form.inbound_email_adapter"
|
|
225
|
+
class="mt-2 w-48 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
226
|
+
>
|
|
227
|
+
<option value="mailgun">Mailgun</option>
|
|
228
|
+
<option value="postmark">Postmark</option>
|
|
229
|
+
<option value="ses">AWS SES</option>
|
|
230
|
+
<option value="imap">IMAP</option>
|
|
231
|
+
</select>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<div>
|
|
235
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
236
|
+
>Support Email Address</label
|
|
237
|
+
>
|
|
238
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
239
|
+
The email address customers will send emails to (e.g. support@example.com)
|
|
240
|
+
</p>
|
|
241
|
+
<input
|
|
242
|
+
v-model="form.inbound_email_address"
|
|
243
|
+
type="email"
|
|
244
|
+
placeholder="support@example.com"
|
|
245
|
+
class="mt-2 w-full max-w-sm rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
246
|
+
/>
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
<!-- Mailgun -->
|
|
250
|
+
<template v-if="form.inbound_email_adapter === 'mailgun'">
|
|
251
|
+
<div>
|
|
252
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
253
|
+
>Signing Key</label
|
|
254
|
+
>
|
|
255
|
+
<input
|
|
256
|
+
v-model="form.mailgun_signing_key"
|
|
257
|
+
type="password"
|
|
258
|
+
class="mt-2 w-full max-w-sm rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
259
|
+
/>
|
|
260
|
+
</div>
|
|
261
|
+
<div>
|
|
262
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
263
|
+
>Webhook URL</label
|
|
264
|
+
>
|
|
265
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
266
|
+
Configure this URL in your Mailgun dashboard
|
|
267
|
+
</p>
|
|
268
|
+
<input
|
|
269
|
+
:value="`${webhookBaseUrl}/mailgun`"
|
|
270
|
+
type="text"
|
|
271
|
+
readonly
|
|
272
|
+
class="mt-2 w-full max-w-lg rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-tertiary)] select-all cursor-default focus:outline-none"
|
|
273
|
+
/>
|
|
274
|
+
</div>
|
|
275
|
+
</template>
|
|
276
|
+
|
|
277
|
+
<!-- Postmark -->
|
|
278
|
+
<template v-if="form.inbound_email_adapter === 'postmark'">
|
|
279
|
+
<div>
|
|
280
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
281
|
+
>Inbound Token</label
|
|
282
|
+
>
|
|
283
|
+
<input
|
|
284
|
+
v-model="form.postmark_inbound_token"
|
|
285
|
+
type="password"
|
|
286
|
+
class="mt-2 w-full max-w-sm rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
287
|
+
/>
|
|
288
|
+
</div>
|
|
289
|
+
<div>
|
|
290
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
291
|
+
>Webhook URL</label
|
|
292
|
+
>
|
|
293
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
294
|
+
Configure this URL in your Postmark server settings
|
|
295
|
+
</p>
|
|
296
|
+
<input
|
|
297
|
+
:value="`${webhookBaseUrl}/postmark`"
|
|
298
|
+
type="text"
|
|
299
|
+
readonly
|
|
300
|
+
class="mt-2 w-full max-w-lg rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-tertiary)] select-all cursor-default focus:outline-none"
|
|
301
|
+
/>
|
|
302
|
+
</div>
|
|
303
|
+
</template>
|
|
304
|
+
|
|
305
|
+
<!-- AWS SES -->
|
|
306
|
+
<template v-if="form.inbound_email_adapter === 'ses'">
|
|
307
|
+
<div>
|
|
308
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
309
|
+
>Region</label
|
|
310
|
+
>
|
|
311
|
+
<input
|
|
312
|
+
v-model="form.ses_region"
|
|
313
|
+
type="text"
|
|
314
|
+
placeholder="us-east-1"
|
|
315
|
+
class="mt-2 w-48 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
316
|
+
/>
|
|
317
|
+
</div>
|
|
318
|
+
<div>
|
|
319
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
320
|
+
>Topic ARN</label
|
|
321
|
+
>
|
|
322
|
+
<input
|
|
323
|
+
v-model="form.ses_topic_arn"
|
|
324
|
+
type="text"
|
|
325
|
+
placeholder="arn:aws:sns:us-east-1:123456789:ses-inbound"
|
|
326
|
+
class="mt-2 w-full max-w-lg rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
327
|
+
/>
|
|
328
|
+
</div>
|
|
329
|
+
<div>
|
|
330
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
331
|
+
>Webhook URL</label
|
|
332
|
+
>
|
|
333
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
334
|
+
Configure this URL as your SNS subscription endpoint
|
|
335
|
+
</p>
|
|
336
|
+
<input
|
|
337
|
+
:value="`${webhookBaseUrl}/ses`"
|
|
338
|
+
type="text"
|
|
339
|
+
readonly
|
|
340
|
+
class="mt-2 w-full max-w-lg rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-tertiary)] select-all cursor-default focus:outline-none"
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
</template>
|
|
344
|
+
|
|
345
|
+
<!-- IMAP -->
|
|
346
|
+
<template v-if="form.inbound_email_adapter === 'imap'">
|
|
347
|
+
<div>
|
|
348
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
349
|
+
>Host</label
|
|
350
|
+
>
|
|
351
|
+
<input
|
|
352
|
+
v-model="form.imap_host"
|
|
353
|
+
type="text"
|
|
354
|
+
placeholder="imap.example.com"
|
|
355
|
+
class="mt-2 w-full max-w-sm rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
356
|
+
/>
|
|
357
|
+
</div>
|
|
358
|
+
<div class="flex items-end gap-4">
|
|
359
|
+
<div>
|
|
360
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
361
|
+
>Port</label
|
|
362
|
+
>
|
|
363
|
+
<input
|
|
364
|
+
v-model.number="form.imap_port"
|
|
365
|
+
type="number"
|
|
366
|
+
min="1"
|
|
367
|
+
max="65535"
|
|
368
|
+
class="mt-2 w-24 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
369
|
+
/>
|
|
370
|
+
</div>
|
|
371
|
+
<div>
|
|
372
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
373
|
+
>Encryption</label
|
|
374
|
+
>
|
|
375
|
+
<select
|
|
376
|
+
v-model="form.imap_encryption"
|
|
377
|
+
class="mt-2 w-28 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
378
|
+
>
|
|
379
|
+
<option value="ssl">SSL</option>
|
|
380
|
+
<option value="tls">TLS</option>
|
|
381
|
+
<option value="none">None</option>
|
|
382
|
+
</select>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
<div>
|
|
386
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
387
|
+
>Username</label
|
|
388
|
+
>
|
|
389
|
+
<input
|
|
390
|
+
v-model="form.imap_username"
|
|
391
|
+
type="text"
|
|
392
|
+
class="mt-2 w-full max-w-sm rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
393
|
+
/>
|
|
394
|
+
</div>
|
|
395
|
+
<div>
|
|
396
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
397
|
+
>Password</label
|
|
398
|
+
>
|
|
399
|
+
<input
|
|
400
|
+
v-model="form.imap_password"
|
|
401
|
+
type="password"
|
|
402
|
+
class="mt-2 w-full max-w-sm rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
403
|
+
/>
|
|
404
|
+
</div>
|
|
405
|
+
<div>
|
|
406
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
407
|
+
>Mailbox</label
|
|
408
|
+
>
|
|
409
|
+
<input
|
|
410
|
+
v-model="form.imap_mailbox"
|
|
411
|
+
type="text"
|
|
412
|
+
placeholder="INBOX"
|
|
413
|
+
class="mt-2 w-48 rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 text-sm text-[var(--esc-panel-text-secondary)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
414
|
+
/>
|
|
415
|
+
</div>
|
|
416
|
+
</template>
|
|
417
|
+
</template>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
|
|
421
|
+
<!-- Branding -->
|
|
422
|
+
<div class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6">
|
|
423
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Branding</h3>
|
|
424
|
+
<div class="space-y-5">
|
|
425
|
+
<label class="flex items-center justify-between">
|
|
426
|
+
<div>
|
|
427
|
+
<span class="text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
428
|
+
>Show "Powered by Escalated"</span
|
|
429
|
+
>
|
|
430
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
431
|
+
Display attribution badge in the support portal footer
|
|
432
|
+
</p>
|
|
433
|
+
</div>
|
|
434
|
+
<button
|
|
435
|
+
type="button"
|
|
436
|
+
:class="[
|
|
437
|
+
'relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors',
|
|
438
|
+
form.show_powered_by ? 'bg-emerald-500' : 'bg-neutral-700',
|
|
439
|
+
]"
|
|
440
|
+
@click="form.show_powered_by = !form.show_powered_by"
|
|
441
|
+
>
|
|
442
|
+
<span
|
|
443
|
+
:class="[
|
|
444
|
+
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition-transform',
|
|
445
|
+
form.show_powered_by ? 'translate-x-5' : 'translate-x-0',
|
|
446
|
+
]"
|
|
447
|
+
/>
|
|
448
|
+
</button>
|
|
449
|
+
</label>
|
|
450
|
+
</div>
|
|
451
|
+
</div>
|
|
452
|
+
|
|
453
|
+
<PluginSlot slot="admin.settings.extra" :components="getPageComponents('admin.settings', 'extra')" />
|
|
454
|
+
|
|
455
|
+
<!-- Submit -->
|
|
456
|
+
<div class="flex items-center justify-end gap-3">
|
|
457
|
+
<span v-if="form.recentlySuccessful" class="text-sm text-emerald-400">Saved.</span>
|
|
458
|
+
<button
|
|
459
|
+
type="submit"
|
|
460
|
+
:disabled="form.processing"
|
|
461
|
+
class="rounded-lg bg-gradient-to-r from-[var(--esc-panel-accent)] to-[var(--esc-panel-accent-secondary)] px-5 py-2 text-sm font-medium text-white shadow-lg shadow-[var(--esc-panel-bg)]/20 transition-all hover:from-[var(--esc-panel-accent-hover)] hover:to-[var(--esc-panel-accent-secondary-hover)] disabled:opacity-50"
|
|
462
|
+
>
|
|
463
|
+
{{ form.processing ? 'Saving...' : 'Save Settings' }}
|
|
464
|
+
</button>
|
|
465
|
+
</div>
|
|
466
|
+
</form>
|
|
467
|
+
</EscalatedLayout>
|
|
468
|
+
</template>
|