@escalated-dev/escalated

中文文档
0.12.10发布于 2026/11/08MITES Module构建来源已验证近 30 天下载 5570

Vue 3 + Inertia.js UI components for Escalated — the embeddable support ticket system

原始使用文档
文档目录28 节
  1. Features
  2. Get Started
  3. Embedding the admin in your own admin panel (optional)
  4. Tailwind CSS
  5. Recommended: Tailwind in your existing build
  6. Using Escalated without a Tailwind build step
  7. Theming
  8. Layout Integration
  9. CSS Custom Properties
  10. Admin and Agent Panels
  11. Framework Examples
  12. What's in This Repo
  13. 📸 Screenshots
  14. Pages
  15. Shared Components
  16. Composables
  17. Plugin
  18. Plugin Development
  19. How the Frontend Plugin System Works
  20. How It Connects to the Backend
  21. Quick Example: Both Entry Points
  22. Installing Plugins
  23. Resources
  24. For Package Maintainers
  25. Contributing
  26. Backend settings capabilities
  27. Ecosystem
  28. License

العربية • Deutsch • English • Español • Français • Italiano • 日本語 • 한국어 • Nederlands • Polski • Português (BR) • Русский • Türkçe • 简体中文

Escalated

Testsnpm npm downloads Vue 3 License: MIT Views

Escalated — support tickets, built into your app

Escalated is an embeddable support ticket system with SLA tracking, escalation rules, agent workflows, and a customer portal. This repo contains all the shared frontend assets (Vue 3 + Inertia.js) used across every supported backend framework.

👉 Learn more, view demos, and compare Cloud vs Self-Hosted options at https://escalated.dev

You don't install this package directly. Start with the backend package for your framework — it handles everything including pulling in these frontend assets.

Escalated demo: on Pinecone, a made-up notes app, a customer files a ticket from the support widget themed in the app's green, then, in the dark agent panel, an agent opens it from the inbox, assigns it, replies and sets the status

Features

  • Ticket splitting — Split a reply into a new standalone ticket while preserving context
  • Ticket snooze — Snooze tickets with presets (1h, 4h, tomorrow, next week) and automatic wake
  • Saved views / custom queues — Save, name, and share filter presets as reusable ticket views
  • Embeddable support widget — Drop-in <script> widget with KB search, ticket form, and status check
  • Real-time updates — WebSocket support (Pusher/Reverb/Soketi) with automatic polling fallback
  • Knowledge base toggle — Enable or disable the public knowledge base from admin settings
  • CI: ESLint + Prettier — Automated code style enforcement on every pull request

Get Started

Pick your framework:

FrameworkRepoInstall
Laravelescalated-dev/escalated-laravelcomposer require escalated-dev/escalated-laravel
Railsescalated-dev/escalated-railsgem "escalated"
Djangoescalated-dev/escalated-djangopip install escalated-django
AdonisJSescalated-dev/escalated-adonisnpm install @escalated-dev/escalated-adonis
WordPressescalated-dev/escalated-wordpressDownload escalated.zip
Filamentescalated-dev/escalated-filamentcomposer require escalated-dev/escalated-filament
React Nativeescalated-dev/escalated-react-nativenpm install @escalated-dev/escalated-react-native
Flutterescalated-dev/escalated-flutterSee pubspec.yaml setup

Each backend repo has full setup instructions — install command, migrations, config, and frontend integration.

Embedding the admin in your own admin panel (optional)

Escalated comes with its own standalone admin panel, and that stays the default. If your app already has an admin panel, you can optionally show Escalated's admin screens inside it instead: under your sidebar and header, your URL prefix and your middleware, with Escalated's menu available to render in your own sidebar. Nothing changes unless you turn it on.

Three ways to do it, depending on your admin:

  • Vue + Inertia admin: Escalated's admin pages render chrome-free inside your layout (app.use(EscalatedPlugin, { layout, layoutScope: ['admin'] })), and <EscalatedNavigation /> lists the admin menu in your sidebar.
  • Server-rendered admin (Blade, ERB, Django templates, …): your admin template becomes the Inertia root view for the embedded pages.
  • Anything else: an allow-listed iframe with a small postMessage protocol for height, theme and navigation (@escalated-dev/escalated/embed).

