@escalated-dev/escalated 0.8.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +388 -361
  3. package/package.json +85 -84
  4. package/src/components/ActiveChatsPanel.vue +246 -246
  5. package/src/components/AdminDashboard.stories.js +1423 -1423
  6. package/src/components/AttachmentList.vue +65 -65
  7. package/src/components/ChatActionBar.vue +226 -226
  8. package/src/components/ChatBubble.vue +162 -162
  9. package/src/components/ChatComposer.vue +308 -308
  10. package/src/components/ChatQueue.vue +222 -222
  11. package/src/components/ChatThread.vue +197 -197
  12. package/src/components/CustomTicketActions.stories.js +71 -0
  13. package/src/components/CustomTicketActions.vue +101 -0
  14. package/src/components/EscalatedLayout.vue +628 -604
  15. package/src/components/FollowButton.vue +20 -1
  16. package/src/components/MentionDropdown.vue +154 -154
  17. package/src/components/MetricComparison.vue +89 -89
  18. package/src/components/PercentileChart.vue +67 -67
  19. package/src/components/PeriodSelector.vue +98 -98
  20. package/src/components/PresenceIndicator.vue +228 -213
  21. package/src/components/ReplyComposer.vue +336 -336
  22. package/src/components/ReplyThread.vue +153 -153
  23. package/src/components/ReportChart.vue +395 -395
  24. package/src/components/ReportExportButton.vue +108 -108
  25. package/src/components/SaveViewDialog.vue +172 -172
  26. package/src/components/SavedViewSidebar.vue +208 -208
  27. package/src/components/SkillTagManager.vue +3 -0
  28. package/src/components/SnoozeButton.vue +247 -247
  29. package/src/components/TicketFilters.vue +270 -270
  30. package/src/components/TicketList.vue +655 -655
  31. package/src/components/TicketSidebar.vue +4 -0
  32. package/src/components/TicketSplitDialog.vue +98 -98
  33. package/src/components/TicketSubjects.stories.js +63 -0
  34. package/src/components/TicketSubjects.vue +107 -0
  35. package/src/components/TwoFactorSetup.vue +1 -37
  36. package/src/components/VariableTokenInput.vue +111 -111
  37. package/src/components/WorkflowActionConfig.vue +287 -287
  38. package/src/components/WorkflowActionList.vue +350 -350
  39. package/src/components/WorkflowConditionBuilder.vue +265 -265
  40. package/src/components/WorkflowTriggerSelector.vue +125 -125
  41. package/src/components/admin/newsletters/AnalyticsTiles.stories.js +14 -0
  42. package/src/components/admin/newsletters/AnalyticsTiles.vue +55 -0
  43. package/src/components/admin/newsletters/DeliveriesTable.stories.js +28 -0
  44. package/src/components/admin/newsletters/DeliveriesTable.vue +104 -0
  45. package/src/components/admin/newsletters/DynamicFilterBuilder.stories.js +11 -0
  46. package/src/components/admin/newsletters/DynamicFilterBuilder.vue +53 -0
  47. package/src/components/admin/newsletters/ListMemberTable.stories.js +12 -0
  48. package/src/components/admin/newsletters/ListMemberTable.vue +53 -0
  49. package/src/components/admin/newsletters/MarkdownEditor.stories.js +6 -0
  50. package/src/components/admin/newsletters/MarkdownEditor.vue +53 -0
  51. package/src/components/admin/newsletters/MergeFieldDropdown.stories.js +6 -0
  52. package/src/components/admin/newsletters/MergeFieldDropdown.vue +84 -0
  53. package/src/components/admin/newsletters/PreviewIframe.stories.js +7 -0
  54. package/src/components/admin/newsletters/PreviewIframe.vue +40 -0
  55. package/src/components/admin/newsletters/SummaryTiles.stories.js +8 -0
  56. package/src/components/admin/newsletters/SummaryTiles.vue +63 -0
  57. package/src/composables/useChat.js +187 -187
  58. package/src/composables/useI18n.js +102 -102
  59. package/src/composables/useMentions.js +134 -134
  60. package/src/composables/usePermissions.js +31 -0
  61. package/src/composables/useRealtime.js +182 -182
  62. package/src/index.js +85 -84
  63. package/src/locales/README.md +13 -13
  64. package/src/locales/ar.json +727 -727
  65. package/src/locales/de.json +690 -690
  66. package/src/locales/en.json +889 -729
  67. package/src/locales/es.json +691 -691
  68. package/src/locales/fr.json +691 -691
  69. package/src/locales/index.js +16 -16
  70. package/src/locales/it.json +727 -727
  71. package/src/locales/ja.json +727 -727
  72. package/src/locales/ko.json +727 -727
  73. package/src/locales/nl.json +727 -727
  74. package/src/locales/pl.json +727 -727
  75. package/src/locales/pt-BR.json +727 -727
  76. package/src/locales/ru.json +727 -727
  77. package/src/locales/tr.json +727 -727
  78. package/src/locales/zh-CN.json +727 -727
  79. package/src/pages/Admin/Automations/Form.vue +280 -0
  80. package/src/pages/Admin/Automations/Index.vue +230 -0
  81. package/src/pages/Admin/Newsletters/Compose.vue +192 -0
  82. package/src/pages/Admin/Newsletters/Edit.vue +24 -0
  83. package/src/pages/Admin/Newsletters/Index.vue +141 -0
  84. package/src/pages/Admin/Newsletters/Lists/Create.vue +64 -0
  85. package/src/pages/Admin/Newsletters/Lists/Index.vue +59 -0
  86. package/src/pages/Admin/Newsletters/Lists/Show.vue +53 -0
  87. package/src/pages/Admin/Newsletters/Settings.vue +85 -0
  88. package/src/pages/Admin/Newsletters/Show.vue +140 -0
  89. package/src/pages/Admin/Newsletters/Templates/Create.vue +11 -0
  90. package/src/pages/Admin/Newsletters/Templates/Index.vue +54 -0
  91. package/src/pages/Admin/Newsletters/Templates/Show.vue +65 -0
  92. package/src/pages/Admin/Newsletters/usePreview.js +44 -0
  93. package/src/pages/Admin/Plugins/Index.vue +10 -2
  94. package/src/pages/Admin/Reports/AgentDetail.vue +132 -132
  95. package/src/pages/Admin/Reports/AgentRanking.vue +246 -246
  96. package/src/pages/Admin/Reports/Cohorts.vue +180 -180
  97. package/src/pages/Admin/Reports/Comparison.vue +141 -141
  98. package/src/pages/Admin/Reports/Dashboard.vue +226 -226
  99. package/src/pages/Admin/Reports/ResolutionTimes.vue +164 -164
  100. package/src/pages/Admin/Reports/ResponseTimes.vue +164 -164
  101. package/src/pages/Admin/Reports/SlaTrends.vue +183 -183
  102. package/src/pages/Admin/Settings/DatabaseConnection.vue +228 -0
  103. package/src/pages/Admin/Settings/PublicTickets.vue +163 -0
  104. package/src/pages/Admin/Settings/SsoSettings.vue +157 -4
  105. package/src/pages/Admin/Settings/TwoFactor.vue +32 -6
  106. package/src/pages/Admin/Settings.vue +1008 -1008
  107. package/src/pages/Admin/Skills/Form.vue +30 -10
  108. package/src/pages/Admin/Tickets/Index.vue +126 -126
  109. package/src/pages/Admin/Tickets/Show.vue +254 -249
  110. package/src/pages/Admin/Users/Index.vue +145 -145
  111. package/src/pages/Admin/Webhooks/DeliveryLog.vue +1 -2
  112. package/src/pages/Admin/Workflows/Builder.vue +207 -207
  113. package/src/pages/Admin/Workflows/Form.vue +24 -0
  114. package/src/pages/Admin/Workflows/Index.vue +235 -235
  115. package/src/pages/Admin/Workflows/Logs.vue +286 -286
  116. package/src/pages/Agent/TicketIndex.vue +112 -112
  117. package/src/pages/Agent/TicketShow.vue +547 -494
  118. package/src/pages/Customer/Index.vue +56 -56
  119. package/src/pages/Customer/KnowledgeBase/Article.vue +129 -129
  120. package/src/pages/Plugin/Page.vue +61 -0
  121. package/src/plugin.js +175 -175
  122. package/src/utils/mentionHighlight.js +24 -24
  123. package/src/widget/EscalatedWidget.vue +804 -804
  124. package/src/widget/index.js +254 -254
