Rename Cache to Media in navigation, add login to home page

- Change navigation tab from "Cache" to "Media"
- Change /cache list route to /media
- Add Recipes link to home page navigation
- Add Login button to home page
- Update all active_tab="cache" to active_tab="media"
- Update "Back to cache" links to "Back to media"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-08 15:18:40 +00:00
parent 5e6353d150
commit c0a98dd0ff

View File

@@ -357,8 +357,10 @@ HOME_HTML = """
<div class="max-w-4xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
<nav class="flex flex-wrap gap-3 mb-8 p-4 bg-dark-700 rounded-lg">
<a href="/runs" class="px-4 py-2 bg-dark-500 hover:bg-dark-600 rounded-md text-blue-400 hover:text-blue-300 font-medium transition-colors">Runs</a>
<a href="/cache" class="px-4 py-2 bg-dark-500 hover:bg-dark-600 rounded-md text-blue-400 hover:text-blue-300 font-medium transition-colors">Cache</a>
<a href="/recipes" class="px-4 py-2 bg-dark-500 hover:bg-dark-600 rounded-md text-blue-400 hover:text-blue-300 font-medium transition-colors">Recipes</a>
<a href="/media" class="px-4 py-2 bg-dark-500 hover:bg-dark-600 rounded-md text-blue-400 hover:text-blue-300 font-medium transition-colors">Media</a>
<a href="/docs" class="px-4 py-2 bg-dark-500 hover:bg-dark-600 rounded-md text-blue-400 hover:text-blue-300 font-medium transition-colors">API Docs</a>
<a href="/login" class="ml-auto px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-md text-white font-medium transition-colors">Login</a>
</nav>
<h1 class="text-3xl font-bold text-white border-b border-dark-500 pb-4 mb-6">Art DAG L1 Server</h1>
@@ -386,7 +388,8 @@ HOME_HTML = """
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">POST</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/runs</code></td><td class="px-4 py-2 border border-dark-500">Start a rendering run</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">GET</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/runs</code></td><td class="px-4 py-2 border border-dark-500">List all runs</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">GET</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/runs/{run_id}</code></td><td class="px-4 py-2 border border-dark-500">Get run status</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">GET</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/cache</code></td><td class="px-4 py-2 border border-dark-500">List cached content hashes</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">GET</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/media</code></td><td class="px-4 py-2 border border-dark-500">List media items</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">GET</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/recipes</code></td><td class="px-4 py-2 border border-dark-500">List recipes</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">GET</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/cache/{hash}</code></td><td class="px-4 py-2 border border-dark-500">Download cached content</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">POST</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/cache/upload</code></td><td class="px-4 py-2 border border-dark-500">Upload file to cache</td></tr>
<tr class="bg-dark-800"><td class="px-4 py-2 border border-dark-500">GET</td><td class="px-4 py-2 border border-dark-500"><code class="bg-dark-600 px-2 py-0.5 rounded text-blue-300">/assets</code></td><td class="px-4 py-2 border border-dark-500">List known assets</td></tr>
@@ -1594,19 +1597,19 @@ async def cache_detail(content_hash: str, request: Request):
if not cache_path:
if wants_html(request):
content = f'<p class="text-red-400">Content not found: {content_hash}</p>'
return HTMLResponse(render_page("Not Found", content, current_user, active_tab="cache"), status_code=404)
return HTMLResponse(render_page("Not Found", content, current_user, active_tab="media"), status_code=404)
raise HTTPException(404, f"Content {content_hash} not in cache")
if wants_html(request):
if not current_user:
content = '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login</a> to view cached content.</p>'
return HTMLResponse(render_page("Login Required", content, current_user, active_tab="cache"), status_code=401)
return HTMLResponse(render_page("Login Required", content, current_user, active_tab="media"), status_code=401)
# Check user has access
user_hashes = get_user_cache_hashes(current_user)
if content_hash not in user_hashes:
content = '<p class="text-red-400 py-8 text-center">Access denied.</p>'
return HTMLResponse(render_page("Access Denied", content, current_user, active_tab="cache"), status_code=403)
return HTMLResponse(render_page("Access Denied", content, current_user, active_tab="media"), status_code=403)
media_type = detect_media_type(cache_path)
file_size = cache_path.stat().st_size
@@ -1626,11 +1629,11 @@ async def cache_detail(content_hash: str, request: Request):
media_html = f'<p class="text-gray-400">Unknown file type. <a href="/cache/{content_hash}" download class="text-blue-400 hover:text-blue-300">Download file</a></p>'
content = f'''
<a href="/cache" class="inline-flex items-center text-blue-400 hover:text-blue-300 mb-6">
<a href="/media" class="inline-flex items-center text-blue-400 hover:text-blue-300 mb-6">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
Back to cache
Back to media
</a>
<div class="bg-dark-700 rounded-lg p-6">
@@ -1681,7 +1684,7 @@ async def cache_detail(content_hash: str, request: Request):
</div>
'''
return HTMLResponse(render_page(f"Cache: {content_hash[:16]}...", content, current_user, active_tab="cache"))
return HTMLResponse(render_page(f"Cache: {content_hash[:16]}...", content, current_user, active_tab="media"))
# JSON response - return metadata
meta = load_cache_meta(content_hash)
@@ -2091,8 +2094,8 @@ async def ui_republish_cache(content_hash: str, request: Request):
return '<div class="bg-green-900/50 border border-green-700 text-green-300 px-4 py-3 rounded-lg mb-4">Updated on L2!</div>'
@app.get("/cache")
async def list_cache(
@app.get("/media")
async def list_media(
request: Request,
page: int = 1,
limit: int = 20,
@@ -2100,14 +2103,14 @@ async def list_cache(
collection: Optional[str] = None,
tag: Optional[str] = None
):
"""List cached content. HTML for browsers (with infinite scroll), JSON for APIs (with pagination)."""
"""List media items. HTML for browsers (with infinite scroll), JSON for APIs (with pagination)."""
current_user = get_user_from_cookie(request)
if wants_html(request):
# Require login for HTML cache view
# Require login for HTML media view
if not current_user:
content = '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login</a> to see cached content.</p>'
return HTMLResponse(render_page("Cache", content, current_user, active_tab="cache"))
content = '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login</a> to see media.</p>'
return HTMLResponse(render_page("Media", content, current_user, active_tab="media"))
# Get hashes owned by/associated with this user
user_hashes = get_user_cache_hashes(current_user)
@@ -2165,7 +2168,7 @@ async def list_cache(
filter_msg = f" in collection '{collection}'"
elif tag:
filter_msg = f" with tag '{tag}'"
content = f'<p class="text-gray-400 py-8 text-center">No cached files{filter_msg}. Upload files or run effects to see them here.</p>'
content = f'<p class="text-gray-400 py-8 text-center">No media{filter_msg}. Upload files or run effects to see them here.</p>'
else:
return HTMLResponse("") # Empty for infinite scroll
else:
@@ -2216,7 +2219,7 @@ async def list_cache(
if tag:
query_params += f"&tag={tag}"
html_parts.append(f'''
<div hx-get="/cache?{query_params}" hx-trigger="revealed" hx-swap="afterend">
<div hx-get="/media?{query_params}" hx-trigger="revealed" hx-swap="afterend">
<p class="py-4 text-center text-gray-400">Loading more...</p>
</div>
''')
@@ -2233,20 +2236,20 @@ async def list_cache(
if tag:
query_params += f"&tag={tag}"
infinite_scroll_trigger = f'''
<div hx-get="/cache?{query_params}" hx-trigger="revealed" hx-swap="afterend">
<div hx-get="/media?{query_params}" hx-trigger="revealed" hx-swap="afterend">
<p class="py-4 text-center text-gray-400">Loading more...</p>
</div>
'''
content = f'''
<h2 class="text-xl font-semibold text-white mb-6">Cache ({total} items)</h2>
<h2 class="text-xl font-semibold text-white mb-6">Media ({total} items)</h2>
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{''.join(html_parts)}
{infinite_scroll_trigger}
</div>
'''
return HTMLResponse(render_page("Cache", content, current_user, active_tab="cache"))
return HTMLResponse(render_page("Media", content, current_user, active_tab="media"))
# JSON response for APIs - list all hashes with optional pagination
all_hashes = [cf.content_hash for cf in cache_manager.list_all()]
@@ -2373,7 +2376,7 @@ async def ui_discard_cache(content_hash: str, request: Request):
return '''
<div class="bg-green-900/50 border border-green-700 text-green-300 px-4 py-3 rounded-lg mb-4">
Item discarded. <a href="/cache" class="underline">Back to cache</a>
Item discarded. <a href="/media" class="underline">Back to media</a>
</div>
'''
@@ -2952,7 +2955,7 @@ def render_page(title: str, content: str, username: Optional[str] = None, active
runs_active = "border-b-2 border-blue-500 text-white" if active_tab == "runs" else "text-gray-400 hover:text-white"
recipes_active = "border-b-2 border-blue-500 text-white" if active_tab == "recipes" else "text-gray-400 hover:text-white"
cache_active = "border-b-2 border-blue-500 text-white" if active_tab == "cache" else "text-gray-400 hover:text-white"
media_active = "border-b-2 border-blue-500 text-white" if active_tab == "media" else "text-gray-400 hover:text-white"
return f"""
<!DOCTYPE html>
@@ -2975,7 +2978,7 @@ def render_page(title: str, content: str, username: Optional[str] = None, active
<nav class="flex gap-6 mb-6 border-b border-dark-500 pb-0">
<a href="/runs" class="pb-3 px-1 font-medium transition-colors {runs_active}">Runs</a>
<a href="/recipes" class="pb-3 px-1 font-medium transition-colors {recipes_active}">Recipes</a>
<a href="/cache" class="pb-3 px-1 font-medium transition-colors {cache_active}">Cache</a>
<a href="/media" class="pb-3 px-1 font-medium transition-colors {media_active}">Media</a>
</nav>
<main>