Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 018e323ed4 | |||
| 0e1805b8ce |
@@ -23,6 +23,47 @@ skip versions are the composition of each intervening adjacent
|
|||||||
release's steps in order — no A-to-B path is pre-computed beyond
|
release's steps in order — no A-to-B path is pre-computed beyond
|
||||||
that.
|
that.
|
||||||
|
|
||||||
|
## 0.2.2 — 2026-05-26
|
||||||
|
|
||||||
|
**Patch — no operator action required.** Rebuild the frontend and
|
||||||
|
restart per the routine deploy steps; no `.env` changes, no schema
|
||||||
|
changes, no behavior changes a deployment would notice in steady
|
||||||
|
state beyond the fix below.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Mermaid blocks rendered as raw code on `/philosophy`.**
|
||||||
|
`frontend/src/components/Philosophy.jsx` parsed PHILOSOPHY.md with
|
||||||
|
the bare `marked` import and `dangerouslySetInnerHTML`, so
|
||||||
|
```` ```mermaid ```` fences fell through as `<pre>` blocks rather
|
||||||
|
than rendered diagrams. Swapped to `MarkdownPreview`, which already
|
||||||
|
carries the lazy mermaid loader + SVG render path used by the RFC
|
||||||
|
body view, so the philosophy surface now renders mermaid the same
|
||||||
|
way RFC bodies do. Pre-existing gap, surfaced when a deployment
|
||||||
|
authored a mermaid block in its `PHILOSOPHY_PATH` override.
|
||||||
|
|
||||||
|
## 0.2.1 — 2026-05-26
|
||||||
|
|
||||||
|
**Patch — no operator action required.** Rebuild the frontend and
|
||||||
|
restart per the routine deploy steps; no `.env` changes, no schema
|
||||||
|
changes, no behavior changes a deployment would notice in steady
|
||||||
|
state.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **PR view blank page (React #310).** `frontend/src/components/PRView.jsx`
|
||||||
|
declared its `threadsByKind` `useMemo` *after* the early-return
|
||||||
|
guard for the loading state (`if (!pr) return …`). On first mount
|
||||||
|
`pr` was null so the early return fired and 14 hooks were called;
|
||||||
|
on the second render `pr` was populated and execution reached the
|
||||||
|
`useMemo`, calling 15 hooks — violating the Rules of Hooks and
|
||||||
|
unmounting the page subtree (blank screen). The `useMemo` is now
|
||||||
|
declared above the early returns with optional-chaining on `pr`,
|
||||||
|
keeping the hook count stable between the loading and loaded
|
||||||
|
renders. Pre-existing bug in the post-Contribute-rewrite PR view;
|
||||||
|
surfaced in production by 0.2.0's graduation merge race fix
|
||||||
|
enabling the workflow that opens this code path.
|
||||||
|
|
||||||
## 0.2.0 — 2026-05-26
|
## 0.2.0 — 2026-05-26
|
||||||
|
|
||||||
**Breaking config change.** The frontend now requires
|
**Breaking config change.** The frontend now requires
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "rfc-app-frontend",
|
"name": "rfc-app-frontend",
|
||||||
"version": "0.1.0",
|
"version": "0.2.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rfc-app-frontend",
|
"name": "rfc-app-frontend",
|
||||||
"version": "0.1.0",
|
"version": "0.2.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/commands": "^6.10.3",
|
"@codemirror/commands": "^6.10.3",
|
||||||
"@codemirror/lang-markdown": "^6.5.0",
|
"@codemirror/lang-markdown": "^6.5.0",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "rfc-app-frontend",
|
"name": "rfc-app-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.0",
|
"version": "0.2.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -143,6 +143,19 @@ export default function PRView({ viewer }) {
|
|||||||
}
|
}
|
||||||
}, [slug, prNumber, reviewText, reviewDraft, refresh])
|
}, [slug, prNumber, reviewText, reviewDraft, refresh])
|
||||||
|
|
||||||
|
// §10.6: split messages by thread kind for the visual distinction
|
||||||
|
// §10.4 requires. Within each kind, sort by id for chronological
|
||||||
|
// order. Declared above the early returns below so the hook count
|
||||||
|
// stays stable between the loading render (pr == null) and the
|
||||||
|
// loaded render (Rules of Hooks — React #310 otherwise).
|
||||||
|
const threadsByKind = useMemo(() => {
|
||||||
|
const out = { chat: [], review: [], flag: [] }
|
||||||
|
for (const t of pr?.threads || []) {
|
||||||
|
out[t.thread_kind]?.push(t)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}, [pr?.threads])
|
||||||
|
|
||||||
// ── render ─────────────────────────────────────────────────────
|
// ── render ─────────────────────────────────────────────────────
|
||||||
if (error) return <article className="entry-view"><p>Error: {error}</p></article>
|
if (error) return <article className="entry-view"><p>Error: {error}</p></article>
|
||||||
if (!pr) return <article className="entry-view">Loading PR…</article>
|
if (!pr) return <article className="entry-view">Loading PR…</article>
|
||||||
@@ -154,17 +167,6 @@ export default function PRView({ viewer }) {
|
|||||||
const supersededBy = pr.superseded_by_pr_number
|
const supersededBy = pr.superseded_by_pr_number
|
||||||
const supersedes = pr.supersedes_pr_number
|
const supersedes = pr.supersedes_pr_number
|
||||||
|
|
||||||
// §10.6: split messages by thread kind for the visual distinction
|
|
||||||
// §10.4 requires. Within each kind, sort by id for chronological
|
|
||||||
// order.
|
|
||||||
const threadsByKind = useMemo(() => {
|
|
||||||
const out = { chat: [], review: [], flag: [] }
|
|
||||||
for (const t of pr.threads || []) {
|
|
||||||
out[t.thread_kind]?.push(t)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}, [pr.threads])
|
|
||||||
|
|
||||||
const seenSha = pr.seen?.last_seen_commit_sha
|
const seenSha = pr.seen?.last_seen_commit_sha
|
||||||
const seenMsgId = pr.seen?.last_seen_message_id || 0
|
const seenMsgId = pr.seen?.last_seen_message_id || 0
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import { marked } from 'marked'
|
import MarkdownPreview from './MarkdownPreview.jsx'
|
||||||
import { getPhilosophy } from '../api.js'
|
import { getPhilosophy } from '../api.js'
|
||||||
|
|
||||||
export default function Philosophy({ authenticated }) {
|
export default function Philosophy({ authenticated }) {
|
||||||
@@ -33,8 +33,6 @@ export default function Philosophy({ authenticated }) {
|
|||||||
return () => { active = false }
|
return () => { active = false }
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const html = body ? marked.parse(body) : ''
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="philosophy-page">
|
<div className="philosophy-page">
|
||||||
<header className="philosophy-header">
|
<header className="philosophy-header">
|
||||||
@@ -53,7 +51,7 @@ export default function Philosophy({ authenticated }) {
|
|||||||
{loading && <p className="muted">Loading…</p>}
|
{loading && <p className="muted">Loading…</p>}
|
||||||
{error && <p className="error">Could not load the philosophy: {error}</p>}
|
{error && <p className="error">Could not load the philosophy: {error}</p>}
|
||||||
{!loading && !error && (
|
{!loading && !error && (
|
||||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
<MarkdownPreview content={body} />
|
||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user