@@ -62,7 +62,9 @@ function removeAgent(index) {
62
62
  </div>
63
63
 
64
64
  <div class="grid gap-5 lg:grid-cols-2">
65
- <div class="space-y-3 rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface-alt)] p-4">
65
+ <div
66
+ class="space-y-3 rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface-alt)] p-4"
67
+ >
66
68
  <div>
67
69
  <h2 class="text-sm font-semibold text-[var(--esc-panel-text-secondary)]">Routing Rules</h2>
68
70
  <p class="mt-1 text-xs text-[var(--esc-panel-text-muted)]">
@@ -70,7 +72,9 @@ function removeAgent(index) {
70
72
  </p>
71
73
  </div>
72
74
  <div>
73
- <label class="mb-2 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]">
75
+ <label
76
+ class="mb-2 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]"
77
+ >
74
78
  Required Tags
75
79
  </label>
76
80
  <SkillTagManager
@@ -84,7 +88,9 @@ function removeAgent(index) {
84
88
  </p>
85
89
  </div>
86
90
  <div>
87
- <label class="mb-2 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]">
91
+ <label
92
+ class="mb-2 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]"
93
+ >
88
94
  Departments
89
95
  </label>
90
96
  <SkillTagManager
@@ -99,10 +105,14 @@ function removeAgent(index) {
99
105
  </div>
100
106
  </div>
101
107
 
102
- <div class="space-y-3 rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface-alt)] p-4">
108
+ <div
109
+ class="space-y-3 rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface-alt)] p-4"
110
+ >
103
111
  <div class="flex items-start justify-between gap-3">
104
112
  <div>
105
- <h2 class="text-sm font-semibold text-[var(--esc-panel-text-secondary)]">Agent Proficiency</h2>
113
+ <h2 class="text-sm font-semibold text-[var(--esc-panel-text-secondary)]">
114
+ Agent Proficiency
115
+ </h2>
106
116
  <p class="mt-1 text-xs text-[var(--esc-panel-text-muted)]">
107
117
  Assign eligible agents and tune their proficiency from 1 to 5.
108
118
  </p>
@@ -124,7 +134,9 @@ function removeAgent(index) {
124
134
  class="grid gap-3 rounded-lg border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-3 md:grid-cols-[minmax(0,1fr)_110px_auto]"
125
135
  >
126
136
  <div>
127
- <label class="mb-1 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]">
137
+ <label
138
+ class="mb-1 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]"
139
+ >
128
140
  Agent
129
141
  </label>
130
142
  <select
@@ -132,16 +144,21 @@ function removeAgent(index) {
132
144
  class="w-full 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)]"
133
145
  >
134
146
  <option
135
- v-for="option in [...unassignedAgents, availableAgents.find((entry) => entry.id === agent.user_id)].filter(Boolean)"
147
+ v-for="option in [
148
+ ...unassignedAgents,
149
+ availableAgents.find((entry) => entry.id === agent.user_id),
150
+ ].filter(Boolean)"
136
151
  :key="option.id"
137
152
  :value="option.id"
138
153
  >
139
- {{ option.name }} · {{ option.email }}
154
+ {{ option.name }} / {{ option.email }}
140
155
  </option>
141
156
  </select>
142
157
  </div>
143
158
  <div>
144
- <label class="mb-1 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]">
159
+ <label
160
+ class="mb-1 block text-xs font-medium uppercase tracking-wide text-[var(--esc-panel-text-muted)]"
161
+ >
145
162
  Proficiency
146
163
  </label>
147
164
  <select
@@ -167,7 +184,10 @@ function removeAgent(index) {
167
184
  </div>
168
185
  </div>
169
186
 
170
- <div v-else class="rounded-lg border border-dashed border-[var(--esc-panel-border)] px-4 py-6 text-center text-sm text-[var(--esc-panel-text-muted)]">
187
+ <div
188
+ v-else
189
+ class="rounded-lg border border-dashed border-[var(--esc-panel-border)] px-4 py-6 text-center text-sm text-[var(--esc-panel-text-muted)]"
190
+ >
171
191
  No agents assigned yet.
172
192
  </div>
173
193
  </div>
@@ -1,126 +1,126 @@
1
- <script setup>
2
- import { ref } from 'vue';
3
- import { usePage, router } from '@inertiajs/vue3';
4
- import EscalatedLayout from '../../../components/EscalatedLayout.vue';
5
- import TicketList from '../../../components/TicketList.vue';
6
- import TicketFilters from '../../../components/TicketFilters.vue';
7
- import QuickFilters from '../../../components/QuickFilters.vue';
8
- import BulkActionBar from '../../../components/BulkActionBar.vue';
9
- import KeyboardShortcutHelp from '../../../components/KeyboardShortcutHelp.vue';
10
- import PluginSlot from '../../../components/PluginSlot.vue';
11
- import SavedViewSidebar from '../../../components/SavedViewSidebar.vue';
12
- import SaveViewDialog from '../../../components/SaveViewDialog.vue';
13
- import { useKeyboardShortcuts } from '../../../composables/useKeyboardShortcuts';
14
- import { usePluginExtensions } from '../../../composables/usePluginExtensions';
15
-
16
- defineProps({
17
- tickets: Object,
18
- filters: Object,
19
- departments: Array,
20
- tags: Array,
21
- agents: Array,
22
- savedViews: { type: Array, default: () => [] },
23
- });
24
-
25
- const page = usePage();
26
- const selectedIds = ref([]);
27
- const ticketListRef = ref(null);
28
- const showShortcutHelp = ref(false);
29
- const showSaveDialog = ref(false);
30
- const ticketFiltersRef = ref(null);
31
-
32
- useKeyboardShortcuts({
33
- j: () => {
34
- ticketListRef.value?.moveDown();
35
- },
36
- k: () => {
37
- ticketListRef.value?.moveUp();
38
- },
39
- x: () => {
40
- ticketListRef.value?.toggleSelectFocused();
41
- },
42
- Enter: () => {
43
- ticketListRef.value?.openFocused();
44
- },
45
- '?': () => {
46
- showShortcutHelp.value = true;
47
- },
48
- });
49
-
50
- const { getPageComponents } = usePluginExtensions();
51
-
52
- function applyQuickFilter(filter) {
53
- router.get(route('escalated.admin.tickets.index'), filter, { preserveState: true });
54
- }
55
-
56
- function onViewSaved() {
57
- router.reload({ only: ['savedViews'] });
58
- }
59
- </script>
60
-
61
- <template>
62
- <EscalatedLayout title="All Tickets">
63
- <div class="flex gap-6">
64
- <!-- Saved Views Sidebar -->
65
- <aside v-if="savedViews && savedViews.length" class="hidden w-52 shrink-0 lg:block">
66
- <div class="sticky top-4">
67
- <h3 class="mb-2 px-3 text-xs font-semibold uppercase tracking-wider text-gray-400">Views</h3>
68
- <SavedViewSidebar
69
- :saved-views="savedViews"
70
- :current-filters="filters"
71
- :route="route('escalated.admin.tickets.index')"
72
- />
73
- </div>
74
- </aside>
75
-
76
- <!-- Main content -->
77
- <div class="min-w-0 flex-1">
78
- <div class="mb-4">
79
- <QuickFilters :current-user-id="page.props.auth?.user?.id" @filter="applyQuickFilter" />
80
- </div>
81
- <PluginSlot
82
- slot="ticket.list.before_filters"
83
- :components="getPageComponents('ticket.list', 'before_filters')"
84
- />
85
- <div class="mb-6">
86
- <TicketFilters
87
- ref="ticketFiltersRef"
88
- :filters="filters"
89
- :route="route('escalated.admin.tickets.index')"
90
- :departments="departments"
91
- :tags="tags"
92
- :agents="agents"
93
- show-assignee
94
- show-following
95
- @save-view="showSaveDialog = true"
96
- />
97
- </div>
98
- <TicketList
99
- ref="ticketListRef"
100
- v-model:selected-ids="selectedIds"
101
- :tickets="tickets"
102
- route-prefix="escalated.admin.tickets"
103
- :columns="['reference', 'subject', 'requester', 'status', 'priority', 'assignee', 'updated']"
104
- selectable
105
- navigable
106
- />
107
- <BulkActionBar
108
- :selected-ids="selectedIds"
109
- :bulk-route="route('escalated.admin.tickets.bulk')"
110
- :agents="agents"
111
- :departments="departments"
112
- @clear="selectedIds = []"
113
- />
114
- <PluginSlot slot="ticket.list.footer" :components="getPageComponents('ticket.list', 'footer')" />
115
- </div>
116
- </div>
117
-
118
- <SaveViewDialog
119
- :show="showSaveDialog"
120
- :filters="ticketFiltersRef?.filterData || filters"
121
- @close="showSaveDialog = false"
122
- @saved="onViewSaved"
123
- />
124
- <KeyboardShortcutHelp v-model:show="showShortcutHelp" context="list" />
125
- </EscalatedLayout>
126
- </template>
1
+ <script setup>
2
+ import { ref } from 'vue';
3
+ import { usePage, router } from '@inertiajs/vue3';
4
+ import EscalatedLayout from '../../../components/EscalatedLayout.vue';
5
+ import TicketList from '../../../components/TicketList.vue';
6
+ import TicketFilters from '../../../components/TicketFilters.vue';
7
+ import QuickFilters from '../../../components/QuickFilters.vue';
8
+ import BulkActionBar from '../../../components/BulkActionBar.vue';
9
+ import KeyboardShortcutHelp from '../../../components/KeyboardShortcutHelp.vue';
10
+ import PluginSlot from '../../../components/PluginSlot.vue';
11
+ import SavedViewSidebar from '../../../components/SavedViewSidebar.vue';
12
+ import SaveViewDialog from '../../../components/SaveViewDialog.vue';
13
+ import { useKeyboardShortcuts } from '../../../composables/useKeyboardShortcuts';
14
+ import { usePluginExtensions } from '../../../composables/usePluginExtensions';
15
+
16
+ defineProps({
17
+ tickets: Object,
18
+ filters: Object,
19
+ departments: Array,
20
+ tags: Array,
21
+ agents: Array,
22
+ savedViews: { type: Array, default: () => [] },
23
+ });
24
+
25
+ const page = usePage();
26
+ const selectedIds = ref([]);
27
+ const ticketListRef = ref(null);
28
+ const showShortcutHelp = ref(false);
29
+ const showSaveDialog = ref(false);
30
+ const ticketFiltersRef = ref(null);
31
+
32
+ useKeyboardShortcuts({
33
+ j: () => {
34
+ ticketListRef.value?.moveDown();
35
+ },
36
+ k: () => {
37
+ ticketListRef.value?.moveUp();
38
+ },
39
+ x: () => {
40
+ ticketListRef.value?.toggleSelectFocused();
41
+ },
42
+ Enter: () => {
43
+ ticketListRef.value?.openFocused();
44
+ },
45
+ '?': () => {
46
+ showShortcutHelp.value = true;
47
+ },
48
+ });
49
+
50
+ const { getPageComponents } = usePluginExtensions();
51
+
52
+ function applyQuickFilter(filter) {
53
+ router.get(route('escalated.admin.tickets.index'), filter, { preserveState: true });
54
+ }
55
+
56
+ function onViewSaved() {
57
+ router.reload({ only: ['savedViews'] });
58
+ }
59
+ </script>
60
+
61
+ <template>
62
+ <EscalatedLayout title="All Tickets">
63
+ <div class="flex gap-6">
64
+ <!-- Saved Views Sidebar -->
65
+ <aside v-if="savedViews && savedViews.length" class="hidden w-52 shrink-0 lg:block">
66
+ <div class="sticky top-4">
67
+ <h3 class="mb-2 px-3 text-xs font-semibold uppercase tracking-wider text-gray-400">Views</h3>
68
+ <SavedViewSidebar
69
+ :saved-views="savedViews"
70
+ :current-filters="filters"
71
+ :route="route('escalated.admin.tickets.index')"
72
+ />
73
+ </div>
74
+ </aside>
75
+
76
+ <!-- Main content -->
77
+ <div class="min-w-0 flex-1">
78
+ <div class="mb-4">
79
+ <QuickFilters :current-user-id="page.props.auth?.user?.id" @filter="applyQuickFilter" />
80
+ </div>
81
+ <PluginSlot
82
+ slot="ticket.list.before_filters"
83
+ :components="getPageComponents('ticket.list', 'before_filters')"
84
+ />
85
+ <div class="mb-6">
86
+ <TicketFilters
87
+ ref="ticketFiltersRef"
88
+ :filters="filters"
89
+ :route="route('escalated.admin.tickets.index')"
90
+ :departments="departments"
91
+ :tags="tags"
92
+ :agents="agents"
93
+ show-assignee
94
+ show-following
95
+ @save-view="showSaveDialog = true"
96
+ />
97
+ </div>
98
+ <TicketList
99
+ ref="ticketListRef"
100
+ v-model:selected-ids="selectedIds"
101
+ :tickets="tickets"
102
+ route-prefix="escalated.admin.tickets"
103
+ :columns="['reference', 'subject', 'requester', 'status', 'priority', 'assignee', 'updated']"
104
+ selectable
105
+ navigable
106
+ />
107
+ <BulkActionBar
108
+ :selected-ids="selectedIds"
109
+ :bulk-route="route('escalated.admin.tickets.bulk')"
110
+ :agents="agents"
111
+ :departments="departments"
112
+ @clear="selectedIds = []"
113
+ />
114
+ <PluginSlot slot="ticket.list.footer" :components="getPageComponents('ticket.list', 'footer')" />
115
+ </div>
116
+ </div>
117
+
118
+ <SaveViewDialog
119
+ :show="showSaveDialog"
120
+ :filters="ticketFiltersRef?.filterData || filters"
121
+ @close="showSaveDialog = false"
122
+ @saved="onViewSaved"
123
+ />
124
+ <KeyboardShortcutHelp v-model:show="showShortcutHelp" context="list" />
125
+ </EscalatedLayout>
126
+ </template>