prvng_platform/crates/provisioning-daemon/ui/templates/pages/workspaces.html

125 lines
4.5 KiB
HTML

{% extends "base.html" %}
{% import "macros/ui.html" as m %}
{% block title %}Workspaces{% endblock %}
{% block nav_workspaces %}btn-active{% endblock %}
{% block content %}
<div class="flex items-center gap-3 mb-2">
<h1 class="text-2xl font-bold font-mono">Workspaces</h1>
<button id="toggle-features-btn" class="btn btn-xs btn-ghost font-mono ml-auto text-base-content/40"
onclick="toggleAllFeatures()">features ↕</button>
</div>
<p class="text-base-content/50 text-sm mb-6">
Infrastructure workspaces — only workspaces with a <code class="font-mono">card.ncl</code> are shown.
</p>
{% if not ws_root_set %}
<div class="alert alert-warning mb-6">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-2.194-.833-2.964 0L3.232 16.5c-.77.833.192 2.5 1.732 2.5z"/>
</svg>
<span>
<strong>Workspaces root not set.</strong>
Start with <code class="font-mono">--project-root /path/to/provisioning</code>
or <code class="font-mono">--workspaces-root /path/to/workspaces</code>.
</span>
</div>
{% endif %}
{% if infra_workspaces %}
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3">
{% for ws in infra_workspaces %}
<div class="card bg-base-200 shadow hover:bg-base-300 transition-colors">
<div class="card-body p-4">
{# ── Header ── #}
<div class="flex items-center gap-2">
<a href="/ui/workspaces/{{ ws.name }}" class="font-mono font-semibold text-primary text-sm truncate hover:underline">
{{ ws.name }}
</a>
<div class="ml-auto flex items-center gap-1 flex-shrink-0">
{% if ws.status == "Active" %}
<span class="badge badge-success badge-xs">active</span>
{% elif ws.status %}
<span class="badge badge-ghost badge-xs font-mono">{{ ws.status | lower }}</span>
{% endif %}
</div>
</div>
{# ── Tagline ── #}
{% if ws.tagline %}
<p class="text-xs text-base-content/60 mt-1 leading-relaxed">{{ ws.tagline }}</p>
{% endif %}
{# ── Tags ── #}
{% if ws.tags %}
<div class="flex flex-wrap gap-1 mt-2">
{% for tag in ws.tags %}
<span class="badge badge-ghost badge-xs font-mono text-base-content/50">{{ tag }}</span>
{% endfor %}
</div>
{% endif %}
{# ── Environments ── #}
{% if ws.environments %}
<div class="flex gap-1 flex-wrap mt-2">
{% for env in ws.environments %}
<span class="badge badge-outline badge-xs font-mono text-primary/60">{{ env }}</span>
{% endfor %}
</div>
{% endif %}
{# ── Features (collapsible) ── #}
{% if ws.features %}
<details class="mt-3 ws-features">
<summary class="text-xs text-base-content/30 cursor-pointer hover:text-base-content/60 select-none font-mono list-none flex items-center gap-1">
<span class="ws-feat-arrow"></span>
<span>{{ ws.features | length }} features</span>
</summary>
<ul class="mt-2 space-y-0.5 pl-2 border-l border-base-content/10">
{% for feat in ws.features %}
<li class="text-xs text-base-content/50 font-mono">{{ feat }}</li>
{% endfor %}
</ul>
</details>
{% endif %}
<div class="mt-3 text-right">
<a href="/ui/workspaces/{{ ws.name }}" class="text-xs text-base-content/30 hover:text-primary">View →</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% elif ws_root_set %}
<div class="alert">
<span class="text-sm font-mono">No infra workspaces found (no <code>card.ncl</code> detected).</span>
</div>
{% endif %}
<div class="mt-6 flex gap-2">
<a href="/ui/tools/workspace_list" class="btn btn-ghost btn-xs font-mono">workspace_list tool</a>
<a href="/ui/ontology" class="btn btn-ghost btn-xs">Domain graph</a>
</div>
<script>
// Sync the rotate arrow when details open/close.
document.querySelectorAll('.ws-features').forEach(d => {
d.addEventListener('toggle', () => {
const arrow = d.querySelector('.ws-feat-arrow');
if (arrow) arrow.textContent = d.open ? '▼' : '▶';
});
});
let featuresOpen = false;
function toggleAllFeatures() {
featuresOpen = !featuresOpen;
document.querySelectorAll('.ws-features').forEach(d => {
d.open = featuresOpen;
const arrow = d.querySelector('.ws-feat-arrow');
if (arrow) arrow.textContent = featuresOpen ? '▼' : '▶';
});
}
</script>
{% endblock %}