Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7e08dd2
chore(guided-tours): create new workspace
christoph-jerolimov Oct 23, 2026
fff5c6e
Add OpenSpec proposal for guided tour plugin
christoph-jerolimov Oct 23, 2026
eddaaaf
Add guided tour plugin for the new frontend system
christoph-jerolimov Oct 23, 2026
676dd54
Fix padding and width of centered guided tour steps
christoph-jerolimov Oct 23, 2026
a3dec38
Keep the Next button on click-through tour steps
christoph-jerolimov Oct 23, 2026
e478971
Move RestartTourAction into the guided tour react library
christoph-jerolimov Oct 23, 2026
8dd0146
Open the catalog, create and settings pages in the welcome tour
christoph-jerolimov Oct 23, 2026
2a43e95
Rename the default RestartTourAction label
christoph-jerolimov Oct 23, 2026
6fb5446
Restore the route of earlier steps when restarting or resuming a tour
christoph-jerolimov Oct 23, 2026
ebb7ee4
Split resetProgress into resetProgress(id) and resetAllProgress()
christoph-jerolimov Oct 23, 2026
6e1eccd
Turn the guided tour dev app into a portal-like demo
christoph-jerolimov Oct 23, 2026
b612056
Split the dev app tours into files and add page tours
christoph-jerolimov Oct 23, 2026
258100d
Tune the dev app tours
christoph-jerolimov Oct 23, 2026
5470df0
Spotlight the Tasks tab in the scaffolder dev tour
christoph-jerolimov Oct 23, 2026
05f975e
Remove the demo pages and demo tours from the dev app
christoph-jerolimov Oct 23, 2026
7aa33c8
Rework the welcome tour and add a completeRoute to tours
christoph-jerolimov Oct 23, 2026
15a74db
Reorder and reword the welcome tour steps
christoph-jerolimov Oct 23, 2026
1e132a5
Align the remixicon dependency range with Backstage
christoph-jerolimov Oct 23, 2026
3f398d4
Archive the guided-tour-plugin change
christoph-jerolimov Oct 23, 2026
5cc8160
Move the restart-tour button to the pages that own a tour
christoph-jerolimov Oct 23, 2026
07ed7f4
Prepare the guided tours plugins for publishing
christoph-jerolimov Oct 23, 2026
a344bd3
Add API and knip reports and make the tests run in the workspace
christoph-jerolimov Oct 23, 2026
d8c3a91
Fix the deprecations reported by CI
christoph-jerolimov Oct 23, 2026
15850b7
Address review feedback
christoph-jerolimov Oct 23, 2026
07e4983
Add Playwright tests and raise the unit test coverage
christoph-jerolimov Oct 23, 2026
896e7a1
Use act from react in the tests
christoph-jerolimov Oct 24, 2026
d95e58d
Use path instead of route for the autoStart trigger
christoph-jerolimov Oct 24, 2026
e8a46f3
Add an exact flag to the autoStart path
christoph-jerolimov Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ yarn.lock @backsta
/workspaces/grafana @backstage/community-plugins-maintainers
/workspaces/graphiql @backstage/community-plugins-maintainers
/workspaces/graphql-voyager @backstage/community-plugins-maintainers
/workspaces/guided-tours @backstage/community-plugins-maintainers @christoph-jerolimov @ciiay @debsmita1 @divyanshiGupta @its-mitesh-kumar @logonoff @lokanandaprabhu @rohitkrai03 @karthikjeeyar
/workspaces/healert @backstage/community-plugins-maintainers @amgadmag @israa-mosad
/workspaces/ilert @backstage/community-plugins-maintainers
/workspaces/jaeger @backstage/community-plugins-maintainers
Expand Down
8 changes: 8 additions & 0 deletions workspaces/guided-tours/.changeset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
14 changes: 14 additions & 0 deletions workspaces/guided-tours/.changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"privatePackages": {
"tag": false,
"version": false
}
}
6 changes: 6 additions & 0 deletions workspaces/guided-tours/.changeset/guided-tours-initial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@backstage-community/plugin-guided-tours': minor
'@backstage-community/plugin-guided-tours-react': minor
---

Added the guided tours plugins for the new frontend system: spotlight steps on top of any page, per-user progress and automatic start on login or on the first visit of a path. See the [README](https://github.com/backstage/community-plugins/tree/main/workspaces/guided-tours/plugins/guided-tours#readme) for all the details.
8 changes: 8 additions & 0 deletions workspaces/guided-tours/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.git
.yarn/cache
.yarn/install-state.gz
node_modules
packages/*/src
packages/*/node_modules
plugins
*.local.yaml
2 changes: 2 additions & 0 deletions workspaces/guided-tours/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
e2e-tests
playwright.config.ts
1 change: 1 addition & 0 deletions workspaces/guided-tours/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../../.eslintrc.cjs');
54 changes: 54 additions & 0 deletions workspaces/guided-tours/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# macOS
.DS_Store

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Coverage directory generated when running tests with coverage
coverage

# Dependencies
node_modules/

# Yarn files
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Node version directives
.nvmrc

# dotenv environment variables file
.env
.env.test

# Build output
dist
dist-types

# Temporary change files created by Vim
*.swp

# MkDocs build output
site

# Local configuration files
*.local.yaml

# Sensitive credentials
*-credentials.yaml

# vscode database functionality support files
*.session.sql

# E2E test reports
e2e-test-report/
6 changes: 6 additions & 0 deletions workspaces/guided-tours/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dist
dist-types
coverage
.vscode
.eslintrc.js
knip-report.md
38 changes: 38 additions & 0 deletions workspaces/guided-tours/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Guided Tours plugin for Backstage

This workspace contains the guided tours plugins for Backstage: spotlight
steps on top of any page, per-user progress and automatic start on login or
on the first visit of a path. They target the new frontend system.

## Plugins

- [plugin-guided-tours](./plugins/guided-tours/README.md): the tour runner,
the overlay and the overview page at `/guided-tours`.
- [plugin-guided-tours-react](./plugins/guided-tours-react/README.md): the
blueprint, API ref and hooks that let any frontend plugin ship a tour.

## Getting Started

To start the dev app, run:

```sh
yarn install
yarn start
```

It opens a portal-like demo at http://localhost:3000 with a welcome tour and
page tours for the catalog, templates, notifications and settings.

## Tests

```sh
yarn test # unit tests
yarn test:e2e # Playwright tests against the dev app
```

To generate the API and knip reports for this workspace, run:

```sh
yarn build:api-reports
yarn build:knip-reports
```
3 changes: 3 additions & 0 deletions workspaces/guided-tours/backstage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": "1.56.2"
}
7 changes: 7 additions & 0 deletions workspaces/guided-tours/bcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"autoVersionBump": true,
"knipReports": true,
"listDeprecations": true,
"playwrightTests": true,
"codecov": true
}
92 changes: 92 additions & 0 deletions workspaces/guided-tours/e2e-tests/guided-tours-page.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2026 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect, test } from '@playwright/test';
import { closeTour, resetAllTours, step, stepButton } from './helpers';

test.describe('guided tours page', () => {
test.beforeEach(async ({ page }) => {
await resetAllTours(page);
await page.goto('/guided-tours');
await closeTour(page);
});

test('lists every tour with its status and lets the user start, continue and restart', async ({
page,
}) => {
await expect(
page.getByRole('heading', { name: 'Guided tours' }).first(),
).toBeVisible();
for (const title of [
'Welcome to Backstage',
'The software catalog',
'Create from a template',
'Your notifications',
'Your settings',
]) {
await expect(page.getByRole('heading', { name: title })).toBeVisible();
}
const welcome = page.locator(
'[data-guided-tour="guided-tours.row.guided-tours/welcome"]',
);
const catalog = page.locator(
'[data-guided-tour="guided-tours.row.guided-tours/catalog"]',
);
await expect(welcome.getByText('Dismissed')).toBeVisible();
await expect(catalog.getByText('New')).toBeVisible();
await expect(
catalog.getByText('3 steps · Starts on first visit of /catalog'),
).toBeVisible();

// Start opens the tour on the page of its first step
await catalog.getByRole('button', { name: 'Start' }).click();
await expect(page).toHaveURL(/\/catalog/);
await expect(step(page, 'Pick a kind')).toBeVisible();
await stepButton(page, 'Next').click();
await expect(step(page, 'Yours, starred, or everything')).toBeVisible();

// a tour left on another page is not resumed here, the page offers to
// continue it where it was
await page.goto('/guided-tours');
await expect(catalog.getByText('In progress')).toBeVisible();
await expect(page.getByRole('dialog')).toHaveCount(0);
await catalog.getByRole('button', { name: 'Continue' }).click();
await expect(page).toHaveURL(/\/catalog/);
await expect(
step(page, 'Yours, starred, or everything').getByText('Step 2 of 3'),
).toBeVisible();
await closeTour(page);

// dismissed and completed tours can be restarted from the first step
await page.goto('/guided-tours');
await expect(catalog.getByText('Dismissed')).toBeVisible();
await welcome.getByRole('button', { name: 'Restart' }).click();
await expect(
step(page, 'Welcome 👋').getByText('Step 1 of 6'),
).toBeVisible();
await closeTour(page);

// Reset all asks for confirmation and clears every status
await page.getByRole('button', { name: 'Reset all tours' }).click();
await expect(
page.getByRole('dialog').getByText('Reset all tours?'),
).toBeVisible();
await page.getByRole('button', { name: 'Cancel' }).click();
await expect(welcome.getByText('Dismissed')).toBeVisible();
await page.getByRole('button', { name: 'Reset all tours' }).click();
await page.getByRole('button', { name: 'Reset', exact: true }).click();
await expect(page.getByText('New')).toHaveCount(5);
});
});
52 changes: 52 additions & 0 deletions workspaces/guided-tours/e2e-tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2026 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect, Page } from '@playwright/test';

/** The button inside the step card; the dev pages have other Next/Previous buttons. */
export const stepButton = (page: Page, name: 'Previous' | 'Next' | 'Done') =>
page.getByRole('dialog').getByRole('button', { name, exact: true });

/** The step card: a centered dialog named after its heading, or an anchored popover. */
export const step = (page: Page, title: string) =>
page.getByRole('dialog', { name: title });

export const spotlight = (page: Page) =>
page.getByTestId('guided-tour-spotlight');

/** Closes a running tour, if any. Tours start a moment after the page loads. */
export async function closeTour(page: Page) {
const close = page.getByRole('button', { name: 'Close tour' });
await close
.first()
.waitFor({ state: 'visible', timeout: 3000 })
.catch(() => undefined);
if (await close.count()) {
await close.first().click();
}
await expect(page.getByRole('dialog')).toHaveCount(0);
}

/**
* Clears all progress through the guided tours page. The welcome tour then
* starts again on the next page load, as it does for a new user.
*/
export async function resetAllTours(page: Page) {
await page.goto('/guided-tours');
await closeTour(page);
await page.getByRole('button', { name: 'Reset all tours' }).click();
await page.getByRole('button', { name: 'Reset', exact: true }).click();
await expect(page.getByRole('dialog')).toHaveCount(0);
}
Loading
Loading