@escalated-dev/escalated 0.7.0 → 0.8.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/LICENSE +21 -21
- package/README.md +36 -1
- package/package.json +16 -7
- package/src/components/ActiveChatsPanel.vue +246 -0
- package/src/components/ActivityTimeline.stories.js +55 -55
- package/src/components/ActivityTimeline.vue +83 -83
- package/src/components/AdminDashboard.stories.js +1423 -1095
- package/src/components/AgentLoadIndicator.stories.js +37 -37
- package/src/components/AgentLoadIndicator.vue +49 -49
- package/src/components/AgentPerformanceCard.vue +44 -44
- package/src/components/ArticleEditor.vue +82 -82
- package/src/components/AssigneeSelect.vue +37 -37
- package/src/components/AttachmentList.vue +13 -1
- package/src/components/AuditLogEntry.vue +95 -95
- package/src/components/BulkActionBar.vue +166 -166
- package/src/components/CategoryTree.vue +89 -89
- package/src/components/ChartWidget.vue +46 -46
- package/src/components/ChatActionBar.vue +226 -0
- package/src/components/ChatBubble.vue +162 -0
- package/src/components/ChatComposer.vue +308 -0
- package/src/components/ChatQueue.vue +222 -0
- package/src/components/ChatThread.vue +197 -0
- package/src/components/CollisionWarning.stories.js +30 -30
- package/src/components/CollisionWarning.vue +68 -68
- package/src/components/ConditionalFieldRules.vue +135 -135
- package/src/components/ContextPanel.vue +66 -66
- package/src/components/ContextPanelSection.vue +65 -65
- package/src/components/CustomFieldRenderer.vue +159 -159
- package/src/components/EscalatedLayout.vue +35 -6
- package/src/components/FileDropzone.vue +57 -57
- package/src/components/FollowButton.stories.js +30 -30
- package/src/components/FollowButton.vue +88 -88
- package/src/components/KeyboardShortcutHelp.vue +213 -213
- package/src/components/KnowledgePanel.vue +122 -122
- package/src/components/KpiCard.stories.js +32 -32
- package/src/components/KpiCard.vue +88 -88
- package/src/components/MacroDropdown.vue +150 -150
- package/src/components/MentionDropdown.vue +154 -0
- package/src/components/MetricComparison.vue +89 -0
- package/src/components/PercentileChart.vue +67 -0
- package/src/components/PeriodSelector.vue +98 -0
- package/src/components/PermissionMatrix.vue +107 -107
- package/src/components/PinnedNotes.vue +129 -129
- package/src/components/PluginSlot.vue +68 -62
- package/src/components/PresenceIndicator.vue +46 -2
- package/src/components/PriorityBadge.stories.js +33 -33
- package/src/components/PriorityBadge.vue +46 -46
- package/src/components/ReplyComposer.vue +81 -18
- package/src/components/ReplyThread.vue +40 -2
- package/src/components/ReportChart.vue +395 -0
- package/src/components/ReportExportButton.vue +108 -0
- package/src/components/SatisfactionRating.vue +180 -180
- package/src/components/SaveViewDialog.vue +172 -0
- package/src/components/SavedViewSidebar.vue +208 -0
- package/src/components/ScheduleEditor.vue +104 -104
- package/src/components/SideConversation.vue +165 -165
- package/src/components/SideConversationList.vue +147 -147
- package/src/components/SkillTagManager.vue +83 -79
- package/src/components/SlaComplianceChart.vue +46 -53
- package/src/components/SlaTimer.stories.js +35 -35
- package/src/components/SlaTimer.vue +62 -62
- package/src/components/SnoozeButton.vue +247 -0
- package/src/components/StatsCard.stories.js +24 -24
- package/src/components/StatsCard.vue +58 -58
- package/src/components/StatusBadge.stories.js +53 -53
- package/src/components/StatusBadge.vue +78 -78
- package/src/components/TagSelect.vue +84 -84
- package/src/components/TicketFilters.vue +270 -225
- package/src/components/TicketLinkPanel.vue +193 -193
- package/src/components/TicketList.vue +655 -594
- package/src/components/TicketMergeDialog.vue +157 -157
- package/src/components/TicketSplitDialog.vue +98 -0
- package/src/components/TotpInput.stories.js +9 -9
- package/src/components/TotpInput.vue +81 -81
- package/src/components/TwoFactorSetup.vue +113 -113
- package/src/components/VariableTokenInput.vue +111 -0
- package/src/components/WorkflowActionConfig.vue +287 -0
- package/src/components/WorkflowActionList.vue +350 -0
- package/src/components/WorkflowConditionBuilder.vue +265 -0
- package/src/components/WorkflowTriggerSelector.vue +125 -0
- package/src/composables/useChat.js +187 -0
- package/src/composables/useI18n.js +30 -8
- package/src/composables/useKeyboardShortcuts.js +46 -46
- package/src/composables/useMentions.js +134 -0
- package/src/composables/usePluginExtensions.js +159 -159
- package/src/composables/usePluginHooks.js +65 -65
- package/src/composables/useRealtime.js +182 -0
- package/src/defineEscalatedPlugin.js +76 -76
- package/src/index.js +84 -72
- package/src/locales/README.md +13 -0
- package/src/locales/ar.json +727 -0
- package/src/locales/de.json +678 -430
- package/src/locales/en.json +717 -455
- package/src/locales/es.json +679 -430
- package/src/locales/fr.json +680 -431
- package/src/locales/index.js +12 -2
- package/src/locales/it.json +727 -0
- package/src/locales/ja.json +727 -0
- package/src/locales/ko.json +727 -0
- package/src/locales/nl.json +727 -0
- package/src/locales/pl.json +727 -0
- package/src/locales/pt-BR.json +727 -0
- package/src/locales/ru.json +727 -0
- package/src/locales/tr.json +727 -0
- package/src/locales/zh-CN.json +727 -0
- package/src/pages/Admin/ApiTokens/Index.vue +381 -381
- package/src/pages/Admin/AuditLog/Index.vue +154 -154
- package/src/pages/Admin/BusinessHours/Form.vue +172 -172
- package/src/pages/Admin/BusinessHours/Index.vue +113 -113
- package/src/pages/Admin/CannedResponses/Index.vue +127 -127
- package/src/pages/Admin/Capacity/Index.vue +134 -134
- package/src/pages/Admin/CustomFields/Form.vue +195 -195
- package/src/pages/Admin/CustomFields/Index.vue +134 -134
- package/src/pages/Admin/CustomObjects/Form.vue +202 -202
- package/src/pages/Admin/CustomObjects/Index.vue +127 -127
- package/src/pages/Admin/CustomObjects/Records.vue +228 -228
- package/src/pages/Admin/Departments/Form.vue +75 -75
- package/src/pages/Admin/Departments/Index.vue +110 -109
- package/src/pages/Admin/EscalationRules/Form.vue +157 -157
- package/src/pages/Admin/EscalationRules/Index.vue +178 -178
- package/src/pages/Admin/Import/Connect.vue +0 -1
- package/src/pages/Admin/Import/Index.vue +1 -1
- package/src/pages/Admin/Import/Progress.vue +1 -1
- package/src/pages/Admin/KnowledgeBase/Articles/Form.vue +142 -142
- package/src/pages/Admin/KnowledgeBase/Articles/Index.vue +195 -195
- package/src/pages/Admin/KnowledgeBase/Categories/Index.vue +193 -193
- package/src/pages/Admin/Macros/Index.vue +448 -448
- package/src/pages/Admin/Plugins/Index.vue +327 -327
- package/src/pages/Admin/Reports/AgentDetail.vue +132 -0
- package/src/pages/Admin/Reports/AgentMetrics.vue +115 -115
- package/src/pages/Admin/Reports/AgentRanking.vue +246 -0
- package/src/pages/Admin/Reports/Cohorts.vue +180 -0
- package/src/pages/Admin/Reports/Comparison.vue +141 -0
- package/src/pages/Admin/Reports/CsatReport.vue +127 -127
- package/src/pages/Admin/Reports/Dashboard.vue +36 -21
- package/src/pages/Admin/Reports/ResolutionTimes.vue +164 -0
- package/src/pages/Admin/Reports/ResponseTimes.vue +164 -0
- package/src/pages/Admin/Reports/SlaReport.vue +162 -166
- package/src/pages/Admin/Reports/SlaTrends.vue +183 -0
- package/src/pages/Admin/Reports.vue +206 -206
- package/src/pages/Admin/Roles/Form.vue +71 -71
- package/src/pages/Admin/Roles/Index.vue +122 -122
- package/src/pages/Admin/Settings/CsatSettings.vue +165 -165
- package/src/pages/Admin/Settings/DataRetention.vue +182 -182
- package/src/pages/Admin/Settings/EmailSettings.vue +243 -243
- package/src/pages/Admin/Settings/Sandbox.vue +135 -135
- package/src/pages/Admin/Settings/SsoSettings.vue +218 -218
- package/src/pages/Admin/Settings/TwoFactor.vue +110 -110
- package/src/pages/Admin/Settings.vue +1008 -468
- package/src/pages/Admin/Skills/Form.vue +193 -53
- package/src/pages/Admin/Skills/Index.vue +105 -94
- package/src/pages/Admin/SlaPolicies/Form.vue +118 -118
- package/src/pages/Admin/SlaPolicies/Index.vue +121 -120
- package/src/pages/Admin/Statuses/Form.vue +114 -114
- package/src/pages/Admin/Statuses/Index.vue +153 -153
- package/src/pages/Admin/Tags/Index.vue +191 -191
- package/src/pages/Admin/Tickets/Index.vue +126 -91
- package/src/pages/Admin/Tickets/Show.vue +29 -0
- package/src/pages/Admin/Users/Index.vue +145 -0
- package/src/pages/Admin/Webhooks/DeliveryLog.vue +120 -120
- package/src/pages/Admin/Webhooks/Form.vue +110 -110
- package/src/pages/Admin/Webhooks/Index.vue +136 -136
- package/src/pages/Admin/Workflows/Builder.vue +207 -0
- package/src/pages/Admin/Workflows/Index.vue +235 -0
- package/src/pages/Admin/Workflows/Logs.vue +286 -0
- package/src/pages/Agent/TicketIndex.vue +112 -88
- package/src/pages/Agent/TicketShow.vue +192 -60
- package/src/pages/Customer/Create.vue +1 -1
- package/src/pages/Customer/Index.vue +26 -1
- package/src/pages/Customer/KnowledgeBase/Article.vue +4 -2
- package/src/pages/Customer/KnowledgeBase/Index.vue +151 -151
- package/src/pages/Customer/Show.vue +69 -63
- package/src/pages/Guest/Create.vue +40 -15
- package/src/pages/Guest/Show.vue +124 -93
- package/src/plugin.js +26 -1
- package/src/utils/mentionHighlight.js +24 -0
- package/src/utils/sanitizeHtml.js +78 -64
- package/src/widget/EscalatedWidget.vue +804 -0
- package/src/widget/index.js +254 -0
- package/src/pages/Admin/Automations/Form.vue +0 -184
- package/src/pages/Admin/Automations/Index.vue +0 -129
|
@@ -12,6 +12,7 @@ import PresenceIndicator from '../../../components/PresenceIndicator.vue';
|
|
|
12
12
|
import PinnedNotes from '../../../components/PinnedNotes.vue';
|
|
13
13
|
import KeyboardShortcutHelp from '../../../components/KeyboardShortcutHelp.vue';
|
|
14
14
|
import PluginSlot from '../../../components/PluginSlot.vue';
|
|
15
|
+
import SnoozeButton from '../../../components/SnoozeButton.vue';
|
|
15
16
|
import { useKeyboardShortcuts } from '../../../composables/useKeyboardShortcuts';
|
|
16
17
|
import { usePluginExtensions } from '../../../composables/usePluginExtensions';
|
|
17
18
|
import { router, useForm, usePage } from '@inertiajs/vue3';
|
|
@@ -26,6 +27,7 @@ const props = defineProps({
|
|
|
26
27
|
macros: { type: Array, default: () => [] },
|
|
27
28
|
is_following: { type: Boolean, default: false },
|
|
28
29
|
followers_count: { type: Number, default: 0 },
|
|
30
|
+
is_snoozed: { type: Boolean, default: false },
|
|
29
31
|
});
|
|
30
32
|
|
|
31
33
|
const page = usePage();
|
|
@@ -89,6 +91,32 @@ useKeyboardShortcuts({
|
|
|
89
91
|
<!-- Plugin: ticket show header slot -->
|
|
90
92
|
<PluginSlot slot="ticket.show.header" :components="getPageComponents('ticket.show', 'header')" />
|
|
91
93
|
|
|
94
|
+
<!-- Snoozed banner (visible only when ticket is snoozed) -->
|
|
95
|
+
<div
|
|
96
|
+
v-if="ticket.is_snoozed || (ticket.snoozed_until && new Date(ticket.snoozed_until) > new Date())"
|
|
97
|
+
class="mb-4 flex items-center gap-3 rounded-lg px-4 py-2.5 text-sm font-medium border border-amber-500/20 bg-amber-500/10 text-amber-300"
|
|
98
|
+
>
|
|
99
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 shrink-0" viewBox="0 0 20 20" fill="currentColor">
|
|
100
|
+
<path
|
|
101
|
+
fill-rule="evenodd"
|
|
102
|
+
d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.828a1 1 0 101.415-1.414L11 9.586V6z"
|
|
103
|
+
clip-rule="evenodd"
|
|
104
|
+
/>
|
|
105
|
+
</svg>
|
|
106
|
+
<span
|
|
107
|
+
>Snoozed until
|
|
108
|
+
{{
|
|
109
|
+
new Date(ticket.snoozed_until).toLocaleString(undefined, {
|
|
110
|
+
month: 'short',
|
|
111
|
+
day: 'numeric',
|
|
112
|
+
year: 'numeric',
|
|
113
|
+
hour: 'numeric',
|
|
114
|
+
minute: '2-digit',
|
|
115
|
+
})
|
|
116
|
+
}}</span
|
|
117
|
+
>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
92
120
|
<div class="mb-5 flex flex-wrap items-center gap-3">
|
|
93
121
|
<span class="text-sm font-mono font-medium text-[var(--esc-panel-text)]">{{ ticket.reference }}</span>
|
|
94
122
|
<StatusBadge :status="ticket.status" />
|
|
@@ -113,6 +141,7 @@ useKeyboardShortcuts({
|
|
|
113
141
|
>
|
|
114
142
|
Assign to Me
|
|
115
143
|
</button>
|
|
144
|
+
<SnoozeButton :ticket="ticket" route-prefix="escalated.admin" />
|
|
116
145
|
<select
|
|
117
146
|
ref="statusSelectRef"
|
|
118
147
|
class="rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-1.5 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)]"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import { router } from '@inertiajs/vue3';
|
|
4
|
+
import EscalatedLayout from '../../../components/EscalatedLayout.vue';
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
users: Object,
|
|
8
|
+
filters: { type: Object, default: () => ({}) },
|
|
9
|
+
currentUserId: { type: [Number, String], default: null },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const search = ref(props.filters?.search ?? '');
|
|
13
|
+
|
|
14
|
+
function applySearch() {
|
|
15
|
+
router.get(
|
|
16
|
+
route('escalated.admin.users.index'),
|
|
17
|
+
{ search: search.value },
|
|
18
|
+
{ preserveState: true, preserveScroll: true },
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function toggleRole(user, role) {
|
|
23
|
+
const value = role === 'admin' ? !user.is_admin : !user.is_agent;
|
|
24
|
+
router.patch(route('escalated.admin.users.role', user.id), { role, value }, { preserveScroll: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isSelf(user) {
|
|
28
|
+
return props.currentUserId !== null && String(user.id) === String(props.currentUserId);
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<EscalatedLayout title="Users">
|
|
34
|
+
<div class="mb-4 flex items-center justify-between gap-4">
|
|
35
|
+
<form class="flex-1 max-w-sm" @submit.prevent="applySearch">
|
|
36
|
+
<input
|
|
37
|
+
v-model="search"
|
|
38
|
+
type="search"
|
|
39
|
+
placeholder="Search by name or email"
|
|
40
|
+
class="w-full rounded-lg border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] px-3 py-2 text-sm text-[var(--esc-panel-text)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-accent)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-accent)]"
|
|
41
|
+
/>
|
|
42
|
+
</form>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="overflow-hidden rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)]">
|
|
46
|
+
<table class="min-w-full divide-y divide-[var(--esc-panel-border)]">
|
|
47
|
+
<thead>
|
|
48
|
+
<tr class="bg-[var(--esc-panel-hover)]">
|
|
49
|
+
<th
|
|
50
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
51
|
+
>
|
|
52
|
+
User
|
|
53
|
+
</th>
|
|
54
|
+
<th
|
|
55
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
56
|
+
>
|
|
57
|
+
Email
|
|
58
|
+
</th>
|
|
59
|
+
<th
|
|
60
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
61
|
+
>
|
|
62
|
+
Admin
|
|
63
|
+
</th>
|
|
64
|
+
<th
|
|
65
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
66
|
+
>
|
|
67
|
+
Agent
|
|
68
|
+
</th>
|
|
69
|
+
</tr>
|
|
70
|
+
</thead>
|
|
71
|
+
<tbody class="divide-y divide-[var(--esc-panel-border)]">
|
|
72
|
+
<tr v-if="!users?.data?.length">
|
|
73
|
+
<td colspan="4" class="px-4 py-12 text-center text-sm text-[var(--esc-panel-text-muted)]">
|
|
74
|
+
No users found.
|
|
75
|
+
</td>
|
|
76
|
+
</tr>
|
|
77
|
+
<tr v-for="user in users?.data || []" :key="user.id" class="hover:bg-[var(--esc-panel-hover)]">
|
|
78
|
+
<td class="whitespace-nowrap px-4 py-3 text-sm text-[var(--esc-panel-text)]">
|
|
79
|
+
<span>{{ user.name || '—' }}</span>
|
|
80
|
+
<span
|
|
81
|
+
v-if="isSelf(user)"
|
|
82
|
+
class="ml-2 rounded-full bg-[var(--esc-panel-accent)]/15 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wider text-[var(--esc-panel-accent)]"
|
|
83
|
+
>
|
|
84
|
+
You
|
|
85
|
+
</span>
|
|
86
|
+
</td>
|
|
87
|
+
<td class="whitespace-nowrap px-4 py-3 text-sm text-[var(--esc-panel-text-muted)]">
|
|
88
|
+
{{ user.email }}
|
|
89
|
+
</td>
|
|
90
|
+
<td class="px-4 py-3">
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
:disabled="isSelf(user) && user.is_admin"
|
|
94
|
+
:title="isSelf(user) && user.is_admin ? 'You cannot remove your own admin role.' : ''"
|
|
95
|
+
class="inline-flex h-6 w-11 items-center rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-50"
|
|
96
|
+
:class="user.is_admin ? 'bg-indigo-600' : 'bg-gray-300'"
|
|
97
|
+
@click="toggleRole(user, 'admin')"
|
|
98
|
+
>
|
|
99
|
+
<span
|
|
100
|
+
class="inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform"
|
|
101
|
+
:class="user.is_admin ? 'translate-x-6' : 'translate-x-1'"
|
|
102
|
+
/>
|
|
103
|
+
</button>
|
|
104
|
+
</td>
|
|
105
|
+
<td class="px-4 py-3">
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
class="inline-flex h-6 w-11 items-center rounded-full transition-colors"
|
|
109
|
+
:class="user.is_agent ? 'bg-indigo-600' : 'bg-gray-300'"
|
|
110
|
+
@click="toggleRole(user, 'agent')"
|
|
111
|
+
>
|
|
112
|
+
<span
|
|
113
|
+
class="inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform"
|
|
114
|
+
:class="user.is_agent ? 'translate-x-6' : 'translate-x-1'"
|
|
115
|
+
/>
|
|
116
|
+
</button>
|
|
117
|
+
</td>
|
|
118
|
+
</tr>
|
|
119
|
+
</tbody>
|
|
120
|
+
</table>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div v-if="users?.links?.length > 3" class="mt-4 flex items-center justify-end gap-1">
|
|
124
|
+
<template v-for="(link, idx) in users.links" :key="idx">
|
|
125
|
+
<button
|
|
126
|
+
v-if="link.url"
|
|
127
|
+
type="button"
|
|
128
|
+
class="rounded-md px-3 py-1 text-sm"
|
|
129
|
+
:class="
|
|
130
|
+
link.active
|
|
131
|
+
? 'bg-[var(--esc-panel-accent)] text-white'
|
|
132
|
+
: 'text-[var(--esc-panel-text-muted)] hover:bg-[var(--esc-panel-hover)]'
|
|
133
|
+
"
|
|
134
|
+
@click="router.get(link.url, {}, { preserveState: true, preserveScroll: true })"
|
|
135
|
+
v-html="link.label"
|
|
136
|
+
/>
|
|
137
|
+
<span
|
|
138
|
+
v-else
|
|
139
|
+
class="rounded-md px-3 py-1 text-sm text-[var(--esc-panel-text-muted)]/40"
|
|
140
|
+
v-html="link.label"
|
|
141
|
+
/>
|
|
142
|
+
</template>
|
|
143
|
+
</div>
|
|
144
|
+
</EscalatedLayout>
|
|
145
|
+
</template>
|
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import EscalatedLayout from '../../../components/EscalatedLayout.vue';
|
|
3
|
-
import { router } from '@inertiajs/vue3';
|
|
4
|
-
import { ref } from 'vue';
|
|
5
|
-
|
|
6
|
-
defineProps({
|
|
7
|
-
webhook: Object,
|
|
8
|
-
deliveries: Object,
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
const expandedId = ref(null);
|
|
12
|
-
|
|
13
|
-
function retry(deliveryId) {
|
|
14
|
-
router.post(route('escalated.admin.webhooks.retry', deliveryId), {}, { preserveScroll: true });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function togglePayload(id) {
|
|
18
|
-
expandedId.value = expandedId.value === id ? null : id;
|
|
19
|
-
}
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<template>
|
|
23
|
-
<EscalatedLayout :title="`Webhook Delivery Log - ${webhook.url}`">
|
|
24
|
-
<div class="mb-4">
|
|
25
|
-
<a
|
|
26
|
-
:href="route('escalated.admin.webhooks.index')"
|
|
27
|
-
class="text-sm text-[var(--esc-panel-text-tertiary)] hover:text-[var(--esc-panel-text-secondary)]"
|
|
28
|
-
>
|
|
29
|
-
← Back to Webhooks
|
|
30
|
-
</a>
|
|
31
|
-
</div>
|
|
32
|
-
|
|
33
|
-
<div class="overflow-hidden rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)]">
|
|
34
|
-
<table class="min-w-full divide-y divide-[var(--esc-panel-border)]">
|
|
35
|
-
<thead>
|
|
36
|
-
<tr class="bg-[var(--esc-panel-hover)]">
|
|
37
|
-
<th
|
|
38
|
-
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
39
|
-
>
|
|
40
|
-
Event
|
|
41
|
-
</th>
|
|
42
|
-
<th
|
|
43
|
-
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
44
|
-
>
|
|
45
|
-
Status
|
|
46
|
-
</th>
|
|
47
|
-
<th
|
|
48
|
-
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
49
|
-
>
|
|
50
|
-
Attempts
|
|
51
|
-
</th>
|
|
52
|
-
<th
|
|
53
|
-
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
54
|
-
>
|
|
55
|
-
Timestamp
|
|
56
|
-
</th>
|
|
57
|
-
<th
|
|
58
|
-
class="px-4 py-3 text-right text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
59
|
-
>
|
|
60
|
-
Actions
|
|
61
|
-
</th>
|
|
62
|
-
</tr>
|
|
63
|
-
</thead>
|
|
64
|
-
<tbody class="divide-y divide-[var(--esc-panel-border)]">
|
|
65
|
-
<tr v-if="!deliveries?.data?.length">
|
|
66
|
-
<td colspan="5" class="px-4 py-12 text-center text-sm text-[var(--esc-panel-text-muted)]">
|
|
67
|
-
No deliveries yet.
|
|
68
|
-
</td>
|
|
69
|
-
</tr>
|
|
70
|
-
<template v-for="delivery in deliveries?.data" :key="delivery.id">
|
|
71
|
-
<tr class="transition-colors hover:bg-[var(--esc-panel-hover)]">
|
|
72
|
-
<td class="px-4 py-3 text-sm font-mono text-[var(--esc-panel-text-secondary)]">
|
|
73
|
-
{{ delivery.event }}
|
|
74
|
-
</td>
|
|
75
|
-
<td class="px-4 py-3 text-sm">
|
|
76
|
-
<span
|
|
77
|
-
:class="
|
|
78
|
-
delivery.response_code >= 200 && delivery.response_code < 300
|
|
79
|
-
? 'text-emerald-400'
|
|
80
|
-
: 'text-rose-400'
|
|
81
|
-
"
|
|
82
|
-
>
|
|
83
|
-
{{ delivery.response_code || 'Failed' }}
|
|
84
|
-
</span>
|
|
85
|
-
</td>
|
|
86
|
-
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
87
|
-
{{ delivery.attempts }}
|
|
88
|
-
</td>
|
|
89
|
-
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
90
|
-
{{ delivery.created_at }}
|
|
91
|
-
</td>
|
|
92
|
-
<td class="px-4 py-3 text-right text-sm">
|
|
93
|
-
<button
|
|
94
|
-
class="text-[var(--esc-panel-text-tertiary)] hover:text-[var(--esc-panel-text-secondary)]"
|
|
95
|
-
@click="togglePayload(delivery.id)"
|
|
96
|
-
>
|
|
97
|
-
{{ expandedId === delivery.id ? 'Hide' : 'Payload' }}
|
|
98
|
-
</button>
|
|
99
|
-
<button
|
|
100
|
-
class="ml-3 text-[var(--esc-panel-accent)] hover:text-cyan-300"
|
|
101
|
-
@click="retry(delivery.id)"
|
|
102
|
-
>
|
|
103
|
-
Retry
|
|
104
|
-
</button>
|
|
105
|
-
</td>
|
|
106
|
-
</tr>
|
|
107
|
-
<tr v-if="expandedId === delivery.id">
|
|
108
|
-
<td colspan="5" class="bg-[var(--esc-panel-hover)] px-4 py-3">
|
|
109
|
-
<pre
|
|
110
|
-
class="max-h-40 overflow-auto rounded-lg bg-[var(--esc-panel-surface-alt)] p-3 text-xs text-[var(--esc-panel-text-tertiary)]"
|
|
111
|
-
>{{ JSON.stringify(delivery.payload, null, 2) }}</pre
|
|
112
|
-
>
|
|
113
|
-
</td>
|
|
114
|
-
</tr>
|
|
115
|
-
</template>
|
|
116
|
-
</tbody>
|
|
117
|
-
</table>
|
|
118
|
-
</div>
|
|
119
|
-
</EscalatedLayout>
|
|
120
|
-
</template>
|
|
1
|
+
<script setup>
|
|
2
|
+
import EscalatedLayout from '../../../components/EscalatedLayout.vue';
|
|
3
|
+
import { router } from '@inertiajs/vue3';
|
|
4
|
+
import { ref } from 'vue';
|
|
5
|
+
|
|
6
|
+
defineProps({
|
|
7
|
+
webhook: Object,
|
|
8
|
+
deliveries: Object,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const expandedId = ref(null);
|
|
12
|
+
|
|
13
|
+
function retry(deliveryId) {
|
|
14
|
+
router.post(route('escalated.admin.webhooks.retry', deliveryId), {}, { preserveScroll: true });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function togglePayload(id) {
|
|
18
|
+
expandedId.value = expandedId.value === id ? null : id;
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<EscalatedLayout :title="`Webhook Delivery Log - ${webhook.url}`">
|
|
24
|
+
<div class="mb-4">
|
|
25
|
+
<a
|
|
26
|
+
:href="route('escalated.admin.webhooks.index')"
|
|
27
|
+
class="text-sm text-[var(--esc-panel-text-tertiary)] hover:text-[var(--esc-panel-text-secondary)]"
|
|
28
|
+
>
|
|
29
|
+
← Back to Webhooks
|
|
30
|
+
</a>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="overflow-hidden rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)]">
|
|
34
|
+
<table class="min-w-full divide-y divide-[var(--esc-panel-border)]">
|
|
35
|
+
<thead>
|
|
36
|
+
<tr class="bg-[var(--esc-panel-hover)]">
|
|
37
|
+
<th
|
|
38
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
39
|
+
>
|
|
40
|
+
Event
|
|
41
|
+
</th>
|
|
42
|
+
<th
|
|
43
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
44
|
+
>
|
|
45
|
+
Status
|
|
46
|
+
</th>
|
|
47
|
+
<th
|
|
48
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
49
|
+
>
|
|
50
|
+
Attempts
|
|
51
|
+
</th>
|
|
52
|
+
<th
|
|
53
|
+
class="px-4 py-3 text-left text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
54
|
+
>
|
|
55
|
+
Timestamp
|
|
56
|
+
</th>
|
|
57
|
+
<th
|
|
58
|
+
class="px-4 py-3 text-right text-[11px] font-semibold uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
59
|
+
>
|
|
60
|
+
Actions
|
|
61
|
+
</th>
|
|
62
|
+
</tr>
|
|
63
|
+
</thead>
|
|
64
|
+
<tbody class="divide-y divide-[var(--esc-panel-border)]">
|
|
65
|
+
<tr v-if="!deliveries?.data?.length">
|
|
66
|
+
<td colspan="5" class="px-4 py-12 text-center text-sm text-[var(--esc-panel-text-muted)]">
|
|
67
|
+
No deliveries yet.
|
|
68
|
+
</td>
|
|
69
|
+
</tr>
|
|
70
|
+
<template v-for="delivery in deliveries?.data" :key="delivery.id">
|
|
71
|
+
<tr class="transition-colors hover:bg-[var(--esc-panel-hover)]">
|
|
72
|
+
<td class="px-4 py-3 text-sm font-mono text-[var(--esc-panel-text-secondary)]">
|
|
73
|
+
{{ delivery.event }}
|
|
74
|
+
</td>
|
|
75
|
+
<td class="px-4 py-3 text-sm">
|
|
76
|
+
<span
|
|
77
|
+
:class="
|
|
78
|
+
delivery.response_code >= 200 && delivery.response_code < 300
|
|
79
|
+
? 'text-emerald-400'
|
|
80
|
+
: 'text-rose-400'
|
|
81
|
+
"
|
|
82
|
+
>
|
|
83
|
+
{{ delivery.response_code || 'Failed' }}
|
|
84
|
+
</span>
|
|
85
|
+
</td>
|
|
86
|
+
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
87
|
+
{{ delivery.attempts }}
|
|
88
|
+
</td>
|
|
89
|
+
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
90
|
+
{{ delivery.created_at }}
|
|
91
|
+
</td>
|
|
92
|
+
<td class="px-4 py-3 text-right text-sm">
|
|
93
|
+
<button
|
|
94
|
+
class="text-[var(--esc-panel-text-tertiary)] hover:text-[var(--esc-panel-text-secondary)]"
|
|
95
|
+
@click="togglePayload(delivery.id)"
|
|
96
|
+
>
|
|
97
|
+
{{ expandedId === delivery.id ? 'Hide' : 'Payload' }}
|
|
98
|
+
</button>
|
|
99
|
+
<button
|
|
100
|
+
class="ml-3 text-[var(--esc-panel-accent)] hover:text-cyan-300"
|
|
101
|
+
@click="retry(delivery.id)"
|
|
102
|
+
>
|
|
103
|
+
Retry
|
|
104
|
+
</button>
|
|
105
|
+
</td>
|
|
106
|
+
</tr>
|
|
107
|
+
<tr v-if="expandedId === delivery.id">
|
|
108
|
+
<td colspan="5" class="bg-[var(--esc-panel-hover)] px-4 py-3">
|
|
109
|
+
<pre
|
|
110
|
+
class="max-h-40 overflow-auto rounded-lg bg-[var(--esc-panel-surface-alt)] p-3 text-xs text-[var(--esc-panel-text-tertiary)]"
|
|
111
|
+
>{{ JSON.stringify(delivery.payload, null, 2) }}</pre
|
|
112
|
+
>
|
|
113
|
+
</td>
|
|
114
|
+
</tr>
|
|
115
|
+
</template>
|
|
116
|
+
</tbody>
|
|
117
|
+
</table>
|
|
118
|
+
</div>
|
|
119
|
+
</EscalatedLayout>
|
|
120
|
+
</template>
|