Skip to content

feat: Learning Hub Tour Framework#2299

Draft
camielvs wants to merge 1 commit into
05-20-feat_learning_hub_guided_toursfrom
05-20-feat_learning_hub_tour_framework_and_first_tour
Draft

feat: Learning Hub Tour Framework#2299
camielvs wants to merge 1 commit into
05-20-feat_learning_hub_guided_toursfrom
05-20-feat_learning_hub_tour_framework_and_first_tour

Conversation

@camielvs
Copy link
Copy Markdown
Collaborator

@camielvs camielvs commented May 21, 2026

Description

Foundational groundwork for guided tours in the UI, built on Reactour. Tours live at their own URL (/tour/$tourId) so they're refreshable, shareable, and own their lifecycle cleanly.

Supports forward/back controls, interactive activities ("click here", "drag this"), dynamic highlighting of relevant UI elements, and inline-markdown step copy (**bold**, _italic_, `code`, paragraph breaks). Interactive steps include fallback copy when the prompted state is already satisfied.

Tours run inside a fresh ephemeral pipeline (__tour__<slug>). When the user leaves the tour route the pipeline is deleted — tours have no save state, every visit starts fresh. "Save as new pipeline" in the editor's tour-mode action bar promotes the temp pipeline into a regular one.

Architecture

Route (/tour/$tourId, src/routes/Dashboard/Learn/Tour.tsx)

  • Owns the tour pipeline lifecycle: creates a fresh __tour__<slug> on mount, deletes it on unmount unless promoted
  • Snapshots the editor's window layout on entry, restores it on exit so the user's saved arrangement isn't disturbed
  • Bridges the URL's ?step=N and reactour's internal currentStep so browser back/forward navigates tour steps
  • Defers reactour activation until the editor DOM mounts (waitForSelector('[data-testid="editor-v2"]'))
  • Falls back to /learn/tours if tourId doesn't match a registered tour

Tour mode context (src/providers/TourProvider/TourModeContext.tsx)

  • Exposes useTourMode() to editor components: { tour, tempPipelineName, markPipelinePromoted }
  • Editor menu bar uses this to render a "Tour" badge, hide rename/delete actions in the File menu, and show Resume / Save as new pipeline / Exit buttons while the popover is dismissed

Reactour wrapper (src/providers/TourProvider/TourProvider.tsx)

  • Wraps the app in <TourProvider> from reactour with custom Prev / Next / Finish buttons and styling
  • Finish navigates to /learn/tours; X / ESC dismiss the popover but stay on the route so the user can poke around or resume
  • Clamps the popover to the viewport so the step badge isn't clipped near screen edges
  • data-tour-anchor="no-spotlight" sentinel lets a step open a centered popover with no highlight cutout

Editor bridge (src/routes/v2/pages/Editor/components/EditorTourBridge.tsx)

  • Implements three interaction primitives a step can declare: interaction: "undock-window" | "redock-window" | "select-task"
  • Follows window positions so the highlight tracks a floating panel as the user drags it
  • select-task detects clicks on a stable [data-tour-node="task"] ancestor (not a library CSS class) so task selection only counts for true task nodes, not IO ports

Orphan cleanup (src/providers/TourProvider/TourOrphanCleanup.tsx)

  • Sweeps __tour__* pipelines on app load to catch tab-close / crash orphans. Route unmount handles every normal exit path; this covers what the browser kills before we can run.

Layout snapshot (src/routes/v2/shared/windows/windowPersistence.ts)

  • snapshotLayout / restoreLayout stash the editor's persisted window arrangement so a tour can mutate it freely and roll back on exit

Learn page wiringFeaturedTours and ToursLibrary link directly to /tour/$tourId for registered tours; unregistered IDs render as "Coming soon"

Registry is intentionally empty