Guides: frontend · Laravel · Rails · Django · AdonisJS · NestJS · Symfony · Phoenix · Go · .NET · Spring · WordPress. Laravel is the reference implementation; the other backends are adding it.

Tailwind CSS

Escalated components use Tailwind CSS utility classes (~hundreds of them across 140+ Vue files). Some Tailwind-compatible class processor must be available in the host app for the UI to render correctly — without one, every component renders as unstyled DOM with class names that don't resolve to any CSS.

If your host app already uses Tailwind via Vite / PostCSS / Tailwind CLI, just add this package to your content config so its classes aren't purged:

// tailwind.config.js
export default {
    content: [
        // ... your existing paths
        './node_modules/@escalated-dev/escalated/src/**/*.vue',
    ],
}

Tailwind 4+ users: content globs are auto-detected from imported modules — you usually don't need to add anything. Skip this step if you're on v4.

Using Escalated without a Tailwind build step

If you don't want a Tailwind toolchain in your build pipeline, you have a few options. Each has trade-offs — pick the one closest to your project's constraints:

OptionWhen to useHow
Tailwind Play CDNPrototyping, internal tools, demos. Not recommended for production (no purging, ~3 MB script tag).Add <script src="https://cdn.tailwindcss.com"></script> to the page that renders Escalated. The CDN script JIT-compiles classes at runtime.
Tailwind standalone CLIYou want a static stylesheet without npm/Vite.Download the standalone CLI binary and run tailwindcss -i input.css -o public/escalated.css --content './node_modules/@escalated-dev/escalated/src/**/*.vue' --minify. Link the output stylesheet from your page.
UnoCSS / Twind in attributify modeAlready using one of these atomic-CSS engines.Configure with the Tailwind preset (@unocss/preset-wind or @twind/preset-tailwind) and add the Escalated package path to the engine's scan config. Class semantics match.
Forking with hand-rolled CSSYou categorically cannot ship any Tailwind-compatible tooling and are willing to maintain a fork.Replace utility classes with scoped CSS per component. Substantial effort; not officially supported.

If none of these fit, please open a discussion so we can understand the constraint and consider a pre-compiled CSS distribution.

Whatever path you choose, also make sure the theme tokens (CSS custom properties) are applied — those control colour, spacing, and radius and are independent of Tailwind.

Theming

Escalated renders inside a standalone layout by default. To integrate it into your app's design system, use the EscalatedPlugin:

import { createApp } from 'vue'
import { EscalatedPlugin } from '@escalated-dev/escalated'
import AppLayout from '@/Layouts/AppLayout.vue'

const app = createApp(...)

app.use(EscalatedPlugin, {
    layout: AppLayout,
    theme: {
        primary: '#3b82f6',
        radius: '0.75rem',
    }
})

Layout Integration

Pass your app's layout component and Escalated's customer pages (the ticket portal and knowledge base) render inside it. The admin and agent panels keep their own navigation by default. The layout component must accept a #header slot and a default slot:

<!-- Your layout must support these slots -->
<template>
    <div>
        <nav>...</nav>
        <header><slot name="header" /></header>
        <main><slot /></main>
    </div>
</template>

When no layout is provided, Escalated uses its own built-in navigation bar.

To render the admin (and optionally the agent workspace) inside your layout as well, list those sections in layoutScope. Admin pages then render without Escalated's sidebar and top bar, with the page title in your #header slot:

app.use(EscalatedPlugin, {
    layout: AdminLayout,
    layoutScope: ['customer', 'admin'], // default: ['customer']
})

This is optional and only changes anything when you set it. See Embedding the admin in your own admin panel.

CSS Custom Properties

The theme option sets CSS custom properties you can reference in your own styles:

PropertyDefaultDescription
--esc-primary#4f46e5Primary action color
--esc-primary-hoverauto-darkenedPrimary hover color
--esc-radius0.5remBorder radius for inputs and buttons
--esc-radius-lgauto-scaledBorder radius for cards and panels
--esc-font-familyinheritFont family override

Admin and Agent Panels

