@quanticjs/journey-ui
v8.0.0
Published
Journey observability UI — dashboard, timeline, and my-items widget for business process tracking
Readme
@quanticjs/journey-ui
Journey observability UI — dashboard, timeline, and my-items widget for business process tracking.
Pages are permission-gated via PermissionGuard from @quanticjs/react-core and emit structured access events for audit trails.
Requires @quanticjs/tailwind-preset >= 8 in the consuming app's CSS build — components render with v8 token utilities (shadow-* tiers, z-(--z-*), animate-*) that compile to nothing on older presets. See docs/MIGRATION-8.md.
Setup
import { JourneyProvider } from '@quanticjs/journey-ui';
<JourneyProvider
config={{
onAccessEvent: (event) => {
// the framework does no batching or transport — POST to your audit backend
client.post('/audit/access-events', event);
},
}}
>
<Routes>…</Routes>
</JourneyProvider>Config reference (JourneyConfig)
| Option | Default | Description |
|---|---|---|
| apiBasePath | /journeys | API base path for journey endpoints |
| routeBasePath | /journeys | Route base path for navigation links |
| permissions.dashboard | journeys:read | Gates JourneyDashboardPage |
| permissions.detail | journeys:read | Gates JourneyDetailPage |
| permissions.stats | journeys:read | Gates JourneyStatsPage |
| onAccessEvent | — | Receives an AccessEvent whenever a page or detail view renders with access granted |
| accessDeniedFallback | styled "Access denied" panel | Rendered inline on denial — pages are embedded, so denial never redirects |
Required permissions per page
| Page | Permission | Access events |
|---|---|---|
| JourneyDashboardPage | permissions.dashboard | journey_dashboard_viewed |
| JourneyDetailPage | permissions.detail | journey_detail_viewed (resourceId = journeyId) |
| JourneyStatsPage | permissions.stats | journey_stats_viewed |
| JourneyMyItems | — (never guarded) | — |
JourneyMyItems is inherently scoped to the current user, so it is intentionally not guarded and emits no events.
Access events
interface AccessEvent {
type: JourneyAccessEventType; // e.g. 'journey_dashboard_viewed'
resourceId?: string; // journeyId for detail views
path: string; // window.location.pathname at emission
timestamp: string; // ISO 8601
}Events fire once per mount (StrictMode-safe) and only after access is granted — a denied or still-loading session emits nothing. If your onAccessEvent callback throws, the error is swallowed: viewing must never break.
Disabling a guard (discouraged)
Setting a permission to null renders that page unguarded:
<JourneyProvider config={{ permissions: { dashboard: null } }}>This is an explicit opt-out for apps that gate access at a higher level (e.g. routing). Prefer granting the proper permission.
Role-based gating instead
If you gate by role rather than permission, opt the page out with null and wrap it yourself:
<PermissionGuard role="journey-viewer" fallback={<Denied />}>
<JourneyDashboardPage />
</PermissionGuard>Internationalization
Every rendered string lives in a labels interface with an English default. Each page/component takes a labels prop, and all of them resolve app-wide from the TranslationProvider in @quanticjs/react-ui — this package registers the journeyUi namespace (JourneyUiTranslations). Precedence per key: explicit labels prop > provider catalog > English default.
import { TranslationProvider } from '@quanticjs/react-ui';
<TranslationProvider
locale="de-DE"
translations={{
journeyUi: {
dashboard: { title: 'Prozess-Journeys', total: (t) => `${t} Journeys insgesamt` },
myItems: { empty: 'Keine Aufgaben für dich' },
status: { active: 'aktiv', completed: 'abgeschlossen' },
},
}}
>
<JourneyDashboardPage />
</TranslationProvider>Namespaces: dashboard (JourneyDashboardLabels), detail (JourneyDetailLabels), stats (JourneyStatsLabels, incl. the duration(ms) function label that keeps the page's compact 45m/2h/3d format), timeline (JourneyTimelineLabels), myItems (JourneyMyItemsLabels), status (JourneyStatusLabels — display text per status; unknown statuses render raw).
The provider's locale drives formatDateTime/formatDuration/formatRelativeTime output on all pages reactively.
Error states
Failed queries render the shared QueryErrorPanel from @quanticjs/react-ui: 403 shows an access message (no retry), 404 shows not-found, network/5xx errors show "Try again". 401 is handled by the @quanticjs/react-core client redirect before it reaches the UI.
Notes
- Permission revoked mid-session: the session is cached with
staleTime: Infinity(ADR-004), so revocation takes effect at next login/refresh, not mid-session.
RTL & reduced motion
The journey timeline (rail, dot, event indent) uses logical properties (ps-6, start-0), so pages mirror under dir="rtl" with no configuration. Date/number output is Intl-based — pass an Arabic locale (e.g. ar-AE) through the locale provider for correct CLDR formatting. Skeleton loading states respect prefers-reduced-motion (via @quanticjs/react-ui primitives and the preset's global media block).
