Skip to content

v0.12.8

Choose a tag to compare

@mpge mpge released this 05 Nov 02:06
9caafff

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/TicketIndex is a list beside a detail pane, and Agent/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.json and
    documented in docs/agent-panel.md: inbox and queue on
    Agent/TicketIndex and Agent/TicketShow (rail counts, saved views, the
    queue title and stat strip), agents ([{ id, name }], for reassigning)
    on Agent/TicketShow, and ticket.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.
  • TicketFilters gains showSearch and showSaveView (both true by
    default) and KeyboardShortcutHelp gains withList and agent; 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 only requester_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/k lands 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. TicketFilters gains showSearch and showSaveView props,
    both defaulting to true.
  • Keyboard help. KeyboardShortcutHelp is translated, uses the panel
    tokens without a blurred backdrop, takes focus and closes on Escape, and
    lists the keys each page binds (new withList and agent props; admin
    pages no longer list the agent-only g sequences).
  • 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) using escalated.agent.tickets.snooze/unsnooze, or the
    admin routes for admins; reassigning to any agent in the new optional
    agents prop on Escalated/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; z opens
    Snooze. Tag chips carry a tag icon in the tag's colour.
  • PanelMenu takes item icons, an optional filterPlaceholder (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 as view=<id> (plus open=1 unless 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 shared escalated.agent_status (or
    escalated.chat_status), then the browser's last choice, and posts changes
    to escalated.admin.chat.status when the host has that route. See
    docs/agent-panel.md.
  • Semantic panel tokens, set by theme.panel in 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}.
  • useKeyboardShortcuts accepts 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 Enter sends 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 (from ticket.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 slots ticket.show.sidebar and
    ticket.show.context-panel render 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/TicketShow keeps the inbox list beside the
    ticket on wide screens and shows the ticket in a new TicketDetailPane: 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
    Composer sits 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
    inbox and queue props are accepted here too. ReplyComposer and
    TicketSidebar are unchanged and still exported.
  • Agent inbox split view. Agent/TicketIndex is 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/k move, x selects (the bulk bar is
    unchanged), Enter opens, / searches; arrow keys move between rows.
    Quick filters move to the queues in the rail. New optional props inbox
    and queue are documented in docs/agent-panel.md; a backend that sends
    neither gets the same list without counts, views or stats.
  • Agent panel shell. Pages under /agent now 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 u and g a go to the three queues. Counts and views appear when
    the backend sends the optional inbox page prop (documented with the inbox
    redesign); without it the rail shows the queues without numbers. The admin
    layout is unchanged. EscalatedLayout takes a new optional fullBleed prop
    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 fix moves follow-redirects to 1.16.2 (GHSA-mrwp-f3q8-3g9p)
      and joi to 18.3.1 (GHSA-4528-x5fx-h6hg).
    • eslint 10.14, eslint-plugin-vue 10.12, eslint-plugin-storybook and
      Storybook 10.6.5, @vue/test-utils 2.5.1: the latest releases of the
      packages that pull in minimatch and glob.
    • Even those latest releases still ask for minimatch ^10 and glob ^13,
      so npm overrides pin minimatch ^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 use Minimatch#match, minimatch(),
      escape(), globSync() and hasMagic(), which the new majors keep.
      Drop the overrides once those packages depend on the patched majors.