Skip to content

grafana/docs-plugin

Grafana Learning Journeys Plugin

Dynamic JSON Badge License

A documentation plugin that provides contextual learning journeys directly within the Grafana interface.

Overview

The Grafana Learning Journeys Plugin transforms how users interact with documentation by providing:

  • 🎯 Context-Aware Recommendations - suggestions based on current Grafana context (page, data sources, dashboard state)
  • πŸ“š Interactive Learning Journeys - Step-by-step guided experiences with progress tracking and milestone navigation
  • πŸ—‚οΈ Tabbed Interface - Browser-like multi-tab experience for simultaneous documentation access
  • πŸ”Œ Extensible Architecture - Decoupled design allowing easy integration with different content sources
  • πŸ“± Responsive Design - Optimized for sidebar integration with adaptive layouts
  • πŸš€ Auto-Launch Tutorials - Automatically open specific tutorials on Grafana startup for demo scenarios

Auto-Launch Tutorial Feature

Perfect for demo scenarios! The plugin can automatically open a specific tutorial when Grafana starts by setting an environment variable:

# Docker Compose example
GF_PLUGINS_GRAFANA_GRAFANADOCSPLUGIN_APP_TUTORIAL_URL=https://grafana.com/docs/learning-journeys/linux-server-integration/

# Docker run example  
docker run -d -p 3000:3000 \
  -e GF_PLUGINS_GRAFANA_GRAFANADOCSPLUGIN_APP_TUTORIAL_URL=https://grafana.com/docs/learning-journeys/linux-server-integration/ \
  grafana/grafana:latest

πŸ“– Complete Auto-Launch Documentation - Detailed setup guide with examples for Docker, Kubernetes, and more.

Running the plugin locally

Clone the repository:

git clone https://github.com/grafana/docs-plugin.git

Then build the plugin:

cd docs-plugin
npm install
npm run build

Spin up the development server:

Note we are currently using main until the next release of Grafana.

GRAFANA_IMAGE=grafana GRAFANA_VERSION=main npm run server

Access the plugin in Grafana at http://localhost:3000

Developer Documentation

This plugin follows a modular, well-documented architecture. Each major component has detailed documentation:

πŸ“ Core Architecture

🧩 Components

πŸ”§ System Architecture

🎨 Assets

Architecture Overview

High-Level Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Grafana Core Application                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                     Plugin Extension Points                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Sidebar Componentβ”‚    β”‚       Navigation Links         β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚                               β”‚
            β–Ό                               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Learning Journeys Plugin                    β”‚
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Context Panel  β”‚    β”‚  Journey Panel  β”‚    β”‚   App Core  β”‚ β”‚
β”‚  β”‚                 β”‚    β”‚                 β”‚    β”‚             β”‚ β”‚
β”‚  β”‚ β€’ Recommendationsβ”‚    β”‚ β€’ Tab Managementβ”‚    β”‚ β€’ Routing   β”‚ β”‚
β”‚  β”‚ β€’ Context Detectionβ”‚  β”‚ β€’ Content Displayβ”‚   β”‚ β€’ State     β”‚ β”‚
β”‚  β”‚ β€’ User Interaction β”‚  β”‚ β€’ Navigation    β”‚    β”‚ β€’ Config    β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚            β”‚                       β”‚                     β”‚     β”‚
β”‚            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                                    β”‚                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β”‚
                                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Data Layer (Decoupled)                    β”‚
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Docs Fetcher   β”‚    β”‚ Recommender API β”‚    β”‚   Cache     β”‚ β”‚
β”‚  β”‚                 β”‚    β”‚                 β”‚    β”‚             β”‚ β”‚
β”‚  β”‚ β€’ Content Fetch β”‚    β”‚ β€’ Context Analysisβ”‚   β”‚ β€’ In-Memory β”‚ β”‚
β”‚  β”‚ β€’ HTML Parsing  β”‚    β”‚ β€’ ML Recommendationsβ”‚ β”‚ β€’ Persistentβ”‚ β”‚
β”‚  β”‚ β€’ URL Resolutionβ”‚    β”‚ β€’ Journey Mapping β”‚   β”‚ β€’ Invalidationβ”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚            β”‚                       β”‚                     β”‚     β”‚
β”‚            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                                    β”‚                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β”‚
                                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    External Data Sources                       β”‚
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚ Grafana.com Docsβ”‚    β”‚  Custom CMS     β”‚    β”‚  Local Docs β”‚ β”‚
β”‚  β”‚ Learning Journeysβ”‚    β”‚ Documentation   β”‚    β”‚   Files     β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Component Architecture

The plugin follows a modular, scene-based architecture using Grafana Scenes. See the Documentation Panel README for detailed component relationships and the Utilities README for the refactored business logic organization.

Refactoring Success Story

This codebase underwent major refactoring to improve maintainability:

  • Before: Single component with ~3,500 lines mixing UI, business logic, and styling
  • After: Organized into focused, reusable modules with clear separation of concerns

Key Improvements:

How the Plugin Operates

1. Initialization Flow

User Opens Grafana
        β”‚
        β–Ό
Plugin Loads via Extension Points
        β”‚
        β–Ό
Context Panel Analyzes Current State
    β€’ Current URL/Path
    β€’ Active Data Sources  
    β€’ Dashboard Information
    β€’ User Session Data
        β”‚
        β–Ό
Recommendation Service Called
    β€’ Sends context payload
    β€’ Receives relevant journeys
    β€’ Pre-fetches milestone information
        β”‚
        β–Ό
UI Renders with Recommendations

2. User Interaction Flow

User Clicks "Start Journey"
        β”‚
        β–Ό
New Tab Created
    β€’ Generates unique tab ID
    β€’ Sets initial loading state
    β€’ Adds to tab collection
        β”‚
        β–Ό
Content Fetching Initiated
    β€’ docs-fetcher.fetchLearningJourneyContent()
    β€’ Multiple strategy fallback system
    β€’ HTML parsing and transformation
        β”‚
        β–Ό
Content Rendered
    β€’ Milestone progress indicator
    β€’ Interactive content with fixed assets
    β€’ Navigation controls
    β€’ Video integration
        β”‚
        β–Ό
User Navigates Through Milestones
    β€’ Previous/Next milestone buttons
    β€’ Direct milestone jumping
    β€’ Progress tracking
    β€’ Cache optimization

3. Data Flow Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    Context Analysis    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Context Panel  β”‚ ──────────────────────→ β”‚ Recommender API β”‚
β”‚                 β”‚                        β”‚                 β”‚
β”‚ β€’ Page Detectionβ”‚ ←──────────────────────  β”‚ β€’ ML Processing β”‚
β”‚ β€’ Data Sources  β”‚   Journey Suggestions   β”‚ β€’ Journey Map   β”‚
β”‚ β€’ Dashboard Infoβ”‚                        β”‚ β€’ Relevance     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                                           β”‚
        β”‚ User Selects Journey                      β”‚
        β–Ό                                           β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    Content Request     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Journey Panel  β”‚ ──────────────────────→ β”‚  Docs Fetcher   β”‚
β”‚                 β”‚                        β”‚                 β”‚
β”‚ β€’ Tab Manager   β”‚ ←──────────────────────  β”‚ β€’ Multi-Strategyβ”‚
β”‚ β€’ UI Renderer   β”‚    Processed Content    β”‚ β€’ HTML Parser   β”‚
β”‚ β€’ Navigation    β”‚                        β”‚ β€’ Asset Fixer   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                   β”‚
                                                   β”‚ Raw Content
                                                   β–Ό
                                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                          β”‚ Content Sources β”‚
                                          β”‚                 β”‚
                                          β”‚ β€’ Grafana Docs  β”‚
                                          β”‚ β€’ Custom CMS    β”‚
                                          β”‚ β€’ Local Files   β”‚
                                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Docs Fetcher: Decoupled Architecture

Design Philosophy

The docs fetcher is intentionally designed as a decoupled, pluggable system that can be easily replaced or extended without affecting the rest of the plugin. This enables teams to:

  • Replace content sources (switch from Grafana.com to internal docs)
  • Customize content processing (add custom parsing logic)
  • Implement different fetching strategies (GraphQL, REST APIs, file systems)
  • Maintain UI functionality (all existing features continue to work)

For detailed information on the docs fetcher architecture and how to customize it, see the Utilities Documentation.

Interface Contracts

The decoupling is achieved through well-defined TypeScript interfaces that act as contracts:

// Core data structures that UI components depend on
export interface LearningJourneyContent {
  title: string;              // Display title
  content: string;            // Processed HTML content  
  url: string;                // Source URL
  currentMilestone: number;   // Progress indicator
  totalMilestones: number;    // Total steps
  milestones: Milestone[];    // Navigation structure
  lastFetched: string;        // Cache metadata
  videoUrl?: string;          // Optional video content
}

