Skip to content
This repository was archived by the owner on Aug 1, 2026. It is now read-only.

feat(web): land on the wiki's own index.md instead of its first page - #91

Merged
protonspy merged 1 commit into
mainfrom
feat/wiki-index-home
Jul 28, 2026
Merged

feat(web): land on the wiki's own index.md instead of its first page#91
protonspy merged 1 commit into
mainfrom
feat/wiki-index-home

Conversation

@protonspy

@protonspy protonspy commented Jul 28, 2026

Copy link
Copy Markdown
Owner

What

#/wiki (no slug) rendered pages[0] — whichever page sorted first in the catalog. The wiki's front door is now docs/wiki/index.md itself: the authored catalog, with its prose, its categories and its order.

How

  • WikiView.tsx — a route with no slug (or a slug that no longer exists) renders the new WikiIndexPane. It loads docs/wiki/index.md through the same hardened /api/file route the pages use, lifts the leading # heading into the pane header (so it doesn't render twice), and shows page count plus an N not in index.md badge with the orphans listed in the footer. Fallbacks are unchanged: no index.md → first page; no pages at all → the existing empty state.
  • Index entries become routes. [Title](pages/<slug>.md) is rewritten to #/wiki/<slug> when the slug exists, and to a [[slug]] citation token when it does not — so a stale entry renders as a broken chip (no such wiki page, the same verdict csdd wiki lint gives) instead of a dead link to a file.
  • Markdown.tsx#/… hrefs are in-app navigation and stay in the tab; only real external links still open one.
  • Rail.tsx — an Index row above the catalog, active when no page is selected.

No Go changes: /api/wiki already exposed has_index, and /api/file already serves docs/wiki/index.md.

Verification

  • npm --prefix internal/web/frontend run typecheck clean; vite build succeeds (bundle not committed — internal/web/dist/.gitkeep restored).
  • Scaffolded a throwaway workspace (csdd init + csdd wiki init, two pages, one stale index entry) and checked the three endpoints the pane depends on: /api/wiki reports has_index: true with both pages in_index, /api/file?path=docs/wiki/index.md serves the catalog, and /api/ref resolves [[cqrs]]#/wiki/cqrs while [[gone]] comes back broken.
  • Not verified in a browser: the rendered pane was not opened visually.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ARBSaXgJ7ssW1hvpy6r64y

Summary by CodeRabbit

  • New Features

    • Added support for authored wiki index pages, including page listings and links to available wiki content.
    • Added an “Index” entry to the wiki navigation rail when an index is available.
    • Highlighted wiki pages listed in the index that are not yet available.
  • Bug Fixes

    • Fixed in-app hash links so they open within the current tab instead of opening as external links in a new tab.

`#/wiki` opened whichever page sorted first, which made the front door an
accident of the catalog's order. It now renders docs/wiki/index.md — the
page the author actually writes to say what the knowledge base is.

The index links pages as files (`[Title](pages/slug.md)`), so entries are
rewritten before rendering: a slug that exists becomes an in-app route, one
that does not becomes a citation token, so a stale entry reads as the broken
reference it is rather than a dead file link. Markdown keeps `#/…` links in
the tab, and the rail carries an Index row above the catalog.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARBSaXgJ7ssW1hvpy6r64y
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The wiki frontend now supports authored index pages. WikiView loads and renders docs/wiki/index.md, WikiRail exposes an Index entry when available, and hash links remain in-tab navigation links.

Changes

Wiki index navigation

Layer / File(s) Summary
Index page selection
internal/web/frontend/src/components/WikiView.tsx
WikiView renders the authored index for missing or unknown slugs when has_index is true, otherwise retaining first-page fallback behavior.
Index content rendering
internal/web/frontend/src/components/WikiView.tsx, internal/web/frontend/src/components/Markdown.tsx
WikiIndexPane loads and renders docs/wiki/index.md, extracts its leading heading, rewrites known and stale page links, and displays pages absent from the index. Hash links render without outbound-link attributes.
Index rail navigation
internal/web/frontend/src/components/Rail.tsx
WikiRail tracks has_index, renders an Index row linking to #/wiki, and places the empty-state placeholder beside the index block.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WikiRail
  participant WikiView
  participant api.wiki
  participant WikiIndexPane
  participant api.file
  participant Markdown
  WikiRail->>api.wiki: load wiki metadata and pages
  api.wiki-->>WikiRail: return has_index and page list
  WikiRail->>WikiView: navigate to `#/wiki`
  WikiView->>WikiIndexPane: render authored index
  WikiIndexPane->>api.file: load docs/wiki/index.md
  api.file-->>WikiIndexPane: return markdown
  WikiIndexPane->>Markdown: render rewritten links and body
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: wiki routes now open the authored index.md instead of the first page.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wiki-index-home

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/web/frontend/src/components/Rail.tsx`:
- Around line 150-158: Update the wiki overview error handler in the useEffect
callback to reset hasIndex to false alongside clearing pages when api.wiki()
fails, preventing stale index state after an unsuccessful refresh.

In `@internal/web/frontend/src/components/WikiView.tsx`:
- Around line 126-131: Restrict INDEX_ENTRY_RE in rewriteIndexEntries to match
only local pages links beginning with pages/ or ./pages/, removing the arbitrary
prefix that captures external URLs. Split the markdown into code and non-code
regions, leave inline and fenced code regions unchanged, and apply the existing
replacement logic only to non-code parts before joining them back together.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1de2a972-a8f4-402b-befb-fb933f924a97

📥 Commits

Reviewing files that changed from the base of the PR and between ac03f09 and e3c86e1.

📒 Files selected for processing (3)
  • internal/web/frontend/src/components/Markdown.tsx
  • internal/web/frontend/src/components/Rail.tsx
  • internal/web/frontend/src/components/WikiView.tsx

Comment on lines 150 to 158
useEffect(() => {
api
.wiki()
.then((w) => {
setPages(w?.pages ?? [])
setCategories(w?.categories ?? [])
setHasIndex(!!w?.has_index)
})
.catch(() => setPages([]))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear hasIndex when the overview refresh fails.

After a prior successful load, this handler clears pages but retains hasIndex; the rail can show an obsolete Index row after the index is removed or the request fails.

Proposed fix
-      .catch(() => setPages([]))
+      .catch(() => {
+        setPages([])
+        setCategories([])
+        setHasIndex(false)
+      })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
api
.wiki()
.then((w) => {
setPages(w?.pages ?? [])
setCategories(w?.categories ?? [])
setHasIndex(!!w?.has_index)
})
.catch(() => setPages([]))
useEffect(() => {
api
.wiki()
.then((w) => {
setPages(w?.pages ?? [])
setCategories(w?.categories ?? [])
setHasIndex(!!w?.has_index)
})
.catch(() => {
setPages([])
setCategories([])
setHasIndex(false)
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/web/frontend/src/components/Rail.tsx` around lines 150 - 158, Update
the wiki overview error handler in the useEffect callback to reset hasIndex to
false alongside clearing pages when api.wiki() fails, preventing stale index
state after an unsuccessful refresh.

Comment on lines +126 to +131
const INDEX_ENTRY_RE = /\]\(\s*(?:\.\/)?(?:[^)\s]*\/)?pages\/([^)\s/]+)\.md\s*\)/g

function rewriteIndexEntries(markdown: string, known: Set<string>): string {
return markdown.replace(INDEX_ENTRY_RE, (_m, slug: string) =>
known.has(slug) ? `](${href('wiki', slug)})` : `](ref:[[${slug}]])`,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restrict rewriting to actual local Markdown links.

The arbitrary optional prefix matches external URLs such as https://example.com/pages/foo.md, incorrectly hijacking them into wiki routes. The global replacement also rewrites examples inside inline/fenced code. Only process pages/... or ./pages/... links outside code regions.

Proposed fix
-const INDEX_ENTRY_RE = /\]\(\s*(?:\.\/)?(?:[^)\s]*\/)?pages\/([^)\s/]+)\.md\s*\)/g
+const INDEX_ENTRY_RE = /\]\(\s*(?:\.\/)?pages\/([^)\s/]+)\.md\s*\)/g

 function rewriteIndexEntries(markdown: string, known: Set<string>): string {
-  return markdown.replace(INDEX_ENTRY_RE, (_m, slug: string) =>
-    known.has(slug) ? `](${href('wiki', slug)})` : `](ref:[[${slug}]])`,
-  )
+  const parts = markdown.split(/(```[\s\S]*?```|`[^`\n]*`)/g)
+  return parts
+    .map((part, i) =>
+      i % 2 === 1
+        ? part
+        : part.replace(INDEX_ENTRY_RE, (_m, slug: string) =>
+            known.has(slug) ? `](${href('wiki', slug)})` : `](ref:[[${slug}]])`,
+          ),
+    )
+    .join('')
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const INDEX_ENTRY_RE = /\]\(\s*(?:\.\/)?(?:[^)\s]*\/)?pages\/([^)\s/]+)\.md\s*\)/g
function rewriteIndexEntries(markdown: string, known: Set<string>): string {
return markdown.replace(INDEX_ENTRY_RE, (_m, slug: string) =>
known.has(slug) ? `](${href('wiki', slug)})` : `](ref:[[${slug}]])`,
)
const INDEX_ENTRY_RE = /\]\(\s*(?:\.\/)?pages\/([^)\s/]+)\.md\s*\)/g
function rewriteIndexEntries(markdown: string, known: Set<string>): string {
const parts = markdown.split(/(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/web/frontend/src/components/WikiView.tsx` around lines 126 - 131,
Restrict INDEX_ENTRY_RE in rewriteIndexEntries to match only local pages links
beginning with pages/ or ./pages/, removing the arbitrary prefix that captures
external URLs. Split the markdown into code and non-code regions, leave inline
and fenced code regions unchanged, and apply the existing replacement logic only
to non-code parts before joining them back together.

@protonspy
protonspy merged commit f9e54d0 into main Jul 28, 2026
7 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant