Repository navigation
v0.12.8
The agent panel, redesigned. Pages under /agent now share a rail and top bar with a command palette (Cmd/Ctrl K), a dense inbox beside a detail pane, and a conversation-first ticket workspace with a customer and details panel and a lighter composer. Agents can resolve, reopen, snooze, reassign and move tickets without leaving the conversation, see toasts and loading states, set their status, and drive it all from the keyboard (j/k, g i, r, n, e, z, ...). Contrast and focus hold WCAG AA in both themes.
Every new prop (inbox, queue, agents, ticket.requester_tickets) is optional: a backend that sends none of them keeps working lists and tickets. The Laravel, NestJS, Rails, Django, Adonis, Symfony, Phoenix, Go, Spring and .NET backends send them from their 2026-11-04 releases. Read Upgrading below before deploying, and see docs/agent-panel.md for the prop shapes and routes.
Upgrading
- The agent panel is redesigned (#227 to #237). Pages under
/agent
use a rail and top bar instead of the old top navigation,
Agent/TicketIndexis a list beside a detail pane, andAgent/TicketShow
is a conversation-first workspace with a customer and details panel and a
new composer. Page names and the props they already read are unchanged,
and the admin layout is untouched. Hosts that restyle the agent pages with
their own CSS should check them; the panel tokens (theme.panel) still
apply. - New optional agent page props, all listed in
pages.jsonand
documented indocs/agent-panel.md:inboxandqueueon
Agent/TicketIndexandAgent/TicketShow(rail counts, saved views, the
queue title and stat strip),agents([{ id, name }], for reassigning)
onAgent/TicketShow, andticket.requester_tickets(the customer's
other conversations). A backend that sends none of them gets the same
lists and tickets without counts, views, the reassign list or previous
conversations. The escalated backends send them from their releases of
2026-11-04. - The customer panel reads only
requester_tickets. It used to list
related_tickets(linked tickets on escalated-laravel) as the customer's
recent tickets; linked tickets now show under Related only. - Snooze, unsnooze and agent status from the agent panel call
escalated.agent.tickets.snooze/escalated.agent.tickets.unsnooze
(the admin routes for admins) and, when the host has it,
escalated.admin.chat.status. A backend without these routes keeps the
rest of the panel; the actions fail with an error toast. TicketFiltersgainsshowSearchandshowSaveView(bothtrueby
default) andKeyboardShortcutHelpgainswithListandagent; existing
uses render as before.
Fixed
- Customer history. The customer tab listed
related_tickets(a
ticket's linked tickets on escalated-laravel) as the customer's recent
tickets. The panel reads onlyrequester_tickets. - The composer's hidden file input has an accessible name.
- Light panel contrast. The light theme's tertiary text (
#646b78), urgent
priority (#b31b1b), SLA breach (#b91c1c) and SLA warning (#a34807)
are a shade darker so they hold WCAG AA (4.5:1) on hovered, active and
selected rows and on the urgent tint. Hosts that set these tokens keep
their own values. - Agent inbox rows. Hovering a row kept the initials circle but showed the
browser's native checkbox (a black square in dark mode); on the ticket page,
where rows are not selectable, the avatar vanished. Rows now keep the circle
and show a token-styled checkbox only where rows can be selected. The first
j/klands on the current row instead of skipping it, and each age shows
the full date and time on hover. - Queues while searching. Searching, filtering, clicking a stat tile or
paging inside a queue keeps its title and its highlight in the rail. - Agent panel focus and contrast. Placeholders use the tertiary token
(AA in both modes); the composer shows focus on its border; every control on
the agent pages has the accent focus ring. - Popovers. The tag picker is a filterable menu with tag colours that
closes on Escape or a click outside. The filter popover drops its second
search box and the "Save as View" button nothing listened to, and closes
the same way.TicketFiltersgainsshowSearchandshowSaveViewprops,
both defaulting totrue. - Keyboard help.
KeyboardShortcutHelpis translated, uses the panel
tokens without a blurred backdrop, takes focus and closes on Escape, and
lists the keys each page binds (newwithListandagentprops; admin
pages no longer list the agent-onlygsequences). - Layout. The list column is 340px from lg and 420px from xl, so the
ticket keeps a usable width at 1024px. On a phone the section tabs stay on
one line and the ticket header scrolls away with the thread while the
composer stays docked.
Added
- Ticket actions in the agent panel: Resolve and Reopen buttons; a
Snooze menu (1 hour, 4 hours, tomorrow, next Monday, or a date and time,
and Unsnooze) usingescalated.agent.tickets.snooze/unsnooze, or the
admin routes for admins; reassigning to any agent in the new optional
agentsprop onEscalated/Agent/TicketShow([{ id, name }], declared in
pages.json); changing the department; previous and next ticket from the
list (Shift K/Shift J); Ticket history in the overflow menu;zopens
Snooze. Tag chips carry a tag icon in the tag's colour. PanelMenutakes itemicons, an optionalfilterPlaceholder(a filter
box beside the menu) and a default slot for a footer.- Rail links match their counts. When the backend sends
inbox.counts
(open tickets), Inbox, Unassigned and All tickets open their lists with
open=1, and views open asview=<id>(plusopen=1unless the view names
a status). The list says "open" in its subline and offers "Include resolved"
/ "Open only"; "Clear filters" returns to the queue as the rail opens it. - Feedback. Toasts for the backend flash and for ticket actions without
one, inline send errors and a Sending state in the composer, a skeleton
while the next ticket loads, a dimmed busy list while a search loads, a
filtered-empty state with Clear filters, an unread dot, and a check on
Copy link. - Agent status. The rail footer and a top-bar avatar show the agent's
status (Online, Away, Offline) with a dot and a menu, whether or not live
chat is on. It reads the sharedescalated.agent_status(or
escalated.chat_status), then the browser's last choice, and posts changes
toescalated.admin.chat.statuswhen the host has that route. See
docs/agent-panel.md. - Semantic panel tokens, set by
theme.panelin dark and light and each
overridable by its camelCase name:--esc-panel-note-{bg,border,text},
--esc-panel-selected-{bg,border}(from the accent),
--esc-panel-primary-{bg,text}(accent with a readable text colour),
--esc-priority-{low,medium,high,urgent}and--esc-sla-{ok,warn,breach}. useKeyboardShortcutsaccepts two-key sequences such as'g i'.
Changed
- A lighter, faster composer. Idle and empty it is 75px instead of 159px
(one line under the tabs); focus, a draft, files or an open menu open it
up, and the text box grows with the text up to 40% of the window. Public
replies say who they go to; internal notes turn the whole composer amber.
Ctrl/Cmd Shift Entersends and resolves, and both shortcuts are shown on
the Send button and its menu. Files can be dropped or pasted, and a draft
can be discarded after a confirmation. At 1280×720 the conversation gets
483px of height instead of 335px. - Agent ticket workspace. The ticket header is 103px instead of 163px
(283px with a long subject): the reference shares a row with the actions,
the subject gets the full width (two lines at most), and status, priority,
assignee, department and tags sit on one row of quiet controls. The
conversation is the only main view and scrolls on its own under a fixed
header, with the composer below it; messages are no longer cards. Customer
messages, agent replies (accent rule), internal notes (amber, lock) and
system events (fromticket.activities) are told apart, text keeps a
760px measure, and attachments are compact file chips. - The Details, Customer and Related tabs became a customer and details
panel beside the conversation (from a 900px pane, so 1920px screens show
it by default) or over it on demand (i, or the header button): customer,
organization when sent, previous conversations, details and filled-in
custom fields, related tickets, the knowledge base link and the ticket
history, in collapsible sections. Plugin slotsticket.show.sidebarand
ticket.show.context-panelrender inside it. - Denser agent inbox. Rows are 69px instead of 87px and name the
requester on the first line beside the age; the reference moves next to the
latest message preview. The four KPI tiles become a single row of filter
toggles with icons (fire for Urgent, clock for SLA at risk, check for
Resolved today), and the header is one title line with a short subline and
a labelled New ticket icon button. At 1280×720 the list shows 7 rows instead
of 5 (10 instead of 7 at 1440×900). - The agent rail is a drawer below 1280px (was 1024px), so on a tablet
the list and the ticket get the width. The list column is 360px up to
1536px, then 400px. Rail items are 28px tall with tighter section spacing. - Section tabs in the agent top bar have icons (Tickets, Dashboard,
Knowledge base), hidden on phones where the tabs scroll. - Agent ticket view.
Agent/TicketShowkeeps the inbox list beside the
ticket on wide screens and shows the ticket in a newTicketDetailPane: the
reference with a copy-link button, the subject, an overflow menu (macros,
custom actions, merge, snooze, copy link) and a follow star; status and
priority menus, tag chips with remove and add (the tags endpoint), and the
assignee with a plain "Assign to me". Tabs: Conversation (oldest first,
pinned notes on top, internal notes tinted with a lock, attachments as file
cards), Details (a dense definition list of today's sidebar content),
Customer (profile, recent tickets, the context panel data and its plugin
slot) and Related (linked tickets, knowledge base, activity). The new
Composersits at the bottom: Reply / Internal note, attach, canned
responses, emoji, bold, italic, link and list, a split Send with "Send and
set waiting on customer" and "Send and resolve", Ctrl/Cmd Enter, and drafts
saved per ticket and mode in localStorage. Live chats show the chat thread,
chat composer and chat action bar instead; light agents get internal notes
only. Shortcuts:r,n,s,p,f,a(assign to me),e
(resolve), and the page's actions in the command palette. The optional
inboxandqueueprops are accepted here too.ReplyComposerand
TicketSidebarare unchanged and still exported. - Agent inbox split view.
Agent/TicketIndexis a list column (queue
title and count, stat strip, search, a filter popover holding the existing
TicketFilters, and dense rows with initials, reference, subject, preview,
age, priority and SLA markers) beside a detail pane that says "Select a
ticket" until one is opened.j/kmove,xselects (the bulk bar is
unchanged),Enteropens,/searches; arrow keys move between rows.
Quick filters move to the queues in the rail. New optional propsinbox
andqueueare documented indocs/agent-panel.md; a backend that sends
neither gets the same list without counts, views or stats. - Agent panel shell. Pages under
/agentnow use a rail and top bar in the
same family as the admin panel instead of the old top navigation. The rail
lists the workspace queues (Inbox, Unassigned, All tickets), saved views and
live chats; the top bar has the section tabs (Tickets, Dashboard, Knowledge
base when it is enabled) and a search button that opens a command palette
(Cmd K / Ctrl K: open a ticket by reference, search tickets, run actions).
g i,g uandg ago to the three queues. Counts and views appear when
the backend sends the optionalinboxpage prop (documented with the inbox
redesign); without it the rail shows the queues without numbers. The admin
layout is unchanged.EscalatedLayouttakes a new optionalfullBleedprop
for pages that lay out their own panes. - README. The demo GIF opens on Pinecone, a made-up notes app, and
then shows the redesigned agent panel (#230, #233); the social image shows
the new agent inbox (#234). - The widget bundle (
dist/widget/escalated-widget.js) is rebuilt with
Vue 3.5.44. The widget's source did not change.
Security
- Dev dependencies only; nothing here ships in the package (its one runtime
dependency is@escalated-dev/locale).npm audit fixmovesfollow-redirectsto 1.16.2 (GHSA-mrwp-f3q8-3g9p)
andjoito 18.3.1 (GHSA-4528-x5fx-h6hg).eslint10.14,eslint-plugin-vue10.12,eslint-plugin-storybookand
Storybook 10.6.5,@vue/test-utils2.5.1: the latest releases of the
packages that pull inminimatchandglob.- Even those latest releases still ask for
minimatch^10 andglob^13,
so npmoverridespinminimatch^11.0.3 (GHSA-g3hv-75wg-m249) and
glob^14.0.3 (GHSA-3g3m-2fjr-6pw4). Their consumers (eslint,
@eslint/config-array,@typescript-eslint/typescript-estree,
editorconfig,js-beautify) only useMinimatch#match,minimatch(),
escape(),globSync()andhasMagic(), which the new majors keep.
Drop the overrides once those packages depend on the patched majors.