src/components/Learn/tours/registry.ts ships with const tours: TourDefinition[] = []. Until the first tour is registered (see #2306), every tile on the Learn page renders as "Coming soon". This keeps the framework merge-safe on its own.

How to add a tour

  1. Create src/components/Learn/tours/<yourTour>.tour.json exporting a TourDefinition
  2. Import + push into the tours array in registry.ts
  3. Use stable data-* anchors on the UI elements your steps target. The codebase already exposes:
    • data-tour="..." for panels and bars you add as you go
    • data-dock-area, data-dock-window, data-dock-window-content, data-window-id for the dock/window system
    • data-tour-anchor="no-spotlight" to open a step with a centered popover and no highlight

Related Issue and Pull requests

Progresses https://github.com/Shopify/oasis-frontend/issues/583

Type of Change

  • New feature

Checklist

  • I have tested this does not break current pipelines / runs functionality
  • I have tested the changes on staging

Screenshots

image.png

image.png

Test Instructions

With the registry empty, the visible behavior is:

  • /learn/tours and the dashboard Featured Tours tile render every tour as "Coming soon"
  • No tour can be started; no tour UI appears anywhere
  • Existing editor / runs / dashboard flows are unaffected
  • Navigating to /tour/anything redirects to /learn/tours

Regression check: confirm pipelines list, editor menu bar, dockable / floating windows, and task nodes behave identically to master — none of the tour engine should be visible until a tour registers.

Additional Comments

More tours are intended to follow the first one, covering a range of topics.

Copy link
Copy Markdown
Collaborator Author

camielvs commented May 21, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@camielvs camielvs mentioned this pull request May 21, 2026
3 tasks
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

🎩 Preview

A preview build has been created at: 05-20-feat_learning_hub_tour_framework_and_first_tour/b4ca659

@camielvs camielvs added the #gsd:50583 Learning Hub label May 21, 2026 — with Graphite App
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch 3 times, most recently from 08e1624 to 90d5b9d Compare May 21, 2026 22:07
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from 0f30f2c to 4cc74f0 Compare May 21, 2026 22:07
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from 90d5b9d to d89055f Compare May 21, 2026 22:36
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from 4cc74f0 to fd9690e Compare May 21, 2026 22:37
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch 4 times, most recently from a0e7c17 to a98fb46 Compare May 22, 2026 18:40
@camielvs camielvs changed the title feat: Learning Hub Tour Framework and First Tour feat: Learning Hub Tour Framework May 22, 2026
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from a98fb46 to 9f459c8 Compare May 22, 2026 19:29
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from fd9690e to 8c23f4e Compare May 22, 2026 21:53
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from 9f459c8 to e7770ca Compare May 22, 2026 21:53
@camielvs camielvs mentioned this pull request May 22, 2026
8 tasks
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from e7770ca to e26abd3 Compare May 23, 2026 00:09
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from 8c23f4e to b781af4 Compare May 23, 2026 00:12
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch 2 times, most recently from d95e8da to 6246686 Compare May 23, 2026 00:21
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from b781af4 to 12125e7 Compare May 23, 2026 00:21
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from 6246686 to 3adc6cd Compare May 23, 2026 00:22
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from 12125e7 to 77a5131 Compare May 23, 2026 00:22
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from 3adc6cd to b57b285 Compare May 25, 2026 18:01
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from 77a5131 to 802d35f Compare May 25, 2026 18:01
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from b57b285 to cb2d208 Compare May 25, 2026 18:15
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from 802d35f to ed60f71 Compare May 25, 2026 18:54
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch 8 times, most recently from fbae363 to 5e902e6 Compare May 25, 2026 23:05
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from ed60f71 to f902a92 Compare May 25, 2026 23:28
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from 5e902e6 to 710fedb Compare May 25, 2026 23:28
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from f902a92 to 885177d Compare May 25, 2026 23:40
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from 710fedb to 3eff01a Compare May 25, 2026 23:40
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from 885177d to f1eb709 Compare May 25, 2026 23:42
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch 2 times, most recently from c70b03e to d2b5dc5 Compare May 26, 2026 00:02
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_guided_tours branch from f1eb709 to 51800ff Compare May 26, 2026 00:07
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from d2b5dc5 to 067908d Compare May 26, 2026 00:07
Introduces the guided tour framework using [Reactour](https://docs.reactour.dev/),
exposed as a dedicated `/tour/$tourId` route rather than an imperative
provider call. The route owns:

- The temp tour pipeline lifecycle (create on mount, delete on unmount,
  no persisted "save state" — tours always start fresh)
- Editor layout snapshot/restore around the tour
- URL ↔ reactour step sync (`?step=N` is a stable, shareable deep-link
  and survives same-tab refresh via the URL itself)
- A `TourModeContext` consumed by `EditorMenuBar` and `FileMenu` to show
  tour-specific UI (badge, Resume/Save-as/Exit buttons when the popover
  is closed) and hide destructive actions

Engine bits live under `src/providers/TourProvider/`:
- `TourProvider.tsx` — slim reactour wrapper, app-wide
- `tourPopover.tsx` — styles, position fn, FinishButton, clamp bridge
- `tourPipelineLifecycle.ts` — create/delete/promote/cleanup helpers
- `TourOrphanCleanup.tsx` — sweeps tour pipelines on app load (catches
  tab-close orphans), skipped while user is on a tour route
- `TourModeContext.tsx` — context hook for editor components
- `waitForSelector.ts` — DOM utility

`EditorV2` accepts an optional `pipelineRef` prop so the tour route can
render the same editor against a temp pipeline it resolved itself.

Layout snapshot/restore is exposed from `windowPersistence` so the tour
doesn't reach into localStorage directly.

`registry.ts` ships with `tours: TourDefinition[] = []` — the first
tour lands in the stacked PR.
@camielvs camielvs force-pushed the 05-20-feat_learning_hub_tour_framework_and_first_tour branch from 067908d to b4ca659 Compare May 26, 2026 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

#gsd:50583 Learning Hub

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant