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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ These GitHub repositories provide supplementary resources for Rush Stack:
| Folder | Description |
| ------ | -----------|
| [/apps/lockfile-explorer-web](./apps/lockfile-explorer-web/) | Rush Lockfile Explorer: helper project for building the React web application component |
| [/apps/rush-serve-dashboard](./apps/rush-serve-dashboard/) | Web dashboard for the Rush serve WebSocket protocol |
| [/build-tests-samples/heft-node-basic-tutorial](./build-tests-samples/heft-node-basic-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft |
| [/build-tests-samples/heft-node-jest-tutorial](./build-tests-samples/heft-node-jest-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft |
| [/build-tests-samples/heft-node-rig-tutorial](./build-tests-samples/heft-node-rig-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft |
Expand Down
10 changes: 10 additions & 0 deletions apps/rush-serve-dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# @rushstack/rush-serve-dashboard

This private package provides the browser dashboard for `@rushstack/rush-serve-plugin`. Its emitted ESM assets are copied into the plugin package during the plugin build; it is not published independently.

The dashboard displays Rush operation state in table and graph views, exposes controls supported by the plugin's WebSocket protocol, and shows operation logs. See the [rush-serve-plugin documentation](../../rush-plugins/rush-serve-plugin/README.md#dashboard) for configuration
and usage.

## Development

From this folder, run `rushx start` to start the Heft development server or `rushx build` to build and test the project. From the repository root, run `rush build --to @rushstack/rush-serve-plugin` to validate the dashboard and the consuming plugin together.
212 changes: 212 additions & 0 deletions apps/rush-serve-dashboard/assets/dashboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -->
<!-- See LICENSE in the project root for license information. -->

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Rush Serve Dashboard</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- Codicon (VS Code icon font) -->
<link
rel="stylesheet"
href="https://microsoft.github.io/vscode-codicons/dist/codicon.css"
crossorigin="anonymous"
/>
</head>
<body>
<div id="top-bar">
<div id="overall-status">
<span id="status-emoji" aria-hidden="true">⏸️</span>
<span id="status-pill">Disconnected</span>
</div>
<div id="app-title">Rush Serve Dashboard</div>
<div id="actions">
<!-- Primary execution controls first -->
<button id="play-pause-btn" disabled aria-label="Automatic mode" title="Toggle automatic/manual">
<span class="codicon codicon-debug-pause" aria-hidden="true"></span>
</button>
<button id="execute-btn" disabled aria-label="Run once" title="Run once">
<span class="codicon codicon-debug-continue" aria-hidden="true"></span>
</button>
<button id="abort-execution-btn" disabled aria-label="Stop execution" title="Stop execution">
<span class="codicon codicon-debug-stop" aria-hidden="true"></span>
</button>
<!-- Logging toggles next -->
<button id="debug-btn" disabled aria-label="Toggle debug" title="Toggle debug output">
<span class="codicon codicon-debug" aria-hidden="true"></span>
</button>
<button id="verbose-btn" disabled aria-label="Toggle verbose" title="Toggle verbose logging">
<span class="codicon codicon-info" aria-hidden="true"></span>
</button>
<label id="parallelism-label">
<span>Parallelism</span>
<input type="number" id="parallelism-input" min="1" step="1" disabled />
</label>
</div>
<div id="graph-state"></div>
<div id="view-controls">
<label><input type="radio" name="view" value="table" checked /> Table</label>
<label><input type="radio" name="view" value="graph" /> Graph</label>
<label
>Filter
<select id="filter-select">
<option value="all">All</option>
<option value="failed-warn">Failed / Warnings</option>
</select>
</label>
<label id="search-label">
Search
<input id="name-search" type="search" placeholder="operations" />
<button
id="select-visible-btn"
type="button"
title="Select all visible operations"
aria-label="Select visible operations"
>
<span class="codicon codicon-check-all" aria-hidden="true"></span>
</button>
</label>
</div>
<div id="top-bar-spacer"></div>
<form id="connection-form">
<button
id="connect-btn"
type="button"
title="Connect to WebSocket"
aria-label="Connect"
data-state="disconnected"
>
<span class="codicon codicon-plug" aria-hidden="true"></span>
</button>
<button
id="toggle-terminal-btn"
type="button"
title="Show/Hide Terminal"
aria-label="Toggle terminal"
aria-pressed="false"
>
<span class="codicon codicon-terminal" aria-hidden="true"></span>
</button>
</form>
</div>
<!-- Selection action bar (appears only when selection non-empty) -->
<div id="selection-bar">
<div id="selection-heading">
<span id="view-heading-text">Dependency Graph</span>
<button id="clear-selection-btn" title="Clear selection">
<span class="codicon codicon-close" aria-hidden="true"></span>
<span id="selection-count">0 selected</span>
</button>
</div>
<div id="selection-actions">
<button id="invalidate-btn" title="Mark selected operations dirty">
<span class="codicon codicon-debug-restart" aria-hidden="true"></span>
<span>Mark Dirty</span>
</button>
<button id="close-runners-btn" title="Close runners for selection">
<span class="codicon codicon-close-all" aria-hidden="true"></span>
<span>Close Runners</span>
</button>
<button
id="set-enabled-default-btn"
title="Set selected to run if dependencies change"
aria-label="Set selected to run if dependencies change"
>
🟢 Enabled
</button>
<button
id="set-enabled-ignore-deps-btn"
title="Ignore dependency changes (run only if files in the same project change)"
aria-label="Ignore dependency changes (run only if files in the same project change)"
>
🟡 Ignore Deps
</button>
<button
id="set-enabled-disabled-btn"
title="Set selected to never run"
aria-label="Set selected to never run"
>
🔴 Disabled
</button>
<button
id="selection-mode-btn"
title="Toggle between safe (dependency aware) and unsafe (direct) enable state application"
aria-label="Toggle selection enable mode"
data-mode="safe"
>
Mode: Safe
</button>
<button id="expand-deps-btn" title="Add all (recursive) dependencies of selection">+ Deps</button>
<button id="expand-consumers-btn" title="Add all (recursive) consumers of selection">
+ Consumers
</button>
</div>
</div>
<!-- Terminal pane: minimizable, output-only virtual terminal for terminal-chunk events -->
<div id="content-wrap">
<div id="main">
<div id="left" data-view="table">
<div id="operations-table-container">
<table id="operations-table">
<thead></thead>
<tbody></tbody>
</table>
</div>
<div id="table-stats"></div>
</div>
<div id="right" data-view="graph">
<!-- Graph heading removed; now integrated into selection bar -->
<div id="graph-container">
<div id="phase-pane">
<h3>Phases</h3>
<div id="phase-groups"></div>
</div>
<div id="graph-wrapper">
<div id="graph">
<svg id="edges">
<defs>
<marker
id="arrowhead"
markerWidth="10"
markerHeight="7"
refX="8"
refY="3.5"
orient="auto"
>
<polygon points="0 0, 10 3.5, 0 7" fill="#4b5563" />
</marker>
</defs>
</svg>
</div>
<div id="graph-legend"></div>
</div>
</div>
</div>
</div>
<div id="resizer" role="separator" aria-orientation="vertical"></div>
<div id="terminal" aria-live="polite">
<div id="terminal-header">
<div id="terminal-title">Terminal Output</div>
<div id="terminal-controls">
<!-- Clear: icon-only button matching other action buttons -->
<button id="term-clear-btn" title="Clear terminal" aria-label="Clear terminal">
<span class="codicon codicon-trash" aria-hidden="true"></span>
</button>
<!-- Auto-scroll: toggle icon button (aria-pressed reflects state) -->
<button
id="term-autoscroll-btn"
title="Toggle auto-scroll"
aria-label="Toggle auto-scroll"
aria-pressed="true"
>
<span id="term-autoscroll-icon" class="codicon codicon-arrow-both" aria-hidden="true"></span>
</button>
<input id="term-autoscroll" type="checkbox" checked />
</div>
</div>
<div id="terminal-body" aria-hidden="false"></div>
</div>
</div>
</body>
</html>
4 changes: 4 additions & 0 deletions apps/rush-serve-dashboard/config/heft.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",
"extends": "local-web-rig/profiles/app/config/heft.json"
}
6 changes: 6 additions & 0 deletions apps/rush-serve-dashboard/config/rig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",

"rigPackageName": "local-web-rig",
"rigProfile": "app"
}
16 changes: 16 additions & 0 deletions apps/rush-serve-dashboard/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

const webAppProfile = require('local-web-rig/profiles/app/includes/eslint/flat/profile/web-app');

module.exports = [
...webAppProfile,
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parserOptions: {
tsconfigRootDir: __dirname
}
}
}
];
24 changes: 24 additions & 0 deletions apps/rush-serve-dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@rushstack/rush-serve-dashboard",
"version": "0.0.0",
"description": "Web dashboard for the Rush serve WebSocket protocol",
"private": true,
"license": "MIT",
"scripts": {
"build": "heft test --clean",
"start": "heft start",
"_phase:build": "heft run --only build -- --clean",
"_phase:test": "heft run --only test -- --clean"
},
"dependencies": {
"tslib": "~2.8.1"
},
"devDependencies": {
"@rushstack/heft": "workspace:*",
"eslint": "~9.37.0",
"local-web-rig": "workspace:*"
Comment thread
mojaza marked this conversation as resolved.
},
"sideEffects": [
"**/*.css"
]
}
Loading