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
4 changes: 2 additions & 2 deletions scripts/browser_smoke.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async function copy(id) {
page.on('response', r => { if (r.status() >= 400) report.http_errors.push({ url: r.url(), status: r.status() }); });
page.on('dialog', async dialog => { report.page_errors.push(`Dialog: ${dialog.message()}`); await dialog.dismiss(); });
await step('Application identity, assets and initial rendering', async () => {
const r = await page.goto(base, { waitUntil: 'networkidle', timeout: 120000 });
const r = await page.goto(base + '/studio/', { waitUntil: 'networkidle', timeout: 120000 });
assert.equal(r.status(), 200);
assert.match(await page.title(), /Simplex Normal Forms Studio/);
await rendered('ai-source-tokens', '62');
Expand All @@ -125,7 +125,7 @@ async function copy(id) {
assert.equal(health.status(), 200);
report.health = await health.json();
assert.equal(report.health.service, 'smplxnf-studio');
for (const [urlPath, local] of [['/', 'web/templates/index.html'], ['/static/app.js', 'web/static/app.js'], ['/static/style.css', 'web/static/style.css']]) {
for (const [urlPath, local] of [['/studio/', 'web/templates/index.html'], ['/', 'web/templates/overview.html'], ['/static/app.js', 'web/static/app.js'], ['/static/style.css', 'web/static/style.css']]) {
const response = await context.request.get(base + urlPath);
assert.equal(response.status(), 200);
const bytes = await response.body();
Expand Down
4 changes: 2 additions & 2 deletions tests/test_web_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ def test_healthz_endpoint(self) -> None:
self.assertEqual(payload.get("version"), "0.1.0")

def test_index_html_renders_all_tabs(self) -> None:
"""Verifies GET / renders the landing SPA with all five workbench tabs."""
response = self.client.get("/")
"""Verifies GET /studio/ renders the studio SPA with all five workbench tabs."""
response = self.client.get("/studio/")
self.assertEqual(response.status_code, 200)
self.assertIn("text/html", response.headers.get("content-type", ""))
html = response.text
Expand Down
15 changes: 13 additions & 2 deletions web/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from fastapi import Body, FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel, Field
Expand Down Expand Up @@ -942,6 +942,17 @@ def project_chunks(chunks: Sequence[Mapping[str, Any]]) -> List[Dict[str, Any]]:
# Frontend SPA Route
# =============================================================================

@app.get("/", response_class=HTMLResponse)
@app.get("/", include_in_schema=False)
async def serve_overview() -> FileResponse:
"""One-screen BQNF overview. Plain HTML, not rendered through Jinja."""
return FileResponse(templates_dir / "overview.html", media_type="text/html")


@app.get("/studio", include_in_schema=False)
async def redirect_studio() -> RedirectResponse:
return RedirectResponse("/studio/", status_code=308)


@app.get("/studio/", response_class=HTMLResponse)
async def serve_index(request: Request):
return templates.TemplateResponse(request=request, name="index.html")
2 changes: 1 addition & 1 deletion web/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<div class="an-header__in">
<a class="an-brand" href="https://anomalon.com/"><svg viewBox="0 0 22 22" aria-hidden="true"><rect x="1" y="1" width="20" height="20" rx="4" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M6 15.5 11 6l5 9.5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/><circle cx="11" cy="12.6" r="1.7" fill="var(--an-accent)"/></svg>Anomalon <span class="an-brand__tool">/ Simplex-NF Studio</span></a>
<button class="an-btn an-btn--ghost an-nav__toggle" aria-expanded="false" aria-controls="an-nav">Menu</button>
<nav class="an-nav" id="an-nav" aria-label="Site"><a href="#quickstart" onclick="switchTab('quickstart')">Quickstart</a><a href="https://github.com/dbccpage/simplex-normal-forms">Source</a><a href="https://anomalon.com/">All tools</a></nav>
<nav class="an-nav" id="an-nav" aria-label="Site"><a href="/">Overview</a><a href="#quickstart" onclick="switchTab('quickstart')">Quickstart</a><a href="https://github.com/dbccpage/simplex-normal-forms">Source</a><a href="https://anomalon.com/">All tools</a></nav>
</div>
</header>

Expand Down
Loading
Loading