theme.panel colours the admin and agent panels: navigation, header, logo tile, links and surfaces, in dark or light mode. Both panels collapse their navigation behind a menu button below 1024px. See docs/theming.md for every token.

Framework Examples

Laravel (Inertia + Vue 3):

import { EscalatedPlugin } from '@escalated-dev/escalated'
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue'

app.use(EscalatedPlugin, { layout: AuthenticatedLayout })

Rails (Inertia + Vue 3):

import { EscalatedPlugin } from '@escalated-dev/escalated'
import AppLayout from '@/layouts/AppLayout.vue'

app.use(EscalatedPlugin, { layout: AppLayout })

Django (Inertia + Vue 3):

import { EscalatedPlugin } from '@escalated-dev/escalated'
import BaseLayout from '@/layouts/BaseLayout.vue'

app.use(EscalatedPlugin, { layout: BaseLayout })

AdonisJS (Inertia + Vue 3):

import { EscalatedPlugin } from '@escalated-dev/escalated'
import AppLayout from '@/layouts/AppLayout.vue'

app.use(EscalatedPlugin, { layout: AppLayout })

What's in This Repo

All the Vue 3 + Inertia.js components that power the Escalated UI. These are identical across Laravel, Rails, Django, and AdonisJS — the backend framework renders them via Inertia.

📸 Screenshots

Screenshots are auto-generated from Storybook via the component-screenshots workflow.

Admin Panel (Dark)
Escalated Admin Panel — dark mode with sidebar navigation, KPI cards, stats, and ticket list

Admin Panel (Light)
Escalated Admin Panel — light mode with sidebar navigation, KPI cards, stats, and ticket list

Agent Inbox
Escalated agent inbox in dark mode: queue rail with saved views and counts, stat strip, and the ticket list beside an empty detail pane

Agent Panel (Light)
Escalated agent panel in light mode: a ticket open beside the inbox list

Ticket View
Escalated ticket view in dark mode: inbox list beside the ticket with status, priority, tags, conversation, and the reply composer

Pages

Customer Portal — Self-service ticket management

  • pages/Customer/Index.vue — Ticket list with status filters and search
  • pages/Customer/Create.vue — New ticket form with file attachments
  • pages/Customer/Show.vue — Ticket detail with reply thread

Agent Dashboard — Ticket queue and workflows

  • pages/Agent/Dashboard.vue — Stats overview and recent tickets
  • pages/Agent/TicketIndex.vue — Filterable ticket queue
  • pages/Agent/TicketShow.vue — Full ticket view with sidebar, internal notes, canned responses

Admin Panel — System configuration

  • pages/Admin/Reports.vue — Analytics dashboard
  • pages/Admin/Departments/ — Department CRUD
  • pages/Admin/SlaPolicies/ — SLA policy management
  • pages/Admin/EscalationRules/ — Escalation rule builder
  • pages/Admin/Tags/ — Tag management
  • pages/Admin/CannedResponses/ — Canned response templates

Shared Components

Reusable building blocks used across the pages above.

ComponentDescription
StatusBadgeColored badge for ticket status
PriorityBadgeColored badge for ticket priority
TicketListPaginated ticket table
ReplyThreadChronological reply display
ReplyComposerReply/note editor with file upload and canned response insertion
ActivityTimelineAudit log of ticket events
SlaTimerSLA countdown with breach/warning states
TicketFiltersStatus, priority, agent, department filter bar
TicketSidebarTicket detail sidebar (status, SLA, tags, activity)
AssigneeSelectAgent assignment dropdown
TagSelectMulti-select tag picker
FileDropzoneDrag-and-drop file upload
AttachmentListFile attachment display with download links
StatsCardMetric card with label, value, and trend
EscalatedLayoutTop-level layout with navigation (supports host layout injection)
BulkActionBarToolbar for batch operations on selected tickets
QuickFiltersOne-click filter chips (My Tickets, Unassigned, Urgent, SLA Breaching)
MacroDropdownDropdown to apply multi-step macros to a ticket
FollowButtonToggle button to follow/unfollow a ticket
SatisfactionRating1-5 star CSAT rating input with optional comment
KeyboardShortcutHelpModal overlay showing all available keyboard shortcuts
PinnedNotesDisplay pinned internal notes at the top of the thread
PresenceIndicatorReal-time indicator showing who is viewing a ticket

Composables

ComposableDescription
useKeyboardShortcutsRegisters and manages keyboard shortcuts for ticket actions

Plugin

ExportDescription
EscalatedPluginVue plugin for layout injection and CSS theming

Plugin Development

Escalated supports framework-agnostic plugins built with the Plugin SDK. Plugins are written once in TypeScript and work across all Escalated backends.

How the Frontend Plugin System Works

The frontend uses defineEscalatedPlugin() to register Vue components — custom admin pages, ticket sidebar widgets, or dashboard panels — that are mounted automatically when the plugin is active.

import { defineEscalatedPlugin } from '@escalated-dev/escalated'
import MySettingsPage from './MySettingsPage.vue'

export default defineEscalatedPlugin({
  name: 'my-plugin',
  pages: {
    'admin/my-plugin/settings': MySettingsPage,
  },
})

How It Connects to the Backend

The backend uses definePlugin() from the Plugin SDK to handle TypeScript business logic — subscribing to ticket lifecycle hooks, exposing API endpoints, and persisting data. The frontend and backend entries work together as a single npm package.

// backend entry (index.ts)
import { definePlugin } from '@escalated-dev/plugin-sdk'

export default definePlugin({
  name: 'my-plugin',
  version: '1.0.0',
  actions: {
    'ticket.created': async (event, ctx) => {
      ctx.log.info('New ticket!', event)
    },
  },
})

Quick Example: Both Entry Points

A published plugin package typically exports both:

my-plugin/
  index.ts          ← backend: definePlugin() for TypeScript logic
  frontend.ts       ← frontend: defineEscalatedPlugin() for Vue components

The backend framework (Laravel, Rails, Django, AdonisJS) loads index.ts via the Plugin Runtime. The Vue app imports frontend.ts and registers it with app.use().

Installing Plugins

npm install @escalated-dev/plugin-slack
npm install @escalated-dev/plugin-jira

Resources

For Package Maintainers

Verified guest access is enabled by backend capabilities. Escalated/Guest/Create accepts optional verification_url and lookup_url props. With these URLs, the form requests an email code before posting a ticket; a separate form verifies email to find existing tickets by tracking/ticket reference and renew private links. Guest/Show displays ticket.guest_access_expires_at when supplied.

The built-in widget enables the same flow only when /config returns guest_verification_required: true. The backend must provide POST /verification with email and purpose (ticket, chat, lookup), returning verification_id; creation accepts verification_id and the eight-digit verification_code. POST /lookup returns { data: [{ reference, subject, guest_access_token, expires_at }] }; subsequent widget status reads send the token as a Bearer header. Chat creation returns an opaque id and polling uses /chat/{id}/messages. Proofs and private results are cleared on destination or identity changes. Tokens remain in component memory. CSRF headers are sent only to the page's own origin.

Backends that omit these capabilities retain their existing form contract. Hosts must ship these forms before requiring verification in their backend. This does not implement verification in the other backend packages or release the separate web-widget plugin.

The widget can also be embedded on other sites, as a launcher or an on-page support form, with host parameters (department, prefill, metadata) and a JavaScript API. Backends opt in with an origin allow list, CORS and a CSRF exemption for those origins. See Embedding the widget.

Backends with account isolation can share escalated.broadcasting.channel_prefix through Inertia, for example escalated.tenants.<opaque-account-namespace>. Ticket, agent, chat and presence subscriptions use this prefix and rejoin when it changes. Omitting it preserves the existing escalated channels. Standalone PresenceIndicator consumers can pass its channelPrefix prop; useRealtime and useChat accept channelPrefix as a string, ref or getter. Raw useRealtime().listen(channel, event, callback) still treats the channel literally.

The backend must authorize the current account and each private/presence join. Channel names alone are not authorization. Ticket presence should expose only agent identity/display names, with requester access limited to private ticket updates. Deploy a frontend version containing this support before enabling a backend's account-scoped channels.

If you're building a new backend integration, this package is available on npm:

npm install @escalated-dev/escalated
// Import the plugin
import { EscalatedPlugin } from '@escalated-dev/escalated'

// Import individual components
import { StatusBadge, SlaTimer } from '@escalated-dev/escalated'

// Or reference pages directly for Inertia resolution
import CustomerIndex from '@escalated-dev/escalated/pages/Customer/Index.vue'

Peer dependencies: vue ^3.3.0, @inertiajs/vue3 ^1.0.0 || ^2.0.0 || ^3.0.0

The API token and two-factor pages accept flash data from page.props.flash (legacy shared props) and page.flash (Inertia 3). Top-level values take precedence, including explicit null values that clear legacy data. Inertia 3 backends should send one-time tokens, setup URIs, and recovery codes through top-level flash so they are excluded from the adapter's browser history state. Hosts must deploy a frontend release containing this support before changing their backend's flash protocol.

Contributing

The development tools require Node 22.22.2+ on the 22.x line, 24.15.0+ on the 24.x line, or 26+. Use nvm use to select the version in .nvmrc. These requirements apply when working on this repository; the published Vue and Inertia peer dependencies are listed above.

npm ci
npm test
npm run lint
npm run format:check
npm run pages:check
npm run build-storybook
npm audit

Commit package-lock.json with dependency updates. CI installs that exact graph with npm ci, checks dependency engines and peer requirements, and runs the test suite on Node 22.22.2, 24.15.0, and 26. Storybook's production build and the full dependency audit also run before merging.

The browser contract packs the current source, installs that tarball in isolated consumers with real Inertia 1, 2, and 3 adapters, audits each consumer, and tests token and two-factor flows on desktop and mobile Chromium. It uses a local HTTP server and synthetic credentials. The clipboard boundary is simulated so the test does not change your clipboard.

npx --no-install playwright install chromium
npm run test:inertia
# Or select a single adapter major:
npm run test:inertia -- 3

Reports and screenshots are written to test-results/inertia-flash/. CI runs each adapter separately and uploads that evidence on success or failure.

Backend settings capabilities

The Escalated/Admin/Settings page accepts optional supported_settings and update_url props. Pass an array of editable setting names to show and submit only those fields, and a URL accepting a flat POST payload. An empty array exposes no editable settings. Omitting these props preserves the full settings form and its Laravel named route. Backends must validate their own setting allowlist; hiding a control is not authorization.

For example, a backend implementing only knowledge-base and branding preferences can expose knowledge_base_enabled, knowledge_base_public, knowledge_base_feedback_enabled, and show_powered_by. Supply typed values in the settings prop. Changing the settings/account props clears stale form values and pending requests, including previously entered credentials.

Ecosystem

This is the shared frontend for the Escalated support ticket system. Host framework packages and client SDKs available across the ecosystem:

License

MIT - Copyright (c) Escalated.dev. See LICENSE.

版本与发布记录

@escalated-dev/escalated 共发布 30 个版本,首次发布于 2026/02/09;过去 12 个月发布了 30 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.12.10latest2026/11/086 天前
0.12.92026/11/067 天前
0.12.82026/11/058 天前
0.12.72026/10/3014 天前
0.12.62026/10/2321 天前
0.12.52026/10/2322 天前

关于 @escalated-dev/escalated 的常见问题

@escalated-dev/escalated 是什么?

Vue 3 + Inertia.js UI components for Escalated — the embeddable support ticket system

如何安装 @escalated-dev/escalated?

在项目目录运行 npm install @escalated-dev/escalated,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:vue(^3.3.0)、@inertiajs/vue3(^1.0.0 || ^2.0.0 || ^3.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@escalated-dev/escalated 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/escalated-dev__escalated 是否存在。

@escalated-dev/escalated 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@escalated-dev/escalated 可以商用吗?

@escalated-dev/escalated 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@escalated-dev/escalated 的下载量有多少?

根据 npm 官方下载统计,@escalated-dev/escalated 在 2026/10/14 – 2026/11/12 这 30 天内被下载 5,570 次,日均约 186 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@escalated-dev/escalated 还在维护吗?

最新版本 0.12.10 发布于 2026/11/08(6 天前);至今共发布 30 个版本,其中过去 12 个月发布了 30 个;首次发布于 2026/02/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。