Skip to content

feat: Guided Tours Framework (Secrets)#2405

Open
camielvs wants to merge 2 commits into
06-03-feat_guided_tour_-_subgraphsfrom
06-10-feat_guided_tours_framework_secrets_
Open

feat: Guided Tours Framework (Secrets)#2405
camielvs wants to merge 2 commits into
06-03-feat_guided_tour_-_subgraphsfrom
06-10-feat_guided_tours_framework_secrets_

Conversation

@camielvs

@camielvs camielvs commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Description

The secret-specific interaction mechanics for the guided-tour framework, layered on the framework stack (#2348 / #2299 / #2347 / #2340) and the subgraphs mechanics (#2365). Foundation for the Using Secrets tour (#2406) — this PR adds the interaction types and bridge logic that detect them, the in-editor Settings → Secrets stand-in the tour opens, an in-memory mock backend so the secret steps stay hands-on without a real backend, and small reusability/behavior tweaks that let it all run without leaving the tour page. The tour content and DOM anchors land in #2406.

What changed

Interaction vocabulary (src/components/Learn/tours/registry.ts)

Five new TourStep.interaction values, plus a tourPanel field, plus a tour-level mockBackend flag (see below):

  • assign-secret-argument — a task argument's value becomes a secret (MobX activeSpec reaction via isSecretArgument; optionally gated to a targetArgumentName)
  • assign-secret-submit — a secret gets bound inside the submit dialog. The value lives in the dialog's local React state (not the spec), so this is detected from the DOM rather than a spec reaction
  • open-secret-dialog / open-settings-panel / open-submit-dialog — the respective dialog appears in the DOM
  • tourPanel: "secrets-manager" — marks the steps during which the in-editor Settings stand-in should be open

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

Each interaction marks the step complete in the shared tour-progress state (following #2299; it doesn't advance the tour itself). The three open-* handlers are MutationObserver DOM-presence checks; assign-secret-argument is a spec reaction; assign-secret-submit watches for the secret display inside the submit dialog. Already-satisfied-on-entry states are marked complete immediately; gated "Next" / auto-advance (#2340) handle progression.

Checklist labels (src/providers/TourProvider/tourActionLabels.ts + test)

Copy for the five interactions, e.g. assign-secret-argument → "Assign a secret to the {targetArgumentName} argument", open-settings-panel → "Open Settings to manage your secrets".

In-editor Settings → Secrets stand-in (TourSecretsDialog.tsx, new)

Navigating to the real /settings/secrets route would unmount the tour page and tear the tour down. Instead, a non-modal dialog mirrors the real settings shell (sidebar with Secrets active, the other tabs disabled) and renders the real SecretsListView, keeping add/replace in-dialog rather than using the Settings router links. It opens when the active step is marked tourPanel: "secrets-manager" and the user clicks the gear (openTourSettings), and closes when the tour leaves those steps.

  • AppMenuActions.tsx — in tour mode the Settings gear calls openTourSettings() instead of routing away (keeps its data-tracking-id so the tour can anchor to it).
  • EditorV2.tsx — mounts <TourSecretsDialog /> alongside the existing tour dialogs.

No-backend mock backend (tourMockBackend.ts new, secretsStorage.ts, Tour.tsx, secret/submit gates)

Secrets live on the backend, so without one the secret steps would otherwise trap the user on a step they can't complete. When a tour opts in (TourDefinition.mockBackend) and there's no real backend, the secrets backend is mocked in-memory so the steps stay fully hands-on — the user really opens the picker, adds a secret, picks it, and assigns it, against an ephemeral store that is cleared when the tour ends. Nothing is persisted or sent anywhere; with a real backend this is inert.

  • tourMockBackend.ts (new) — a provider-free module store: setTourMockActive/isTourMockActive, a useTourMockBackend() hook, and an in-memory Secret map (mockListSecrets/mockAddSecret/mockUpdateSecret/mockRemoveSecret).
  • secretsStorage.tsfetchSecretsList/addSecret/updateSecret/removeSecret route to the in-memory store when the mock is active (the existing SecretsQueryKeys.All() invalidations keep the list fresh).
  • Tour.tsx — a TourMockBackendController activates the mock while tour.mockBackend && !available and clears it (and the store) on tour exit.
  • Gates accept the mock: SelectSecretDialog / SecretsList render the real picker (available || mock); the run-with-arguments (split-arrows) button enables so the submit dialog can open. The primary Submit button and the submit-args confirm stay gated on real availability — the secret-to-input assignment is demonstrated, but launching a real run isn't wired in mock mode.

Friendly no-backend empty state (SecretsBackendUnavailable.tsx, new)

SelectSecretDialog / SecretsList show a "Backend not connected" state (Lock/DB icon + copy) instead of the generic error-boundary icon when there's genuinely no backend and the mock isn't active — which also improves the real Settings → Secrets page for backend-less setups.

Reusable secrets components (SecretsList.tsx, SecretsListView.tsx)

Optional onAddSecret / onEditSecret callbacks. They default to the existing router links (real Settings page is unchanged), but let the stand-in reuse the real list/forms with in-dialog add/replace — so the tour isn't a hand-maintained copy of the secrets UI.

Popover & dialog behavior

  • TourPopover.tsxcomputeDefaultPopoverPosition gains a branch for a tall, centered modal: anchor the popover to its left, aligned to the dialog's top edge (rather than vertically centered).
  • SubmitTaskArgumentsDialog.tsx — renders modal={!tourMode}; non-modal during a tour so the portaled tour popover (Next / Finish Tour) stays clickable while the dialog is open. Behavior outside tours is unchanged.

Related Issue and Pull requests

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

Builds on the framework stack (#2348 / #2299 / #2347 / #2340 / #2365); consumed by the Using Secrets tour in #2406.

Type of Change

  • New feature

Checklist

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

Test Instructions

The registry is otherwise inert in this PR — the interactions are exercised end-to-end by the Using Secrets tour in #2406. To verify in isolation:

  • No regressions in the existing tours and in the real Settings → Secrets page (add / replace / delete still navigate and work as before).
  • No backend: the Using Secrets tour (feat: Guided Tour - Secrets #2406) runs fully hands-on against the in-memory mock — the secret picker/list show real content (not the error icon), steps gate normally, and no /api/secrets calls fire. Settings → Secrets with no backend shows the "Backend not connected" state.
  • With a backend: behavior is unchanged (real secrets, real submit).
  • Submit dialog outside a tour is still modal (focus trap + scrim) as before.
  • pnpm typecheck, pnpm lint, and the tourActionLabels / tourMockBackend unit tests pass.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

🎩 Preview

A preview build has been created at: 06-10-feat_guided_tours_framework_secrets_/b7b4365

camielvs commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator Author

@camielvs camielvs added the #gsd:50583 Learning Hub label Jun 10, 2026 — with Graphite App
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch 2 times, most recently from 62653bf to d7a841f Compare June 11, 2026 20:32
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from f541439 to 4b15ecd Compare June 11, 2026 20:32
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from d7a841f to c7356f5 Compare June 11, 2026 20:55
Comment thread src/routes/v2/pages/Editor/components/EditorTourBridge.tsx
Comment thread src/routes/v2/pages/Editor/components/EditorTourBridge.tsx
Comment thread src/routes/v2/pages/Editor/components/EditorTourBridge.tsx Outdated
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from a386028 to 8035a04 Compare June 15, 2026 17:55
@camielvs camielvs mentioned this pull request Jun 15, 2026
8 tasks
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 8035a04 to 3538d7a Compare June 15, 2026 18:47
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from 4b15ecd to 43ecf52 Compare June 15, 2026 18:47
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 3538d7a to ceba986 Compare June 15, 2026 18:59
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from 43ecf52 to 40d7a25 Compare June 15, 2026 18:59
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from ceba986 to 564f6b9 Compare June 15, 2026 19:21
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch 2 times, most recently from a6562cb to f997497 Compare June 15, 2026 19:32
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 564f6b9 to d2b59c0 Compare June 15, 2026 19:32
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from f997497 to 2ea3d5e Compare June 15, 2026 19:49
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from d2b59c0 to 6b9c892 Compare June 15, 2026 19:49
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from e8326e6 to cc248e5 Compare June 16, 2026 00:38
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from eec8848 to 46f3364 Compare June 16, 2026 00:38
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from cc248e5 to ea6118d Compare June 16, 2026 00:58
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 46f3364 to 2e917b7 Compare June 16, 2026 00:58
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from ea6118d to b44628b Compare June 16, 2026 01:15
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 2e917b7 to d9f0b2a Compare June 16, 2026 01:15
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from b44628b to 6961ae0 Compare June 16, 2026 01:26
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from d9f0b2a to 84a4fcc Compare June 16, 2026 01:27
@camielvs camielvs marked this pull request as ready for review June 16, 2026 19:33
@camielvs camielvs requested a review from a team as a code owner June 16, 2026 19:33
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 84a4fcc to c2bd919 Compare June 17, 2026 17:24
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from c2bd919 to bef69f1 Compare June 19, 2026 02:25
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from 2ce1124 to 723df5c Compare June 19, 2026 02:25
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from bef69f1 to a095516 Compare June 19, 2026 18:49
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch 2 times, most recently from 14e2536 to e9e851a Compare June 19, 2026 21:48
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from a095516 to 9b2a265 Compare June 19, 2026 21:48
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from e9e851a to bc658d3 Compare June 26, 2026 00:20
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 9b2a265 to 7bb124c Compare June 26, 2026 00:20
camielvs and others added 2 commits June 25, 2026 17:53
When a tour opts in (TourDefinition.mockBackend) and runs without a real
backend, mock the secrets backend in-memory so its secret steps stay hands-on
(open the picker, add/pick/assign a secret) against an ephemeral store cleared
when the tour ends. Steps gate normally; the submit dialog opens to demonstrate
assigning a secret to a run input, but real run submission stays gated on
availability.

- tourMockBackend: module store + useTourMockBackend hook + in-memory secrets
- secretsStorage routes to the mock when active
- TourMockBackendController activates it (tour.mockBackend && !available)
- secrets list/picker + run-with-arguments button accept the mock; submit
  confirm stays disabled in mock mode
- Replaces the earlier read-only degrade (drops requiresBackend gating
  relaxation, fallbackContent/BackendAwareStepContent); keeps the
  SecretsBackendUnavailable empty state for non-tour Settings -> Secrets

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@camielvs camielvs force-pushed the 06-03-feat_guided_tour_-_subgraphs branch from bc658d3 to bdaf9f1 Compare June 26, 2026 00:53
@camielvs camielvs force-pushed the 06-10-feat_guided_tours_framework_secrets_ branch from 7bb124c to b7b4365 Compare June 26, 2026 00:53
}

if (interaction === "open-submit-dialog") {
const dialogSelector = '[data-tour="submit-arguments-dialog"]';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 This is an AI-generated code review comment.

The new open-submit-dialog and assign-secret-submit interactions watch for [data-tour="submit-arguments-dialog"], but SubmitTaskArgumentsDialog does not render that data-tour attribute. The Secrets tour will therefore stall when it asks the user to open or complete the submit-arguments dialog.

Suggestion: Add data-tour="submit-arguments-dialog" to the DialogContent in SubmitTaskArgumentsDialog, or update the bridge to use an existing stable selector that the dialog actually renders.

Rule: tangle-ui review: high-priority functional bugs must be flagged; E2E/tour selectors must match real rendered DOM.

// settings shell (sidebar with Secrets active, other tabs disabled) and renders
// the real SecretsListView, but keeps add/replace in-dialog instead of using the
// router links the real page relies on, so the tour never navigates away.
export function TourSecretsDialog() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 This is an AI-generated code review comment.

This PR adds new components/hooks under directories that are not covered by REACT_COMPILER_ENABLED_DIRS (src/providers and src/components/shared/SecretsManagement are not enabled). New components and hooks must be compiler-covered when introduced; otherwise the stack expands uncompiled React code.

Suggestion: Add compiler entries for the new files that are compatible now, at minimum src/providers/TourProvider/TourSecretsDialog.tsx, src/providers/TourProvider/tourMockBackend.ts, and src/components/shared/SecretsManagement/components/SecretsBackendUnavailable.tsx, then validate.

Rule: react-patterns: new/moved/renamed components and hooks must be covered by react-compiler.config.js.

Manage your secrets.
</DialogDescription>

<BlockStack className="h-full">

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 This is an AI-generated code review comment.

The new settings stand-in styles BlockStack, InlineStack, and Button via className, and SecretsBackendUnavailable does the same for BlockStack/Icon. Project rules require semantic primitive props or a local/pattern component instead of using className as an escape hatch on primitives.

Suggestion: Move these layout styles into semantic primitive props or a small local primitive/pattern wrapper for the settings shell; use tone/size props for icon/text styling instead of primitive className.

Rule: ui-primitives: never pass className to a Tangle UI primitive; prefer semantic props or Layer-3/local primitive patterns.

};
}

if (interaction === "open-secret-dialog") {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 This is an AI-generated code review comment.

The PR adds several near-identical MutationObserver branches for selector-based interactions. The file is already very large and FTA reports 85.7 with cyclomatic complexity 160, so adding repeated branches makes future tour interactions harder to maintain.

Suggestion: Extract a small helper such as waitForSelectorInteraction(selector, { skip, advance, stopFollow }) and reuse it for open-secret-dialog, open-settings-panel, open-submit-dialog, and assign-secret-submit.

Rule: static-analysis: high FTA/cyclomatic complexity should be tied to concrete extraction; tangle-ui review: duplicated logic should be extracted.

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.

2 participants