export interface Milestone {
  number: number;             // Step sequence
  title: string;              // Step name
  duration: string;           // Estimated time
  url: string;                // Step URL
  isActive: boolean;          // Current step indicator
}

Current Implementation

The current fetcher implements a resilient approach with multiple fallback strategies for content retrieval. See the Utilities README for comprehensive details on the data fetching architecture and customization options.

Development Setup

Prerequisites

  • Node.js 18+ and npm
  • Grafana 11.0.0 or later
  • Git
  • Docker (for development environment)

Quick Start

# Clone the repository
git clone https://github.com/grafana/grafana-docs-plugin.git
cd grafana-docs-plugin

# Install dependencies
npm install

# Build the plugin
npm run build

# Start development environment with Grafana
GRAFANA_IMAGE=jayclifford349/grafana-oss GRAFANA_VERSION=docs npm run server

Development Environment

The plugin includes a complete development setup:

# Development build with watch mode
npm run dev

# Run tests
npm run test

# Lint code
npm run lint

# Type checking
npm run typecheck

# Build for production
npm run build

Project Structure Deep Dive

For a comprehensive understanding of the project structure, see:

Key Technologies

  • βš›οΈ React - UI framework with hooks and context
  • 🎭 Grafana Scenes - Scene-based architecture for complex UIs
  • πŸ“˜ TypeScript - Full type safety and IntelliSense
  • πŸ’… Emotion - CSS-in-JS with theme integration
  • 🎨 Grafana UI - Consistent component library
  • πŸ”— Extension Points - Grafana plugin integration system

Configuration Options

API Integration

// Configure external recommendation service
export const RECOMMENDER_SERVICE_URL = 'http://localhost:8080';

// Custom documentation endpoints
const customEndpoints = {
  apiUrl: 'https://docs.company.com/api',
  apiKey: 'your-secret-key'
};

For detailed configuration options, see the App Configuration README.

API Reference

Core Classes

For detailed API documentation, see:

Troubleshooting

Common Issues

Content Loading Problems

// Debug content fetching
console.log('Fetching strategies attempted:', strategies);
console.log('Final content result:', content);

// Check network connectivity
fetch(url).then(response => console.log('Direct access:', response.status));

Recommendation Service Issues

// Verify service connectivity
const healthCheck = await fetch(`${RECOMMENDER_SERVICE_URL}/health`);
console.log('Recommender service status:', healthCheck.status);

// Debug context payload
console.log('Context sent to recommender:', payload);

Cache Issues

// Clear all caches manually
clearLearningJourneyCache();
localStorage.clear();
window.location.reload();

Performance Optimization

Bundle Size Analysis

# Analyze bundle composition
npm run build:analyze

# Check for duplicate dependencies
npm run dedupe

Content Loading Optimization

// Implement progressive loading
const preloadNextMilestone = async (content: LearningJourneyContent) => {
  const nextUrl = getNextMilestoneUrl(content);
  if (nextUrl) {
    // Pre-fetch in background
    fetchLearningJourneyContent(nextUrl);
  }
};

For more troubleshooting information, see the component-specific documentation linked above.

Debugging Tips

Enable Verbose Logging

// Add to console for detailed logging
localStorage.setItem('docs-plugin-debug', 'true');

// Monitor scene state changes
console.log('Scene state:', sceneObject.state);

Network Request Debugging

// Monitor all fetch requests
const originalFetch = window.fetch;
window.fetch = (...args) => {
  console.log('Fetch request:', args);
  return originalFetch(...args);
};

Contributing

Code Style

  • TypeScript: Strict mode enabled
  • React: Functional components with hooks
  • Styling: Emotion CSS-in-JS with Grafana theme
  • Testing: Jest + React Testing Library

Submission Guidelines

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Test your changes thoroughly
  4. Commit with conventional commit messages
  5. Push to your branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Development Workflow

# 1. Set up development environment
npm install
npm run dev

# 2. Make changes and test
npm run test
npm run typecheck
npm run lint

# 3. Build and verify
npm run build
npm run server # Test in Grafana

# 4. Submit changes
git add .
git commit -m "feat: add custom content source support"
git push origin feature/custom-content

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.


Quick Links

About

A documentation plugin that provides contextual learning journeys directly within the Grafana interface.

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages