Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 33 additions & 7 deletions .github/skills/dev-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This invokes `robotframework_dashboard/main.py:main()` directly and supports all
## Common Dev Invocations

```powershell
# Generate a dashboard from a single output.xml into robot_dashboard.html (default output)
# Generate a dashboard from a single output.xml (default output: robot_dashboard_<timestamp>.html)
python -m robotframework_dashboard.main -o results\output-20251225-172034.xml

# Generate from multiple output.xml files
Expand All @@ -30,18 +30,20 @@ python -m robotframework_dashboard.main -o results\output-20251225-172034.xml re
# Generate from a folder of output.xml files
python -m robotframework_dashboard.main -f results

# Use a custom output HTML path
python -m robotframework_dashboard.main -o results\output-20251225-172034.xml -g my_dashboard.html
# Use a custom output HTML path (-n / --namedashboard, NOT -g)
python -m robotframework_dashboard.main -o results\output-20251225-172034.xml -n my_dashboard.html

# Offline mode (no CDN, all dependencies embedded)
python -m robotframework_dashboard.main -o results\output-20251225-172034.xml --offlinedependencies
```

`-g` / `--generatedashboard` is a **boolean** flag (default `True`) — it does not take a filename. Use `-n` / `--namedashboard` for a custom output path.

## Generated Output

- Default output file: `robot_dashboard.html` in the current working directory.
- Default output file: `robot_dashboard_<yyyymmdd-hhmmss>.html` in the current working directory, unless `-n` is given.
- The file is fully self-contained: all JS, CSS, and data are embedded — open it directly in a browser with no server needed.
- Re-running does **not** overwrite an existing database by default. To reset, delete the `.db` file (default: `robot_database.db`) before re-running, or specify a different `-d DATABASEPATH`.
- Default database file: `robot_results.db`. Re-running does **not** overwrite an existing database. To reset, delete the `.db` file before re-running, or specify a different `-d DATABASEPATH`.

## Inspecting JS/CSS Changes

Expand All @@ -61,7 +63,31 @@ Template changes in `robotframework_dashboard/templates/dashboard.html` also req
```powershell
# 1. Make changes to js/, css/, or templates/
# 2. Regenerate (delete old db if you want a clean state)
Remove-Item robot_database.db -ErrorAction SilentlyContinue
python -m robotframework_dashboard.main -o results\output-20251225-172034.xml
Remove-Item robot_results.db -ErrorAction SilentlyContinue
python -m robotframework_dashboard.main -o results\output-20251225-172034.xml -n robot_dashboard.html
# 3. Open robot_dashboard.html in a browser
```

## Validating JS/CSS/Template Changes

After any change to `robotframework_dashboard/js/`, `css/`, or `templates/dashboard.html`, **regenerate the HTML** to confirm the bundler/template still produce valid output — importing a module and checking it doesn't throw is not enough, since most bugs (rendering, layout, icon sizing, click handlers) only show up in the bundled, rendered output.

The repo ships with output.xml fixtures under `tests/` that work as a ready-made dataset:

```bash
# From the repo root (Git Bash / Linux / macOS)
python -m robotframework_dashboard.main -f tests -n robot_dashboard.html
```

```powershell
# Windows PowerShell
python -m robotframework_dashboard.main -f tests -n robot_dashboard.html
```

**Do not install or drive a browser (Playwright, Selenium, etc.) as part of this validation.** Regenerating the dashboard without errors, plus a careful read of the diff, is the AI agent's verification step. Actually opening `robot_dashboard.html` and exercising the feature in a browser (e.g. enabling "Customize Layout" to check edit-mode controls) is a manual step left to the developer — describe what to click and what to expect instead of trying to automate it.

Clean up the generated `robot_dashboard.html` and `robot_results.db` once done if they aren't meant to be committed.

### Gotcha: trailing backslashes in paths (Git Bash)

