@escalated-dev/escalated 0.7.0 → 0.7.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.
- package/LICENSE +21 -21
- package/README.md +31 -0
- package/package.json +12 -6
- 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 +29 -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 +79 -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 +80 -80
- 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/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 +53 -53
- package/src/pages/Admin/Skills/Index.vue +94 -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/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 +31 -31
- 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 +25 -0
- 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
|
@@ -1,218 +1,218 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import EscalatedLayout from '../../../components/EscalatedLayout.vue';
|
|
3
|
-
import { useForm } from '@inertiajs/vue3';
|
|
4
|
-
|
|
5
|
-
const props = defineProps({ settings: Object });
|
|
6
|
-
|
|
7
|
-
const form = useForm({
|
|
8
|
-
sso_provider: props.settings.sso_provider ?? 'none',
|
|
9
|
-
sso_entity_id: props.settings.sso_entity_id ?? '',
|
|
10
|
-
sso_url: props.settings.sso_url ?? '',
|
|
11
|
-
sso_certificate: props.settings.sso_certificate ?? '',
|
|
12
|
-
sso_attr_email: props.settings.sso_attr_email ?? 'email',
|
|
13
|
-
sso_attr_name: props.settings.sso_attr_name ?? 'name',
|
|
14
|
-
sso_attr_role: props.settings.sso_attr_role ?? 'role',
|
|
15
|
-
sso_jwt_secret: props.settings.sso_jwt_secret ?? '',
|
|
16
|
-
sso_jwt_algorithm: props.settings.sso_jwt_algorithm ?? 'HS256',
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
function submit() {
|
|
20
|
-
form.post(route('escalated.admin.settings.sso.update'));
|
|
21
|
-
}
|
|
22
|
-
</script>
|
|
23
|
-
|
|
24
|
-
<template>
|
|
25
|
-
<EscalatedLayout title="SSO Settings">
|
|
26
|
-
<form class="mx-auto max-w-2xl space-y-6" @submit.prevent="submit">
|
|
27
|
-
<!-- Provider Selection -->
|
|
28
|
-
<div class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6">
|
|
29
|
-
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Single Sign-On</h3>
|
|
30
|
-
<div class="space-y-5">
|
|
31
|
-
<div>
|
|
32
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
33
|
-
>SSO Provider</label
|
|
34
|
-
>
|
|
35
|
-
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
36
|
-
Choose how users authenticate with your identity provider
|
|
37
|
-
</p>
|
|
38
|
-
<select
|
|
39
|
-
v-model="form.sso_provider"
|
|
40
|
-
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)]"
|
|
41
|
-
>
|
|
42
|
-
<option value="none">None (disabled)</option>
|
|
43
|
-
<option value="saml">SAML 2.0</option>
|
|
44
|
-
<option value="jwt">JWT</option>
|
|
45
|
-
</select>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<!-- SAML Settings -->
|
|
51
|
-
<div
|
|
52
|
-
v-if="form.sso_provider === 'saml'"
|
|
53
|
-
class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6"
|
|
54
|
-
>
|
|
55
|
-
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">SAML Configuration</h3>
|
|
56
|
-
<div class="space-y-5">
|
|
57
|
-
<div>
|
|
58
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
59
|
-
>Entity ID</label
|
|
60
|
-
>
|
|
61
|
-
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
62
|
-
The Entity ID (Issuer) from your Identity Provider
|
|
63
|
-
</p>
|
|
64
|
-
<input
|
|
65
|
-
v-model="form.sso_entity_id"
|
|
66
|
-
type="text"
|
|
67
|
-
placeholder="https://idp.example.com/metadata"
|
|
68
|
-
class="mt-2 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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
69
|
-
/>
|
|
70
|
-
<div v-if="form.errors.sso_entity_id" class="mt-1 text-sm text-rose-400">
|
|
71
|
-
{{ form.errors.sso_entity_id }}
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
<div>
|
|
75
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]">SSO URL</label>
|
|
76
|
-
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">The Single Sign-On URL endpoint</p>
|
|
77
|
-
<input
|
|
78
|
-
v-model="form.sso_url"
|
|
79
|
-
type="url"
|
|
80
|
-
placeholder="https://idp.example.com/sso"
|
|
81
|
-
class="mt-2 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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
82
|
-
/>
|
|
83
|
-
<div v-if="form.errors.sso_url" class="mt-1 text-sm text-rose-400">
|
|
84
|
-
{{ form.errors.sso_url }}
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
<div>
|
|
88
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
89
|
-
>Certificate</label
|
|
90
|
-
>
|
|
91
|
-
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
92
|
-
X.509 certificate from your Identity Provider (PEM format)
|
|
93
|
-
</p>
|
|
94
|
-
<textarea
|
|
95
|
-
v-model="form.sso_certificate"
|
|
96
|
-
rows="6"
|
|
97
|
-
placeholder="-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"
|
|
98
|
-
class="mt-2 w-full rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 font-mono text-xs text-[var(--esc-panel-text-secondary)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
99
|
-
></textarea>
|
|
100
|
-
<div v-if="form.errors.sso_certificate" class="mt-1 text-sm text-rose-400">
|
|
101
|
-
{{ form.errors.sso_certificate }}
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
<!-- JWT Settings -->
|
|
108
|
-
<div
|
|
109
|
-
v-if="form.sso_provider === 'jwt'"
|
|
110
|
-
class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6"
|
|
111
|
-
>
|
|
112
|
-
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">JWT Configuration</h3>
|
|
113
|
-
<div class="space-y-5">
|
|
114
|
-
<div>
|
|
115
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
116
|
-
>Shared Secret</label
|
|
117
|
-
>
|
|
118
|
-
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
119
|
-
Secret key used to sign and verify JWT tokens
|
|
120
|
-
</p>
|
|
121
|
-
<input
|
|
122
|
-
v-model="form.sso_jwt_secret"
|
|
123
|
-
type="password"
|
|
124
|
-
class="mt-2 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)]"
|
|
125
|
-
/>
|
|
126
|
-
<div v-if="form.errors.sso_jwt_secret" class="mt-1 text-sm text-rose-400">
|
|
127
|
-
{{ form.errors.sso_jwt_secret }}
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
<div>
|
|
131
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
132
|
-
>Algorithm</label
|
|
133
|
-
>
|
|
134
|
-
<select
|
|
135
|
-
v-model="form.sso_jwt_algorithm"
|
|
136
|
-
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)]"
|
|
137
|
-
>
|
|
138
|
-
<option value="HS256">HS256</option>
|
|
139
|
-
<option value="HS384">HS384</option>
|
|
140
|
-
<option value="HS512">HS512</option>
|
|
141
|
-
<option value="RS256">RS256</option>
|
|
142
|
-
</select>
|
|
143
|
-
</div>
|
|
144
|
-
<div>
|
|
145
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]">SSO URL</label>
|
|
146
|
-
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
147
|
-
Redirect URL where users authenticate and receive a JWT
|
|
148
|
-
</p>
|
|
149
|
-
<input
|
|
150
|
-
v-model="form.sso_url"
|
|
151
|
-
type="url"
|
|
152
|
-
placeholder="https://auth.example.com/jwt-sso"
|
|
153
|
-
class="mt-2 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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
154
|
-
/>
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
<!-- Attribute Mapping -->
|
|
160
|
-
<div
|
|
161
|
-
v-if="form.sso_provider !== 'none'"
|
|
162
|
-
class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6"
|
|
163
|
-
>
|
|
164
|
-
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Attribute Mapping</h3>
|
|
165
|
-
<p class="mb-4 text-xs text-[var(--esc-panel-text-muted)]">
|
|
166
|
-
Map the attribute names from your identity provider to Escalated user fields
|
|
167
|
-
</p>
|
|
168
|
-
<div class="space-y-5">
|
|
169
|
-
<div>
|
|
170
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
171
|
-
>Email Attribute</label
|
|
172
|
-
>
|
|
173
|
-
<input
|
|
174
|
-
v-model="form.sso_attr_email"
|
|
175
|
-
type="text"
|
|
176
|
-
placeholder="email"
|
|
177
|
-
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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
178
|
-
/>
|
|
179
|
-
</div>
|
|
180
|
-
<div>
|
|
181
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
182
|
-
>Name Attribute</label
|
|
183
|
-
>
|
|
184
|
-
<input
|
|
185
|
-
v-model="form.sso_attr_name"
|
|
186
|
-
type="text"
|
|
187
|
-
placeholder="name"
|
|
188
|
-
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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
189
|
-
/>
|
|
190
|
-
</div>
|
|
191
|
-
<div>
|
|
192
|
-
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
193
|
-
>Role Attribute</label
|
|
194
|
-
>
|
|
195
|
-
<input
|
|
196
|
-
v-model="form.sso_attr_role"
|
|
197
|
-
type="text"
|
|
198
|
-
placeholder="role"
|
|
199
|
-
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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
200
|
-
/>
|
|
201
|
-
</div>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
|
|
205
|
-
<!-- Submit -->
|
|
206
|
-
<div class="flex items-center justify-end gap-3">
|
|
207
|
-
<span v-if="form.recentlySuccessful" class="text-sm text-emerald-400">Saved.</span>
|
|
208
|
-
<button
|
|
209
|
-
type="submit"
|
|
210
|
-
:disabled="form.processing"
|
|
211
|
-
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"
|
|
212
|
-
>
|
|
213
|
-
{{ form.processing ? 'Saving...' : 'Save SSO Settings' }}
|
|
214
|
-
</button>
|
|
215
|
-
</div>
|
|
216
|
-
</form>
|
|
217
|
-
</EscalatedLayout>
|
|
218
|
-
</template>
|
|
1
|
+
<script setup>
|
|
2
|
+
import EscalatedLayout from '../../../components/EscalatedLayout.vue';
|
|
3
|
+
import { useForm } from '@inertiajs/vue3';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({ settings: Object });
|
|
6
|
+
|
|
7
|
+
const form = useForm({
|
|
8
|
+
sso_provider: props.settings.sso_provider ?? 'none',
|
|
9
|
+
sso_entity_id: props.settings.sso_entity_id ?? '',
|
|
10
|
+
sso_url: props.settings.sso_url ?? '',
|
|
11
|
+
sso_certificate: props.settings.sso_certificate ?? '',
|
|
12
|
+
sso_attr_email: props.settings.sso_attr_email ?? 'email',
|
|
13
|
+
sso_attr_name: props.settings.sso_attr_name ?? 'name',
|
|
14
|
+
sso_attr_role: props.settings.sso_attr_role ?? 'role',
|
|
15
|
+
sso_jwt_secret: props.settings.sso_jwt_secret ?? '',
|
|
16
|
+
sso_jwt_algorithm: props.settings.sso_jwt_algorithm ?? 'HS256',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
function submit() {
|
|
20
|
+
form.post(route('escalated.admin.settings.sso.update'));
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<EscalatedLayout title="SSO Settings">
|
|
26
|
+
<form class="mx-auto max-w-2xl space-y-6" @submit.prevent="submit">
|
|
27
|
+
<!-- Provider Selection -->
|
|
28
|
+
<div class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6">
|
|
29
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Single Sign-On</h3>
|
|
30
|
+
<div class="space-y-5">
|
|
31
|
+
<div>
|
|
32
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
33
|
+
>SSO Provider</label
|
|
34
|
+
>
|
|
35
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
36
|
+
Choose how users authenticate with your identity provider
|
|
37
|
+
</p>
|
|
38
|
+
<select
|
|
39
|
+
v-model="form.sso_provider"
|
|
40
|
+
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)]"
|
|
41
|
+
>
|
|
42
|
+
<option value="none">None (disabled)</option>
|
|
43
|
+
<option value="saml">SAML 2.0</option>
|
|
44
|
+
<option value="jwt">JWT</option>
|
|
45
|
+
</select>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- SAML Settings -->
|
|
51
|
+
<div
|
|
52
|
+
v-if="form.sso_provider === 'saml'"
|
|
53
|
+
class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6"
|
|
54
|
+
>
|
|
55
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">SAML Configuration</h3>
|
|
56
|
+
<div class="space-y-5">
|
|
57
|
+
<div>
|
|
58
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
59
|
+
>Entity ID</label
|
|
60
|
+
>
|
|
61
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
62
|
+
The Entity ID (Issuer) from your Identity Provider
|
|
63
|
+
</p>
|
|
64
|
+
<input
|
|
65
|
+
v-model="form.sso_entity_id"
|
|
66
|
+
type="text"
|
|
67
|
+
placeholder="https://idp.example.com/metadata"
|
|
68
|
+
class="mt-2 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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
69
|
+
/>
|
|
70
|
+
<div v-if="form.errors.sso_entity_id" class="mt-1 text-sm text-rose-400">
|
|
71
|
+
{{ form.errors.sso_entity_id }}
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
<div>
|
|
75
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]">SSO URL</label>
|
|
76
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">The Single Sign-On URL endpoint</p>
|
|
77
|
+
<input
|
|
78
|
+
v-model="form.sso_url"
|
|
79
|
+
type="url"
|
|
80
|
+
placeholder="https://idp.example.com/sso"
|
|
81
|
+
class="mt-2 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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
82
|
+
/>
|
|
83
|
+
<div v-if="form.errors.sso_url" class="mt-1 text-sm text-rose-400">
|
|
84
|
+
{{ form.errors.sso_url }}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div>
|
|
88
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
89
|
+
>Certificate</label
|
|
90
|
+
>
|
|
91
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
92
|
+
X.509 certificate from your Identity Provider (PEM format)
|
|
93
|
+
</p>
|
|
94
|
+
<textarea
|
|
95
|
+
v-model="form.sso_certificate"
|
|
96
|
+
rows="6"
|
|
97
|
+
placeholder="-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"
|
|
98
|
+
class="mt-2 w-full rounded-lg border border-[var(--esc-panel-border-input)] bg-[var(--esc-panel-surface-alt)] px-3 py-2 font-mono text-xs text-[var(--esc-panel-text-secondary)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
99
|
+
></textarea>
|
|
100
|
+
<div v-if="form.errors.sso_certificate" class="mt-1 text-sm text-rose-400">
|
|
101
|
+
{{ form.errors.sso_certificate }}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<!-- JWT Settings -->
|
|
108
|
+
<div
|
|
109
|
+
v-if="form.sso_provider === 'jwt'"
|
|
110
|
+
class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6"
|
|
111
|
+
>
|
|
112
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">JWT Configuration</h3>
|
|
113
|
+
<div class="space-y-5">
|
|
114
|
+
<div>
|
|
115
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
116
|
+
>Shared Secret</label
|
|
117
|
+
>
|
|
118
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
119
|
+
Secret key used to sign and verify JWT tokens
|
|
120
|
+
</p>
|
|
121
|
+
<input
|
|
122
|
+
v-model="form.sso_jwt_secret"
|
|
123
|
+
type="password"
|
|
124
|
+
class="mt-2 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)]"
|
|
125
|
+
/>
|
|
126
|
+
<div v-if="form.errors.sso_jwt_secret" class="mt-1 text-sm text-rose-400">
|
|
127
|
+
{{ form.errors.sso_jwt_secret }}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
<div>
|
|
131
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
132
|
+
>Algorithm</label
|
|
133
|
+
>
|
|
134
|
+
<select
|
|
135
|
+
v-model="form.sso_jwt_algorithm"
|
|
136
|
+
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)]"
|
|
137
|
+
>
|
|
138
|
+
<option value="HS256">HS256</option>
|
|
139
|
+
<option value="HS384">HS384</option>
|
|
140
|
+
<option value="HS512">HS512</option>
|
|
141
|
+
<option value="RS256">RS256</option>
|
|
142
|
+
</select>
|
|
143
|
+
</div>
|
|
144
|
+
<div>
|
|
145
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]">SSO URL</label>
|
|
146
|
+
<p class="mt-0.5 text-xs text-[var(--esc-panel-text-muted)]">
|
|
147
|
+
Redirect URL where users authenticate and receive a JWT
|
|
148
|
+
</p>
|
|
149
|
+
<input
|
|
150
|
+
v-model="form.sso_url"
|
|
151
|
+
type="url"
|
|
152
|
+
placeholder="https://auth.example.com/jwt-sso"
|
|
153
|
+
class="mt-2 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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<!-- Attribute Mapping -->
|
|
160
|
+
<div
|
|
161
|
+
v-if="form.sso_provider !== 'none'"
|
|
162
|
+
class="rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-6"
|
|
163
|
+
>
|
|
164
|
+
<h3 class="mb-5 text-sm font-semibold text-[var(--esc-panel-text)]">Attribute Mapping</h3>
|
|
165
|
+
<p class="mb-4 text-xs text-[var(--esc-panel-text-muted)]">
|
|
166
|
+
Map the attribute names from your identity provider to Escalated user fields
|
|
167
|
+
</p>
|
|
168
|
+
<div class="space-y-5">
|
|
169
|
+
<div>
|
|
170
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
171
|
+
>Email Attribute</label
|
|
172
|
+
>
|
|
173
|
+
<input
|
|
174
|
+
v-model="form.sso_attr_email"
|
|
175
|
+
type="text"
|
|
176
|
+
placeholder="email"
|
|
177
|
+
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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
178
|
+
/>
|
|
179
|
+
</div>
|
|
180
|
+
<div>
|
|
181
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
182
|
+
>Name Attribute</label
|
|
183
|
+
>
|
|
184
|
+
<input
|
|
185
|
+
v-model="form.sso_attr_name"
|
|
186
|
+
type="text"
|
|
187
|
+
placeholder="name"
|
|
188
|
+
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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
189
|
+
/>
|
|
190
|
+
</div>
|
|
191
|
+
<div>
|
|
192
|
+
<label class="block text-sm font-medium text-[var(--esc-panel-text-secondary)]"
|
|
193
|
+
>Role Attribute</label
|
|
194
|
+
>
|
|
195
|
+
<input
|
|
196
|
+
v-model="form.sso_attr_role"
|
|
197
|
+
type="text"
|
|
198
|
+
placeholder="role"
|
|
199
|
+
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)] placeholder-[var(--esc-panel-text-muted)] focus:border-[var(--esc-panel-border-input)] focus:outline-none focus:ring-1 focus:ring-[var(--esc-panel-border-input)]"
|
|
200
|
+
/>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<!-- Submit -->
|
|
206
|
+
<div class="flex items-center justify-end gap-3">
|
|
207
|
+
<span v-if="form.recentlySuccessful" class="text-sm text-emerald-400">Saved.</span>
|
|
208
|
+
<button
|
|
209
|
+
type="submit"
|
|
210
|
+
:disabled="form.processing"
|
|
211
|
+
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"
|
|
212
|
+
>
|
|
213
|
+
{{ form.processing ? 'Saving...' : 'Save SSO Settings' }}
|
|
214
|
+
</button>
|
|
215
|
+
</div>
|
|
216
|
+
</form>
|
|
217
|
+
</EscalatedLayout>
|
|
218
|
+
</template>
|