Frontend Guided Tour
Overview
The guided tour introduces key workflows (projects, import, sprint board, ticket details) and is designed to work reliably across route changes.
Implementation lives in frontend/jenga/src/provider/GuideProvider.tsx using Shepherd.js.
Library: Shepherd.js
Shepherd.js is a library for guided tours. It models a tour as a sequence of steps that can be attached to DOM elements, with built-in navigation controls and lifecycle hooks.
In this frontend, Shepherd.js is used to: - define route-aware tours (steps can trigger navigation before attaching) - attach steps to stable UI anchors (via element selectors) - synchronize step rendering with asynchronous UI updates (waiting for DOM targets)
Runtime Design
GuideProvider builds a single tour instance with translated default button labels.
Key helpers:
- waitForElement(selector, timeoutMs)
- goToPathAndWaitFor(path, selector)
- ensureSidebarVisible()
These helpers are the core stability layer for asynchronous UI and routing.
Step Orchestration Strategy
Each step may define beforeShowPromise.
Typical sequence: 1. navigate to target route 2. ensure required shell state (e.g. sidebar open) 3. wait for anchor element 4. render step
Without this, tour steps race against rendering and fail intermittently.
Anchor Contract
Guide steps depend on stable DOM ids:
guide-nav-toggleguide-sidebarguide-projectsguide-file-importguide-ticket-filterguide-kanbanguide-backlogguide-ticket-details
Anchor consistency: - if an anchor id changes, the guide configuration is updated in the same change
i18n Dependency
Guide labels and step content use i18n keys.
Implication:
- GuideProvider depends on I18nProvider being mounted first
- missing translation keys degrade UX immediately (button labels/step texts)
Failure Modes and Current Mitigations
Missing element
Symptom: - step throws "Guide target not found"
Mitigation in current implementation: - ensure route and conditional rendering create target element - keep id anchors in stable, always-mounted wrappers where possible
LayoutProvider dependency:
- Some tour targets exist only when a specific layout branch is rendered. In the current UI, sidebar-bound targets (e.g. guide-sidebar) depend on LayoutProvider.sidebarOpen.
- The tour therefore depends on LayoutProvider being mounted and its state being controllable from the tour logic, otherwise selectors can be correct but still resolve to no DOM element.
Route/render timing mismatch
Symptom: - a step appears before the target route content is present
Mitigation in current implementation:
- route-dependent steps use a navigation + wait strategy (goToPathAndWaitFor(...))
Evolution Characteristics
When new guided steps are added, the implementation typically evolves as follows:
1. define stable anchor id in UI component
2. add translated strings in both locales
3. add step with explicit preconditions (beforeShowPromise)
4. validate complete tour in both languages