In Git Bash on Windows, a Windows-style path with a trailing backslash (e.g. `-f .\tests\`) gets the backslash interpreted as escaping the following space — this silently merges the *next* argument (and its value) into the path, so e.g. `-f .\tests\ -n robot_dashboard.html` is parsed as a single `-f` value and `-n`/`robot_dashboard.html` are swallowed, silently falling back to defaults. Use a forward-slash path with no trailing slash instead: `-f tests`.
152 changes: 152 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# robotframework-dashboard — Copilot Instructions

This file gives AI agents and contributors the context needed to work effectively in this codebase.

## How to Use the Skills Files

Before starting work on any non-trivial task, read the relevant skill file from `.github/skills/`. Each file contains deep domain knowledge that avoids re-exploring the codebase from scratch. Use the table in the **Skills** section below to pick the right one(s). Read the skill file with a file-read tool before making any changes.

---

## Commands

Use the project scripts — do NOT invoke the underlying tools directly (the scripts set coverage paths, artifact dirs, and parallelism). `.bat` for Windows, `.sh` for Linux/macOS.

| Task | Windows | Linux / macOS |
|---|---|---|
| JS unit tests | `scripts\javascript-tests.bat` | `bash scripts/javascript-tests.sh` |
| Python unit tests | `scripts\python-tests.bat` | `bash scripts/python-tests.sh` |
| Robot acceptance tests | `scripts\robot-tests.bat` | `bash scripts/robot-tests.sh` |
| Generate dashboard for testing | `python -m robotframework_dashboard.main -n robot_dashboard -f tests` | same |
| Docs build | `npm run docs:build` | `npm run docs:build` |
| Docs dev server | `npm run docs:dev` | `npm run docs:dev` |

**Generate dashboard for testing** runs the package directly (no install) against the `tests/` output.xml fixtures, producing `robot_dashboard.html`. Use this to validate any JS/CSS/template/Python pipeline change — open the HTML to confirm rendering, layout, and click handlers. A clean import/syntax check is not sufficient; bundled-output bugs only surface here.

---

## Project Purpose

`robotframework-dashboard` is a Python CLI tool that reads Robot Framework `output.xml` execution results, stores them in a SQLite database, and generates a fully self-contained HTML dashboard with interactive charts, tables, and filters. No web server is required to view the output — a single `.html` file contains all data, JS, and CSS.

---

## Core Pipeline: Python CLI → HTML Template → JavaScript

The entire system is this three-stage pipeline:

```
1. PYTHON CLI
output.xml files
└─► OutputProcessor (robot.api ResultVisitor)
└─► SQLite database (runs / suites / tests / keywords tables)

2. HTML TEMPLATE
database.get_data()
└─► DashboardGenerator
├─► DependencyProcessor: merges all JS modules (topological sort) → inline <script>
├─► DependencyProcessor: merges all CSS files → inline <style>
├─► CDN or offline dependency tags
├─► Data encoded as: JSON → zlib compress → base64 → string literal in HTML
└─► templates/dashboard.html (string placeholder replacement) → robot_dashboard.html

3. JAVASCRIPT (runs in the browser)
js/variables/data.js decodes the embedded base64 data back to JS arrays
└─► Chart.js charts, DataTables, filters, layout — all from local data, zero server calls
```

The output is a **single `.html` file** that is entirely self-contained. All Robot Framework data is embedded as compressed strings; all JS and CSS is inlined.

---

## Entry Points

| File | Role |
|---|---|
| `robotframework_dashboard/main.py` | CLI entry point (`robotdashboard` command) |
| `robotframework_dashboard/robotdashboard.py` | `RobotDashboard` class — orchestrates all 5 pipeline steps |
| `robotframework_dashboard/arguments.py` | `ArgumentParser` wrapping `argparse` |
| `robotframework_dashboard/processors.py` | `OutputProcessor` + 4 `ResultVisitor` subclasses |
| `robotframework_dashboard/database.py` | Built-in SQLite implementation |
| `robotframework_dashboard/abstractdb.py` | `AbstractDatabaseProcessor` ABC (custom DB backends) |
| `robotframework_dashboard/queries.py` | All SQL strings as module-level constants |
| `robotframework_dashboard/dashboard.py` | `DashboardGenerator` — template rendering |
| `robotframework_dashboard/dependencies.py` | `DependencyProcessor` — JS/CSS inlining and CDN switching |
| `robotframework_dashboard/server.py` | Optional FastAPI server (`--server` flag) |

---

## JavaScript and CSS

All frontend source lives under `robotframework_dashboard/js/` and `robotframework_dashboard/css/`. **There is no Node.js bundler (no webpack, Vite, or Rollup) for the dashboard.** Bundling is done in Python by `DependencyProcessor` at HTML generation time.

Key JS directories:

| Path | Contents |
|---|---|
| `js/variables/` | Global state, data decoding, settings, graph registry |
| `js/graph_creation/` | Chart.js setup per tab (overview, run, suite, test, keyword, compare, tables) |
| `js/graph_data/` | Data transformation modules that feed Chart.js |
| `js/main.js` | Startup entry — imports and calls all setup functions |
| `js/admin_page/` | Separate JS bundle for the server's `/admin` page only |

See `.github/skills/js-bundling.md` for details on how JS modules are resolved, ordered, and embedded.

---

## HTML Templates

Templates live in `robotframework_dashboard/templates/`. They use simple string placeholder tokens (not Jinja2):

- `templates/dashboard.html` → generates `robot_dashboard.html`
- `templates/admin.html` → generates the server's `/admin` page

Key placeholders: `<!-- placeholder_javascript -->`, `<!-- placeholder_css -->`, `<!-- placeholder_dependencies -->`, `"placeholder_runs"`, `"placeholder_suites"`, `"placeholder_tests"`, `"placeholder_keywords"`.

---

## Database

- Built-in: SQLite via `database.py`. Tables: `runs`, `suites`, `tests`, `keywords`.
- Custom backends: implement `AbstractDatabaseProcessor` from `abstractdb.py`, point to it with `--databaseclass`.
- Run identity: `run_start` timestamp. Duplicate runs are silently skipped.
- Schema migrations are handled inline at DB open time via `ALTER TABLE ADD COLUMN`.

---

## Skills

The `.github/skills/` directory contains domain-specific knowledge files:

| Skill file | When to use |
|---|---|
| `.github/skills/project-architecture.md` | Understanding how components connect and navigating the codebase |
| `.github/skills/dashboard.md` | Dashboard pages, Chart.js graphs, chart types, graph data/creation modules |
| `.github/skills/js-bundling.md` | How JS/CSS is bundled and embedded into the HTML (no Node.js bundler) |
| `.github/skills/js-feature-patterns.md` | **End-to-end patterns for adding new JS features**: custom widget checklist, GridStack item lifecycle, undo/redo snapshot pattern, localStorage-only keys |
| `.github/skills/conventions-and-gotchas.md` | Edge cases, run identity, offline mode, custom DBs, server auth model |
| `.github/skills/coding-style.md` | Python/JS/CSS style conventions |
| `.github/skills/workflows.md` | CLI usage, running tests, server mode, docs site |
| `.github/skills/dev-workflow.md` | How to run the tool locally during development (no install required), dev loop for JS/CSS/template changes |
| `.github/skills/robotframework-tests.md` | Test suite structure, pabot parallelism, how to add tests |
| `.github/skills/fix-robot-tests.md` | **Step-by-step workflow for fixing failing robot tests** — parsing output.xml, updating stale screenshots, fixing tab-navigation timeouts, using Docker to regenerate references |
| `.github/skills/python-unit-tests.md` | Python unit tests (pytest, coverage, test layout, fixtures) |
| `.github/skills/javascript-unit-tests.md` | JavaScript unit tests (Vitest, mocking patterns, which modules are testable) |
| `.github/skills/server-api.md` | All REST endpoints, authentication, log linking, auto-update behavior |
| `.github/skills/filtering-and-settings.md` | Filter pipeline, settings object, localStorage persistence, layout/GridStack system, **filter profiles** (data structure, all profile functions, merge modal) |
| `.github/skills/listener-integration.md` | Listener script (`robotdashboardlistener.py`), all listener arguments, pabot/RobotCode usage, server endpoints called |
| `.github/skills/documentation.md` | All documentation locations (docs/, README.md, CONTRIBUTING.md, setup.py), page map, and checklist for keeping docs in sync when features change |
| `.github/skills/js-patterns.md` | How JavaScript code is currently structured in this project: module layout, variable placement, naming patterns, GridStack/Chart.js usage |
| `.github/skills/js-coding-standards.md` | Rules for writing JavaScript: naming conventions, where to put variables, function patterns, scope, localStorage, DOM access |
| `.github/skills/release-actions.md` | **Step-by-step release workflow** — bump version, update test fixtures, regenerate example dashboard/database, update changelog, produce Slack notes |

---

## Key Rules for AI Agents

- **Never break the placeholder token names** in templates. Replacement is positional string substitution.
- **When adding a new JS module**, import it from an existing module so `DependencyProcessor` can discover it via the dependency graph. The topological sort handles ordering automatically.
- **Data always flows**: parse → DB → HTML. Do not bypass the pipeline.
- **`package.json` is for the VitePress docs site only.** It has nothing to do with bundling dashboard JS.
- **Offline mode** (`--offlinedependencies`) reads from `robotframework_dashboard/dependencies/`. Keep local copies in sync when upgrading library versions.
- **Validate JS/CSS/template changes by regenerating and opening the HTML** — see `.github/skills/dev-workflow.md` ("Validating JS/CSS/Template Changes"). A clean `import`/syntax check is not sufficient; rendering, layout, and click-handler bugs only surface in the bundled output. The `tests/` folder has ready-made output.xml fixtures: `python -m robotframework_dashboard.main -f tests -n robot_dashboard.html`.
22 changes: 15 additions & 7 deletions docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The video above walks through three examples of how you can tailor the dashboard
See how you can reshape the main dashboard layout by:

- resizing individual graphs
- reordering graphs within their sections
- reordering graphs within their sections, either by dragging or using the **Move to First** / **Move to Last** buttons (see [Move to First / Move to Last](#12-move-to-first-move-to-last))
- hiding graphs you don’t want to display
- rearranging entire sections to match your preferred workflow
- it is also possible to combine all sections into a single unified view, see [Settings - Defaults Tab](/settings#defaults-settings-defaults-tab), for the details
Expand Down Expand Up @@ -100,9 +100,11 @@ Stat widgets display a single KPI value (executed runs, failed tests, etc.) as a
To add a stat widget:

1. Enter **Customize view** mode.
2. Click the **"+ Add stat widget"** tile that appears at the bottom of the target grid.
3. In the popup, choose the **statistic** to display and optionally pick a **text color** and **background color**.
4. Click **Add** — the widget is placed in the grid and can be dragged or resized like any other graph.
2. Click the **"Add stat widget"** icon in the section header (top-right of the section, next to the other header icons) of the target grid.
3. The popup has two tabs:
- **Single** — choose one **statistic** to display and optionally pick a **text color** and **background color**, then click **Add Widget**.
- **Multiple** — toggle on any number of stats from the list (use **Toggle all** to select/deselect everything at once), optionally adjust each widget's title, and either use **random colors** or pick a shared **text color** and **background color** for all of them. Click **Add Selected Widgets** to add them all at once.
4. The widget(s) are placed in the grid and can be dragged or resized like any other graph.
5. Click **Save** to persist the layout to localStorage.

To remove a stat widget, enter Customize view mode and click the **✕** button in its top-right corner.
Expand All @@ -116,7 +118,7 @@ Custom section dividers are full-width horizontal bars you can place anywhere in
To add a section divider:

1. Enter **Customize view** mode.
2. Click the **"+ Add custom section"** tile at the bottom of the unified grid.
2. Click the **"Add custom section"** icon in the unified section's header (top-right, next to the other header icons).
3. In the popup, enter a **title** (up to 60 characters) and optionally choose a **text color** and **background color**.
4. Click **Add** — the divider spans the full grid width and can be dragged to any row.
5. Click **Save** to persist the layout to localStorage.
Expand All @@ -132,7 +134,7 @@ Link widgets are clickable tiles you can add to any dashboard section grid. Each
To add a link widget:

1. Enter **Customize view** mode.
2. Click the **"+ Add link widget"** tile that appears at the bottom of the target grid.
2. Click the **"Add link widget"** icon in the section header (top-right of the section, next to the other header icons) of the target grid.
3. In the popup, enter a **label** (the display name shown on the tile) and the **URL** to navigate to.
4. Check **Open in new tab** if you want the link to open in a new browser tab. Leave it unchecked to navigate in the current tab.
5. Optionally pick a **text color** and **background color** for the tile.
Expand All @@ -143,4 +145,10 @@ To remove a link widget, enter Customize view mode and click the **✕** button

> Link widgets are not clickable while Customize view mode is active — this prevents accidental navigation while you are rearranging the layout. Clicking the tile in normal mode navigates to the configured URL.

Link widgets are stored in localStorage and survive page reloads.
Link widgets are stored in localStorage and survive page reloads.

## 12. Move to First / Move to Last

While in **Customize view** mode, every graph and widget shows a **"Move to First"** and **"Move to Last"** control alongside its other edit icons. Clicking one of these instantly moves the item to the start or end of its grid, without needing to drag it past every other item in between.

This works for regular graphs as well as stat widgets, link widgets, and custom section dividers. Click **Save** to persist the new order to localStorage.
16 changes: 16 additions & 0 deletions robotframework_dashboard/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ body {
.boxplot-graph:hover svg,
.shown-graph:hover svg,
.hidden-graph:hover svg,
.move-to-first-graph:hover svg,
.move-to-last-graph:hover svg,
.add-stat-widget-header:hover svg,
.add-link-widget-header:hover svg,
.add-section-header:hover svg,
.delete-custom-stat-widget:hover svg,
.delete-custom-link-widget:hover svg,
.delete-custom-section:hover svg,
.shown-section:hover svg,
.hidden-section:hover svg,
.collapse-icon:hover svg,
Expand Down Expand Up @@ -188,6 +196,14 @@ body.lock-scroll {
.boxplot-graph,
.shown-graph,
.hidden-graph,
.move-to-first-graph,
.move-to-last-graph,
.add-stat-widget-header,
.add-link-widget-header,
.add-section-header,
.delete-custom-stat-widget,
.delete-custom-link-widget,
.delete-custom-section,
.shown-section,
.hidden-section,
.move-up-table,
Expand Down
Loading
Loading