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
33 changes: 33 additions & 0 deletions .github/workflows/bug-tracker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Bug tracker validation
on:
pull_request:
push:
branches: [feature/unified-bug-tracker]
permissions:
contents: read
jobs:
website:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- uses: pnpm/action-setup@v4
with:
version: 9.0.0
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- uses: actions/cache@v4
with:
path: .image-cache
key: image-optimization-cache-${{ runner.os }}-${{ github.run_id }}
restore-keys: image-optimization-cache-${{ runner.os }}-
- run: pnpm build
- run: pnpm exec playwright install --with-deps chromium
- run: pnpm test:bugs
- uses: actions/upload-artifact@v4
if: always()
with:
name: bug-tracker-browser-results
path: test-results
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ social-card-template.html
# Windows artifacts
nul
Thumbs.db
test-results/
playwright-report/
*.tmp

# Version control temp files
Expand Down
27 changes: 27 additions & 0 deletions BUG_TRACKER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Unified OpenHD bug tracker

The website uses `https://openhd.tech/api/bugs` by default. Set `BUG_REPORT_API_URL` at build time to change it. No credentials belong in the website. This extends PR #12; FleetControl owns the backend, so the unused Python requirements are removed.

`/bugs` supports search, type, status, repository and component filters with server pagination. GitHub search caps results at 1,000; narrow filters for older results. GitHub data is cached for one minute, with rate-limit backoff. `/bugs/detail?repo=OpenHD/OpenHD&number=123` shows descriptions as escaped text, metadata, related pull requests and the original link.

`/bugs/report` requires title, description, reproduction steps, version, component, Air hardware, Ground hardware, and both archives. ZIP, tar.gz and tgz are accepted; 50 MiB per archive is the default. The separately marked incomplete-diagnostics workflow requires an explanation of at least 20 characters, holds reports privately for administrator approval, and accepts any available archive.

Turnstile is verified server-side. Uploads show progress, and the browser keeps the submission token in sessionStorage during pending or interrupted requests. Accepted reports return HTTP 202; the client then polls for the GitHub number and URL. Email failures do not affect issue creation.

Private archives are available only after a FleetControl administrator signs in at `https://openhd.tech/#/admin/bugs`. The website sends no cross-origin session cookies and receives no permanent download links. Logs are never sent to GitHub or attached to email.

## Deployment

FleetControl's `docs/bug-tracker.md` contains the API contract, configuration and recovery instructions. Configure the API first, then validate this branch with Node 24 and pnpm 9:

```
pnpm install --frozen-lockfile
pnpm typecheck
pnpm build
pnpm exec playwright install chromium
pnpm test:bugs
```

Playwright uses a built website and mocked integration responses; it does not prove live GitHub creation, human verification or email delivery. Production activation requires the live smoke test in the backend documentation.

Website pushes to `main` publish under `/staging/`; pushes to `online` publish the public root. Feature-branch and PR validation do not deploy. Set the Turnstile widget hostname to `openhdfpv.org` and allow that exact HTTPS origin on FleetControl. The submit button stays disabled until the API reports that all required backend integrations are configured.
7 changes: 7 additions & 0 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const config: Config = {
baseUrl: isStaging ? '/staging/' : '/',
noIndex: isStaging,

customFields: {bugReportApiUrl: process.env.BUG_REPORT_API_URL || 'https://openhd.tech/api/bugs'},

// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: 'OpenHD', // Usually your GitHub org/user name.
Expand Down Expand Up @@ -366,6 +368,11 @@ const config: Config = {
label: 'Changelog',
position: 'left',
},
{
to: '/bugs',
label: 'Bug Tracker',
position: 'left',
},
{
type: 'docsVersionDropdown',
position: 'right',
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"typecheck": "tsc"
"typecheck": "tsc",
"test:bugs": "playwright test"
},
"dependencies": {
"@acid-info/docusaurus-og": "1.0.4-alpha.0",
Expand All @@ -40,6 +41,7 @@
"@docusaurus/module-type-aliases": "3.10.2",
"@docusaurus/tsconfig": "3.10.2",
"@docusaurus/types": "3.10.2",
"@playwright/test": "1.58.2",
"glob": "^13.0.6",
"sharp": "^0.35.3",
"typescript": "~5.7.3"
Expand Down
12 changes: 12 additions & 0 deletions patches/@acid-info__docusaurus-og@1.0.4-alpha.0.patch
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,15 @@ index 106fe9ff80bf9d122a4f43c7e8fa0a849d01a215..567138766af782e53e3c0d4e4a74b5e8
+ };
}
exports.PagesPlugin = PagesPlugin;
diff --git a/lib/server/document.js b/lib/server/document.js
--- a/lib/server/document.js
+++ b/lib/server/document.js
@@ -40,7 +40,7 @@ class Document {
}
load = async () => {
const htmlString = await fsp.readFile(this.path, 'utf-8');
- this.root = (0, node_html_parser_1.parse)(htmlString);
+ this.root = (0, node_html_parser_1.parse)(htmlString, { parseNoneClosedTags: true });
this.loaded = true;
};
write = async () => {
10 changes: 10 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {defineConfig} from '@playwright/test';
export default defineConfig({
testDir: './tests', testMatch: '**/bugs.spec.ts', timeout: 30000,
use: {baseURL: 'http://127.0.0.1:3017', trace: 'retain-on-failure'},
projects: [
{name: 'desktop', use: {viewport: {width: 1440, height: 1000}, colorScheme: 'light'}},
{name: 'mobile-dark', use: {viewport: {width: 390, height: 844}, colorScheme: 'dark'}},
],
webServer: {command: 'pnpm exec docusaurus serve --host 127.0.0.1 --port 3017 --no-open', url: 'http://127.0.0.1:3017/bugs', reuseExistingServer: false, timeout: 120000},
});
44 changes: 41 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/components/BugApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
export type BugEntry = { id: number; number: number; title: string; body?: string; state: string; html_url: string; updated_at: string; repository_url: string; pull_request?: {merged_at?: string}; merged?: boolean; labels: {name: string}[]; related?: BugEntry[] };
export function useBugApi() {
const {siteConfig} = useDocusaurusContext();
const endpoint = String(siteConfig.customFields?.bugReportApiUrl || '').replace(/\/$/, '');
return endpoint.startsWith('https://') ? endpoint : '';
}
export function entryType(entry: BugEntry) { return entry.pull_request ? 'Pull Request' : entry.labels.some(label => label.name === 'website-report') ? 'Bug' : 'GitHub Issue'; }
export function labelValue(entry: BugEntry, prefix: string) { return entry.labels.find(label => label.name.startsWith(`${prefix}:`))?.name.slice(prefix.length + 1) || '—'; }
export async function bugFetch(url: string, options?: RequestInit) {
const response = await fetch(url, options);
const result = await response.json();
if (!response.ok) {const error = new Error((result.message || 'The tracker is temporarily unavailable.') + (response.headers.get('Retry-After') ? ` Retry in ${response.headers.get('Retry-After')} seconds.` : '')); Object.assign(error, {status: response.status}); throw error;}
return result;
}
3 changes: 3 additions & 0 deletions src/pages/bugs.module.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading