npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@paf-devs/app-tour

v0.2.1

Published

Accessible guided-tour frontend for the app-tour Django package.

Downloads

16

Readme

App Tour

app-tour is a dual Django and npm package that extracts the guided-tour capability from Helpdesk for reuse across applications. Django supplies tour configuration, permissions, templates, migrations, and per-user progress. The npm package supplies the dependency-free browser engine and styles for apps that build frontend assets with npm.

It supports multiple tours per app, server-side per-user progress, versioned re-launches, role restrictions, responsive positioning, keyboard focus containment, reduced motion, manual replay, and lifecycle browser events.

Choose the installation mode

  • Install the Django package when Django owns authentication, tour configuration, rendering, and server-side progress. This already includes the JavaScript and CSS through Django static files.
  • Install both Django and npm packages when the application uses a JavaScript bundler and wants to import the frontend engine and CSS explicitly.
  • Install npm only for a custom backend. In this mode, the consuming app must produce the expected markup/data attributes and implement a compatible authenticated state endpoint.

The npm package does not replace the Django package's database model, permissions, templates, migrations, or state API.

Install Django

For local development from this repository:

python -m pip install -e /Users/ryanurms/Documents/app-tour

Install directly from the private GitHub repository:

python -m pip install \
  "app-tour @ git+https://github.com/yanigero/[email protected]"

Private GitHub installation requires an approved Git credential mechanism on the deployment host. Do not place access tokens in source code, requirements files, Dockerfiles, shell history, or image layers.

To build and install a wheel:

python -m build
python -m pip install dist/app_tour-0.2.1-py3-none-any.whl

Add the app and URL route:

# settings.py
INSTALLED_APPS += ["app_tour"]

# project urls.py
path("guided-tours/", include("app_tour.urls")),

Then run:

python manage.py migrate app_tour
python manage.py collectstatic

The standard Django request template context processor must be enabled.

Install npm

The npm package name is @paf-devs/app-tour:

npm install @paf-devs/app-tour

For a private GitHub repository before publishing to the npm registry:

npm install github:yanigero/app-tour#v0.2.1

Import the browser engine and styles in the application's frontend entrypoint:

import "@paf-devs/app-tour/tour.css";
import { scanTours, startTour } from "@paf-devs/app-tour";

// Re-scan after AJAX or framework rendering inserts tour markup.
scanTours();

// Optional programmatic replay.
startTour("inventory-dashboard");

The Django template tag already references Django static files. Do not also bundle the npm assets on the same page unless the template is overridden to remove those static references; loading the engine twice is unnecessary.

npm exports

| Import | Purpose | | --- | --- | | @paf-devs/app-tour | Side-effect initialization plus scanTours() and startTour() | | @paf-devs/app-tour/tour.js | Raw dependency-free browser engine | | @paf-devs/app-tour/tour.css | Tour UI styles |

The npm module is safe to import during server-side rendering, but tour initialization only occurs in a browser with window and document.

Configure a tour

Tours are registered centrally in settings.APP_TOURS. The key must be stable and unique across the whole PAFILS installation.

APP_TOURS = {
    "helpdesk-dashboard": {
        "version": 3,
        "title": "Helpdesk guided tour",
        "autostart": True,
        "allow_skip": True,
        "steps": [
            {
                "title": "Welcome to Helpdesk",
                "body": "This tour explains the request workflow.",
            },
            {
                "selector": "[data-tour='helpdesk-search']",
                "title": "Find a ticket",
                "body": "Search across ticket number, requestor, and content.",
            },
            {
                "selector": "[data-tour='helpdesk-new-ticket']",
                "title": "Create a request",
                "body": "Open the form and describe the issue clearly.",
                "next_label": "Finish",
            },
        ],
    },
    "inventory-dashboard": {
        "version": 1,
        "permission": "inventory.view_asset",
        "steps": [
            {
                "title": "Inventory",
                "body": "Learn the inventory dashboard.",
            },
            {
                "selector": "[data-tour='inventory-filters']",
                "title": "Filter assets",
                "body": "Narrow the list by unit, status, or custodian.",
            },
        ],
    },
}

Optional groups restricts a tour to users in at least one named Django group. Optional permission requires a Django permission. If both are specified, both must pass. Authorization for the tour never replaces authorization for the underlying application feature.

Add stable target attributes and render the tour once on the page:

{% load app_tour %}

<button data-app-tour-start="helpdesk-dashboard">Guided tour</button>
<div data-tour="helpdesk-search">...</div>
<div data-tour="helpdesk-new-ticket">...</div>

{% app_tour "helpdesk-dashboard" %}

A step without selector is a centered welcome or completion step. A missing selector is also handled as a centered step, so conditional role-specific elements do not crash the tour. Prefer separate role tours when the instructions are materially different.

How it works across apps

Each app owns only:

  • its stable tour key and version;
  • its instructional text and ordered selectors;
  • target attributes in its templates;
  • optional group or permission restrictions;
  • an optional replay button.

The package owns the shared state model, state endpoint, UI, CSS, JavaScript, focus handling, positioning, and completion rules. A single user can therefore complete Helpdesk while remaining a first-time user in Inventory or RIS.

Increase version only when a changed tour is important enough to offer again. The next page visit resets that tour to first-time status without deleting its original first_seen_at. Do not rename a key casually: a new key creates a new independent history.

For content loaded after page startup (for example a modal inserted with AJAX), insert the tour markup and dispatch:

document.dispatchEvent(new Event("app-tour:scan"));

The component emits bubbling events named app-tour:start, app-tour:step, app-tour:complete, and app-tour:skip. Analytics code may listen to these without modifying the package. The step event also lets an app open a practice panel or prepare dynamic content:

document.addEventListener("app-tour:step", function (event) {
  if (event.detail.tour !== "helpdesk-dashboard") return;
  document.querySelector("#helpdeskPractice").hidden =
    !event.detail.step.practice;
});

Helpdesk migration

The current Helpdesk implementation should be migrated as follows:

  1. Configure helpdesk-dashboard version 3 using its current dashboard steps.
  2. Replace inline tour CSS, markup, and JavaScript with the template tag.
  3. Replace current target IDs with stable data-tour attributes.
  4. Migrate HelpdeskUserOnboarding rows into UserTourState with the key helpdesk-dashboard, preserving timestamps and status.
  5. Configure the ticket thread as a second tour, such as helpdesk-ticket-requestor and helpdesk-ticket-admin, because its steps differ by role.
  6. After data and behavior verification, remove the Helpdesk-specific model, endpoint, migration-reset logic, and duplicated tour code.

Do not delete the old model before a data migration and rollback plan exist.

Strengths

  • One engine and one progress model for every Django app.
  • Progress follows the authenticated user across devices and browsers.
  • Independent keys prevent one app's completion from suppressing another app.
  • Versions safely re-offer materially revised tours.
  • No external JavaScript/CDN dependency.
  • Role/permission gates and missing-target tolerance support conditional pages.
  • Manual replay, focus return, focus containment, Escape handling, responsive positioning, and reduced-motion support are built in.
  • Lifecycle events provide an analytics integration point.

Required work before production

  • Complete screen-reader testing on Safari/VoiceOver and Windows/NVDA.
  • Test keyboard behavior inside SweetAlert2 and other nested modal frameworks; two simultaneous focus traps can conflict.
  • Add a Content Security Policy strategy. The template currently emits a small inline JSON script, which may require a nonce or hash under strict CSP.
  • Decide whether "skip" is permanent for a version or whether reminders are required after a cooling-off period.
  • Define analytics retention, access, and privacy policy before collecting more detailed step-level telemetry.
  • Add translation (gettext) before multilingual rollout.
  • Establish content ownership and review: each app owner must verify text, selectors, permissions, version changes, and screenshots during release.
  • Add browser tests for desktop, mobile, zoom at 200%, long translated text, dynamically hidden targets, and pages with fixed/sticky headers.
  • Add automated orphan-selector checks so template changes cannot silently turn targeted steps into centered steps.
  • Decide how multi-page tours should resume. Version 0.1 is page-scoped; it does not navigate between URLs or persist the current step.
  • Define anonymous-user behavior. Version 0.1 intentionally requires login and stores no browser-only progress.
  • If several tours are rendered on one page, ensure only one autostarts. Application configuration currently owns that coordination.

Security and operational disclosures

  • Tour visibility is not feature authorization. Every underlying view and API must continue enforcing its own permissions.
  • Step text is rendered from trusted server configuration and assigned through textContent; do not change the engine to inject untrusted HTML.
  • State updates require authentication, POST, and Django CSRF protection.
  • Tour progress is user activity metadata. Include it in retention, export, deletion, audit, and privacy procedures as applicable.
  • The update request is intentionally non-blocking. A network failure does not stop the UI, so state may be offered again later. Monitor endpoint failures.
  • Selectors are a public integration contract between app templates and tour configuration. Prefer purpose-built data-tour attributes over CSS classes used for styling.
  • Removing a configured tour does not automatically delete historical state. Retain it for audit or remove it through an approved data-retention process.

Build and verify both packages

python -m django test tests --settings=tests.settings
python -m build
npm run check
npm pack --dry-run

Python and npm versions must be released together. A release should use the same semantic version in pyproject.toml, setup.py, app_tour.__version__, and package.json.

Publishing to npm is a separate external release action:

npm publish

Do not run it until the @paf-devs npm organization/account ownership, package visibility, release approval, and npm authentication method are confirmed. A private GitHub repository does not automatically make an npm package private; publishConfig.access is currently public.

Package status

Version 0.2.1 is an extracted foundation, not a production approval. It must be integrated into a PAFILS test branch, supplied with the exact existing Helpdesk step definitions, data-migrated, and subjected to the UAT and accessibility gates above before replacing the live Helpdesk implementation.