Consume coop fragments for unified navigation
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m2s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m2s
Add middleware to fetch nav-tree, auth-menu, and cart-mini fragments from coop apps. Update base.html to render coop nav with fallback. Add internal URL env vars for Docker networking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -147,6 +147,47 @@ def create_app() -> FastAPI:
|
||||
)
|
||||
return response
|
||||
|
||||
# Coop fragment pre-fetch — inject nav-tree, auth-menu, cart-mini into
|
||||
# request.state for full-page HTML renders. Skips HTMX, API, and
|
||||
# internal paths. Failures are silent (fragments default to "").
|
||||
_FRAG_SKIP = ("/auth/", "/api/", "/internal/", "/health", "/oembed",
|
||||
"/ipfs/", "/download/", "/inbox", "/static/")
|
||||
|
||||
@app.middleware("http")
|
||||
async def coop_fragments_middleware(request: Request, call_next):
|
||||
path = request.url.path
|
||||
if (
|
||||
request.method != "GET"
|
||||
or any(path.startswith(p) for p in _FRAG_SKIP)
|
||||
or request.headers.get("hx-request")
|
||||
or request.headers.get(fragments.FRAGMENT_HEADER)
|
||||
):
|
||||
request.state.nav_tree_html = ""
|
||||
request.state.auth_menu_html = ""
|
||||
request.state.cart_mini_html = ""
|
||||
return await call_next(request)
|
||||
|
||||
from artdag_common.fragments import fetch_fragments as _fetch_frags
|
||||
|
||||
user = get_user_from_cookie(request)
|
||||
auth_params = {"email": user.email} if user else {}
|
||||
nav_params = {"app_name": "artdag", "path": path}
|
||||
|
||||
try:
|
||||
nav_tree_html, auth_menu_html, cart_mini_html = await _fetch_frags([
|
||||
("blog", "nav-tree", nav_params),
|
||||
("account", "auth-menu", auth_params or None),
|
||||
("cart", "cart-mini", None),
|
||||
])
|
||||
except Exception:
|
||||
nav_tree_html = auth_menu_html = cart_mini_html = ""
|
||||
|
||||
request.state.nav_tree_html = nav_tree_html
|
||||
request.state.auth_menu_html = auth_menu_html
|
||||
request.state.cart_mini_html = cart_mini_html
|
||||
|
||||
return await call_next(request)
|
||||
|
||||
# Initialize Jinja2 templates
|
||||
template_dir = Path(__file__).parent / "templates"
|
||||
app.state.templates = create_jinja_env(template_dir)
|
||||
|
||||
@@ -14,20 +14,36 @@ Art-DAG
|
||||
<a href="/media" class="text-gray-300 hover:text-white {% if active_tab == 'media' %}text-white font-medium{% endif %}">Media{% if nav_counts and nav_counts.media %} ({{ nav_counts.media }}){% endif %}</a>
|
||||
<a href="/storage" class="text-gray-300 hover:text-white {% if active_tab == 'storage' %}text-white font-medium{% endif %}">Storage{% if nav_counts and nav_counts.storage %} ({{ nav_counts.storage }}){% endif %}</a>
|
||||
<a href="/download/client" class="text-gray-300 hover:text-white" title="Download CLI client">Client</a>
|
||||
{% if request and request.state.nav_tree_html %}
|
||||
<span class="text-gray-600">|</span>
|
||||
<div class="flex items-center space-x-3 [&_a]:text-gray-400 [&_a:hover]:text-white [&_a]:text-sm [&_a]:no-underline [&_img]:w-5 [&_img]:h-5">
|
||||
{{ request.state.nav_tree_html | safe }}
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-gray-600">|</span>
|
||||
<a href="https://blog.rose-ash.com/" class="text-gray-400 hover:text-white text-sm">Blog</a>
|
||||
<a href="https://market.rose-ash.com/" class="text-gray-400 hover:text-white text-sm">Market</a>
|
||||
<a href="https://account.rose-ash.com/" class="text-gray-400 hover:text-white text-sm">Account</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
{% block nav_right %}
|
||||
{% if user %}
|
||||
<div class="flex items-center space-x-4">
|
||||
{% if request and request.state.cart_mini_html %}
|
||||
<div class="[&_a]:text-gray-300 [&_a:hover]:text-white">
|
||||
{{ request.state.cart_mini_html | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request and request.state.auth_menu_html %}
|
||||
<div class="[&_a]:text-gray-300 [&_a:hover]:text-white [&_a]:text-sm [&_a]:no-underline">
|
||||
{{ request.state.auth_menu_html | safe }}
|
||||
</div>
|
||||
{% elif user %}
|
||||
<span class="text-gray-400">{{ user.username }}</span>
|
||||
<a href="/auth/logout" class="text-gray-300 hover:text-white">Logout</a>
|
||||
{% else %}
|
||||
<a href="/auth/login" class="text-gray-300 hover:text-white">Login</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="/auth/login" class="text-gray-300 hover:text-white">Login</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -73,6 +73,10 @@ services:
|
||||
# IPFS_API multiaddr - used for all IPFS operations (add, cat, pin)
|
||||
- IPFS_API=/dns/ipfs/tcp/5001
|
||||
- CACHE_DIR=/data/cache
|
||||
# Coop app internal URLs for fragment composition
|
||||
- INTERNAL_URL_BLOG=http://blog:8000
|
||||
- INTERNAL_URL_CART=http://cart:8000
|
||||
- INTERNAL_URL_ACCOUNT=http://account:8000
|
||||
# DATABASE_URL, ADMIN_TOKEN, ARTDAG_CLUSTER_KEY,
|
||||
# L2_SERVER, L2_DOMAIN, IPFS_GATEWAY_URL from .env file
|
||||
healthcheck:
|
||||
|
||||
Reference in New Issue
Block a user