469 lines
28 KiB
HTML
469 lines
28 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ idea.id }}: {{ idea.title }} - ThinkStorm{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- Idea Header Banner -->
|
|
{% if idea.lifecycle_state == 'TRASHED' %}
|
|
<div class="glass-card" style="padding:1.25rem 1.5rem; margin-bottom:1.5rem; border-color:rgba(239,68,68,0.4); background:rgba(239,68,68,0.08); display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:1rem;">
|
|
<div style="display:flex; align-items:center; gap:0.75rem;">
|
|
<span style="font-size:1.5rem;">🗑️</span>
|
|
<div>
|
|
<strong style="color:#f87171; font-size:1.05rem;">This idea is in the Trash Bin</strong>
|
|
<p style="color:var(--text-secondary); font-size:0.85rem; margin:0;">It is withheld from incubation catalogs until restored or permanently emptied.</p>
|
|
</div>
|
|
</div>
|
|
<div style="display:flex; gap:0.5rem;">
|
|
<button onclick="restoreIdea('{{ idea.id }}')" class="btn btn-secondary btn-sm" style="color:#34d399;">
|
|
♻️ Restore Idea
|
|
</button>
|
|
<button onclick="deleteIdeaPermanently('{{ idea.id }}')" class="btn btn-danger btn-sm">
|
|
❌ Delete Forever
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="glass-card" style="padding: 2rem; margin-bottom: 2rem; position:relative; overflow:hidden;">
|
|
<div style="display:flex; justify-content:space-between; align-items:flex-start; flex-wrap:wrap; gap:1rem; margin-bottom:1rem;">
|
|
<div>
|
|
<div style="display:flex; align-items:center; gap:0.75rem; margin-bottom:0.5rem;">
|
|
<span style="font-family:var(--font-mono); font-size:1.1rem; font-weight:700; color:var(--accent-primary);">{{ idea.id }}</span>
|
|
<span class="badge badge-{{ idea.lifecycle_state|lower }}">{{ idea.lifecycle_state }}</span>
|
|
<span class="badge" style="background:rgba(255,255,255,0.06); color:var(--text-secondary);">Proc: {{ idea.processing_state }}</span>
|
|
{% if idea.lifecycle_state != 'TRASHED' %}
|
|
<div class="maturity-meter" title="Enrichment Maturity Level {{ idea.enrichment_level }}/5">
|
|
<span>Level {{ idea.enrichment_level }}</span>
|
|
<div class="dots">
|
|
{% for i in range(1, 6) %}
|
|
<div class="dot {% if idea.enrichment_level >= i %}active{% endif %}"></div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<h1 style="font-size: 2.2rem; line-height: 1.2; margin-bottom: 0.75rem;">{{ idea.title or "Processing Submission..." }}</h1>
|
|
<p style="color: var(--text-secondary); font-size: 1.05rem; max-width: 850px;">{{ idea.summary }}</p>
|
|
</div>
|
|
|
|
<!-- Action Center -->
|
|
<div style="display:flex; flex-direction:column; gap:0.5rem; min-width:200px;">
|
|
{% if idea.lifecycle_state == 'TRASHED' %}
|
|
<button onclick="restoreIdea('{{ idea.id }}')" class="btn btn-primary" style="width:100%;">
|
|
♻️ Restore Idea
|
|
</button>
|
|
<button onclick="deleteIdeaPermanently('{{ idea.id }}')" class="btn btn-danger btn-sm" style="width:100%; margin-top:0.3rem;">
|
|
❌ Delete Forever
|
|
</button>
|
|
{% elif idea.lifecycle_state == 'AVAILABLE' %}
|
|
{% if user and user.role.value != 'ANONYMOUS' %}
|
|
<button onclick="claimIdea('{{ idea.id }}')" class="btn btn-primary" style="width:100%;">
|
|
⚡ Claim Idea
|
|
</button>
|
|
{% else %}
|
|
<a href="/login" class="btn btn-primary" style="width:100%;">
|
|
Sign in to Claim
|
|
</a>
|
|
{% endif %}
|
|
<button onclick="trashIdea('{{ idea.id }}')" class="btn btn-secondary btn-sm" style="margin-top:0.4rem; color:#f87171;" title="Move idea to trash">
|
|
🗑️ Move to Trash
|
|
</button>
|
|
{% elif idea.lifecycle_state == 'CLAIMED' %}
|
|
<div style="background:rgba(99,102,241,0.12); padding:0.75rem; border-radius:var(--radius-md); border:1px solid rgba(99,102,241,0.3); margin-bottom:0.5rem;">
|
|
<div style="font-size:0.8rem; color:var(--text-muted);">Claimed by</div>
|
|
<div style="font-weight:700; color:#a5b4fc;">{{ idea.claimed_by }}</div>
|
|
</div>
|
|
{% if user and (user.username == idea.claimed_by or user.role.value == 'ADMIN') %}
|
|
<button onclick="activateIdea('{{ idea.id }}')" class="btn btn-success btn-sm">
|
|
▶ Begin Work (Activate)
|
|
</button>
|
|
<button onclick="releaseIdea('{{ idea.id }}')" class="btn btn-secondary btn-sm">
|
|
Release Claim
|
|
</button>
|
|
<button onclick="trashIdea('{{ idea.id }}')" class="btn btn-secondary btn-sm" style="margin-top:0.4rem; color:#f87171;" title="Move idea to trash">
|
|
🗑️ Move to Trash
|
|
</button>
|
|
{% endif %}
|
|
{% elif idea.lifecycle_state == 'ACTIVE' %}
|
|
<div style="background:rgba(245,158,11,0.12); padding:0.75rem; border-radius:var(--radius-md); border:1px solid rgba(245,158,11,0.3);">
|
|
<div style="font-size:0.8rem; color:var(--text-muted);">Active Work by</div>
|
|
<div style="font-weight:700; color:#fbbf24;">{{ idea.claimed_by }}</div>
|
|
</div>
|
|
{% if user and (user.username == idea.claimed_by or user.role.value == 'ADMIN') %}
|
|
<button onclick="releaseIdea('{{ idea.id }}')" class="btn btn-secondary btn-sm" style="margin-top:0.4rem;">
|
|
Release Claim
|
|
</button>
|
|
<button onclick="trashIdea('{{ idea.id }}')" class="btn btn-secondary btn-sm" style="margin-top:0.4rem; color:#f87171;" title="Move idea to trash">
|
|
🗑️ Move to Trash
|
|
</button>
|
|
{% endif %}
|
|
{% else %}
|
|
<button onclick="trashIdea('{{ idea.id }}')" class="btn btn-secondary btn-sm" style="color:#f87171;" title="Move idea to trash">
|
|
🗑️ Move to Trash
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Categories & Tags -->
|
|
<div style="display:flex; align-items:center; gap:1.5rem; flex-wrap:wrap; border-top:1px solid var(--border-glass); padding-top:1rem; margin-top:1rem;">
|
|
{% if idea.categories and idea.categories|length > 0 %}
|
|
<div style="display:flex; align-items:center; gap:0.4rem;">
|
|
<span style="font-size:0.8rem; color:var(--text-muted);">Categories:</span>
|
|
{% for c in idea.categories %}
|
|
<span class="badge" style="background:rgba(255,255,255,0.06); color:var(--text-primary);">{{ c }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if idea.tags and idea.tags|length > 0 %}
|
|
<div style="display:flex; align-items:center; gap:0.4rem;">
|
|
<span style="font-size:0.8rem; color:var(--text-muted);">Tags:</span>
|
|
{% for t in idea.tags %}
|
|
<span class="tag-item">#{{ t }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div style="margin-left:auto; font-size:0.8rem; color:var(--text-muted); font-family:var(--font-mono);">
|
|
Submitted: {{ idea.submitted_at[:19] }}Z
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Original Submission & URL Safety Box -->
|
|
<div style="display:grid; grid-template-columns: 2fr 1fr; gap:1.5rem; margin-bottom:2rem;">
|
|
<div class="glass-card" style="padding:1.5rem;">
|
|
<h3 style="font-size:1.1rem; margin-bottom:0.75rem; color:var(--text-secondary); display:flex; align-items:center; gap:0.5rem;">
|
|
<span>📝 Immutable Original Submission</span>
|
|
</h3>
|
|
<div style="background:rgba(0,0,0,0.3); border:1px solid var(--border-glass); border-radius:var(--radius-md); padding:1rem; font-family:var(--font-sans); line-height:1.6; white-space:pre-wrap;">{{ idea.original_text }}</div>
|
|
</div>
|
|
|
|
<div class="glass-card" style="padding:1.5rem;">
|
|
<h3 style="font-size:1.1rem; margin-bottom:0.75rem; color:var(--text-secondary); display:flex; align-items:center; gap:0.5rem;">
|
|
<span>🛡️ URL Safety & VirusTotal</span>
|
|
</h3>
|
|
{% if idea.urls and idea.urls|length > 0 %}
|
|
<div style="display:flex; flex-direction:column; gap:0.6rem;">
|
|
{% for u in idea.urls %}
|
|
<div style="background:rgba(0,0,0,0.25); border:1px solid var(--border-glass); border-radius:var(--radius-sm); padding:0.6rem 0.8rem;">
|
|
<div style="word-break:break-all; font-family:var(--font-mono); font-size:0.8rem; margin-bottom:0.4rem;">
|
|
{{ u.url }}
|
|
</div>
|
|
<div style="display:flex; justify-content:space-between; align-items:center;">
|
|
<span class="badge badge-{{ u.safety_state|lower }}">{{ u.safety_state }}</span>
|
|
<span style="font-size:0.75rem; font-family:var(--font-mono); color:var(--text-muted);">Policy: {{ u.automation_policy }}</span>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<p style="color:var(--text-muted); font-size:0.88rem;">No external URLs extracted in submission.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabs Section -->
|
|
<div class="tab-container glass-card" style="padding:1.75rem;">
|
|
<div class="tab-nav">
|
|
<button class="tab-btn active" data-tab="tab-prior-art">🔍 Prior Art & Alternatives</button>
|
|
<button class="tab-btn" data-tab="tab-research">📚 Deep Research Synthesis</button>
|
|
<button class="tab-btn" data-tab="tab-feasibility">⚙️ Feasibility & Critique</button>
|
|
<button class="tab-btn" data-tab="tab-worktracks">🚀 Work Tracks ({{ idea.work_tracks|length }})</button>
|
|
<button class="tab-btn" data-tab="tab-provenance">⏱️ Provenance & Tokens ({{ idea.provenance|length }})</button>
|
|
<button class="tab-btn" data-tab="tab-artifacts">📦 Dossier & Gitea Project</button>
|
|
</div>
|
|
|
|
<!-- Tab 1: Prior Art -->
|
|
<div id="tab-prior-art" class="tab-panel active">
|
|
<div class="markdown-body">
|
|
{% set prior_art_run = idea.provenance | selectattr("stage", "equalto", "PRIOR_ART") | list %}
|
|
{% if prior_art_run and prior_art_run|length > 0 and prior_art_run[0].output_data.content %}
|
|
<div style="white-space:pre-wrap;">{{ prior_art_run[0].output_data.content }}</div>
|
|
{% else %}
|
|
<p style="color:var(--text-muted);">Prior art discovery is processing or pending.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab 2: Research Synthesis -->
|
|
<div id="tab-research" class="tab-panel">
|
|
<div class="markdown-body">
|
|
{% set research_run = idea.provenance | selectattr("stage", "equalto", "RESEARCH") | list %}
|
|
{% if research_run and research_run|length > 0 and research_run[0].output_data.content %}
|
|
<div style="white-space:pre-wrap;">{{ research_run[0].output_data.content }}</div>
|
|
{% else %}
|
|
<p style="color:var(--text-muted);">Deep research synthesis is processing or pending.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab 3: Feasibility & Critique -->
|
|
<div id="tab-feasibility" class="tab-panel">
|
|
<div class="markdown-body">
|
|
{% set feas_run = idea.provenance | selectattr("stage", "equalto", "FEASIBILITY") | list %}
|
|
{% if feas_run and feas_run|length > 0 and feas_run[0].output_data.content %}
|
|
<div style="white-space:pre-wrap;">{{ feas_run[0].output_data.content }}</div>
|
|
{% else %}
|
|
<p style="color:var(--text-muted);">Feasibility and risk critique is processing or pending.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab 4: Work Tracks -->
|
|
<div id="tab-worktracks" class="tab-panel">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:1.5rem; flex-wrap:wrap; gap:1rem;">
|
|
<div>
|
|
<h3 style="font-size:1.2rem;">Independent Work Tracks</h3>
|
|
<p style="color:var(--text-secondary); font-size:0.9rem;">Assign multiple work types (Article, Blog Entry, Coding Project) to produce distinct outputs.</p>
|
|
</div>
|
|
|
|
{% if user and (user.username == idea.claimed_by or user.role.value == 'ADMIN') %}
|
|
<div style="display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap;">
|
|
<select id="work-type-select" class="form-select" style="width:auto; padding:0.4rem 0.8rem; font-size:0.85rem;">
|
|
<option value="ARTICLE">Article / Essay</option>
|
|
<option value="BLOG_ENTRY">Blog Entry</option>
|
|
<option value="CODING_PROJECT">Coding Project</option>
|
|
</select>
|
|
<input type="text" id="work-track-name" class="form-input" placeholder="Track Name (e.g. Technical Blueprint)" style="width:200px; padding:0.4rem 0.8rem; font-size:0.85rem;">
|
|
<select id="work-model-select" class="form-select" style="width:auto; padding:0.4rem 0.8rem; font-size:0.85rem;" title="Select AI Model">
|
|
<option value="">🤖 Default Policy</option>
|
|
<option value="auto/best-reasoning">🧠 Best Reasoning</option>
|
|
<option value="auto/best-coding">💻 Best Coding</option>
|
|
<option value="auto/best-fast">⚡ Best Fast</option>
|
|
<option value="auto/best-free">🆓 Best Free</option>
|
|
<option value="auto/pro-coding">🎯 Pro Coding</option>
|
|
<option value="auto/pro-reasoning">🏆 Pro Reasoning</option>
|
|
</select>
|
|
<button onclick="createWorkTrack('{{ idea.id }}')" class="btn btn-primary btn-sm">+ Add Track</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if idea.work_tracks and idea.work_tracks|length > 0 %}
|
|
<div style="display:flex; flex-direction:column; gap:1.25rem;">
|
|
{% for tr in idea.work_tracks %}
|
|
<div style="background:rgba(0,0,0,0.3); border:1px solid var(--border-glass); border-radius:var(--radius-md); padding:1.25rem;">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:0.75rem; flex-wrap:wrap; gap:0.5rem;">
|
|
<div style="display:flex; align-items:center; flex-wrap:wrap; gap:0.4rem;">
|
|
<span style="font-family:var(--font-mono); font-weight:700; color:var(--accent-primary);">{{ tr.id }}</span>
|
|
<span style="font-weight:700; font-size:1.1rem;">{{ tr.name }}</span>
|
|
<span class="badge" style="background:rgba(255,255,255,0.08);">{{ tr.work_type_id }}</span>
|
|
<span class="badge badge-{{ tr.state|lower }}">{{ tr.state }}</span>
|
|
{% if tr.model_override %}
|
|
<span class="badge" style="background:rgba(99,102,241,0.18); color:#a5b4fc; border:1px solid rgba(99,102,241,0.3);" title="Assigned AI Model">🤖 {{ tr.model_override }}</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div style="display:flex; gap:0.5rem; align-items:center;">
|
|
{% if user and (user.username == idea.claimed_by or user.role.value == 'ADMIN') %}
|
|
<select id="model-select-{{ tr.id }}" class="form-select form-select-sm" style="font-size:0.78rem; padding:0.25rem 0.5rem; background:rgba(0,0,0,0.4); border-color:var(--border-glass);" title="Select AI Model to run">
|
|
<option value="" {% if not tr.model_override %}selected{% endif %}>🤖 Default Policy</option>
|
|
<option value="auto/best-reasoning" {% if tr.model_override == 'auto/best-reasoning' %}selected{% endif %}>🧠 Best Reasoning</option>
|
|
<option value="auto/best-coding" {% if tr.model_override == 'auto/best-coding' %}selected{% endif %}>💻 Best Coding</option>
|
|
<option value="auto/best-fast" {% if tr.model_override == 'auto/best-fast' %}selected{% endif %}>⚡ Best Fast</option>
|
|
<option value="auto/best-free" {% if tr.model_override == 'auto/best-free' %}selected{% endif %}>🆓 Best Free</option>
|
|
<option value="auto/pro-coding" {% if tr.model_override == 'auto/pro-coding' %}selected{% endif %}>🎯 Pro Coding</option>
|
|
<option value="auto/pro-reasoning" {% if tr.model_override == 'auto/pro-reasoning' %}selected{% endif %}>🏆 Pro Reasoning</option>
|
|
</select>
|
|
<button onclick="activateWorkTrack('{{ tr.id }}')" class="btn btn-primary btn-sm">
|
|
{% if tr.outputs and tr.outputs|length > 0 %}🔄 Re-run Workflow{% else %}⚡ Run Workflow{% endif %}
|
|
</button>
|
|
{% if tr.work_type_id == 'CODING_PROJECT' and tr.state == 'COMPLETED' %}
|
|
<button onclick="graduateToGitea('{{ tr.id }}')" class="btn btn-success btn-sm">📦 Graduate to Gitea</button>
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- External resources (Gitea repo) -->
|
|
{% if tr.external_resources and tr.external_resources|length > 0 %}
|
|
<div style="margin-bottom:0.75rem; background:rgba(16,185,129,0.08); border:1px solid rgba(16,185,129,0.25); border-radius:var(--radius-sm); padding:0.6rem 0.8rem; font-size:0.85rem;">
|
|
{% for ext in tr.external_resources %}
|
|
<span>🎉 Graduated Project Repository: <a href="{{ ext.url }}" target="_blank" style="color:var(--color-success); font-weight:700;">{{ ext.url }} ↗</a></span>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Outputs -->
|
|
{% if tr.outputs and tr.outputs|length > 0 %}
|
|
<div style="margin-top:0.75rem;">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:0.5rem;">
|
|
<h4 style="font-size:0.9rem; color:var(--text-secondary); margin:0;">Generated Artifacts & Versions ({{ tr.outputs|length }}):</h4>
|
|
</div>
|
|
<div style="display:flex; flex-direction:column; gap:0.75rem;">
|
|
{% for out in tr.outputs %}
|
|
<details {% if out.is_current %}open{% endif %} style="background:rgba(255,255,255,0.03); border:1px solid var(--border-glass); border-radius:var(--radius-sm); padding:0.75rem 1rem;">
|
|
<summary style="cursor:pointer; font-weight:600; font-family:var(--font-mono); font-size:0.9rem; color:var(--accent-primary); display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:0.5rem;">
|
|
<div style="display:flex; align-items:center; flex-wrap:wrap; gap:0.4rem;">
|
|
<span>📄 {{ out.name }}</span>
|
|
{% if out.is_current %}
|
|
<span class="badge" style="background:rgba(16,185,129,0.2); color:#34d399; border:1px solid rgba(16,185,129,0.4); font-size:0.75rem;">v{{ out.version }} (Latest)</span>
|
|
{% else %}
|
|
<span class="badge" style="background:rgba(255,255,255,0.08); color:var(--text-muted); font-size:0.75rem;">v{{ out.version }}</span>
|
|
{% endif %}
|
|
{% if out.model_used %}
|
|
<span class="badge" style="background:rgba(99,102,241,0.15); color:#a5b4fc; font-size:0.72rem;">🤖 {{ out.model_used }}</span>
|
|
{% endif %}
|
|
<span style="font-size:0.72rem; color:var(--text-muted); font-family:var(--font-sans); font-weight:normal;">🕒 {{ out.created_at[:19].replace('T', ' ') }} UTC</span>
|
|
</div>
|
|
|
|
<div>
|
|
{% if user and (user.username == idea.claimed_by or user.role.value == 'ADMIN') %}
|
|
<button data-output-id="{{ out.id }}" data-doc-name="{{ out.name }}" data-version="{{ out.version }}" onclick="event.stopPropagation(); deleteWorkTrackOutput(this.dataset.outputId, this.dataset.docName, this.dataset.version)" class="btn btn-sm" style="padding:0.15rem 0.5rem; font-size:0.75rem; background:rgba(239,68,68,0.18); border:1px solid rgba(239,68,68,0.35); color:#fca5a5;" title="Delete this artifact version">
|
|
🗑️ Delete
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</summary>
|
|
<div class="markdown-body" style="margin-top:0.75rem; white-space:pre-wrap; border-top:1px solid var(--border-glass); padding-top:0.75rem; font-size:0.92rem; line-height:1.6;">{{ out.content }}</div>
|
|
</details>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div style="margin-top:0.75rem; padding:0.75rem; background:rgba(255,255,255,0.02); border-radius:var(--radius-sm); border:1px dashed var(--border-glass); display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:0.5rem;">
|
|
<span style="color:var(--text-muted); font-size:0.85rem;">No artifacts generated yet for this track.</span>
|
|
{% if user and (user.username == idea.claimed_by or user.role.value == 'ADMIN') %}
|
|
<button onclick="activateWorkTrack('{{ tr.id }}')" class="btn btn-primary btn-sm" style="padding:0.25rem 0.6rem; font-size:0.8rem;">⚡ Run Workflow</button>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<p style="color:var(--text-muted);">No work tracks created yet. Claim this idea to create independent development tracks.</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Tab 5: Provenance & Tokens -->
|
|
<div id="tab-provenance" class="tab-panel">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:1rem;">
|
|
<h3 style="font-size:1.1rem;">Execution Provenance & Token Accounting</h3>
|
|
<div style="font-family:var(--font-mono); font-size:0.85rem; color:var(--text-secondary);">
|
|
Total Tokens Consumed: <strong style="color:var(--accent-primary);">{{ idea.usage_summary.total_tokens }}</strong>
|
|
</div>
|
|
</div>
|
|
|
|
{% if idea.provenance and idea.provenance|length > 0 %}
|
|
<div style="overflow-x:auto;">
|
|
<table style="width:100%; border-collapse:collapse; font-size:0.85rem; text-align:left;">
|
|
<thead>
|
|
<tr style="border-bottom:1px solid var(--border-glass); color:var(--text-muted);">
|
|
<th style="padding:0.6rem;">Run ID</th>
|
|
<th style="padding:0.6rem;">Processor / Stage</th>
|
|
<th style="padding:0.6rem;">Prompt</th>
|
|
<th style="padding:0.6rem;">Model</th>
|
|
<th style="padding:0.6rem;">Tokens (In/Out/Total)</th>
|
|
<th style="padding:0.6rem;">Duration</th>
|
|
<th style="padding:0.6rem;">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for r in idea.provenance %}
|
|
<tr style="border-bottom:1px solid rgba(255,255,255,0.04);">
|
|
<td style="padding:0.6rem; font-family:var(--font-mono); color:var(--accent-primary);">{{ r.id }}</td>
|
|
<td style="padding:0.6rem;"><strong>{{ r.processor_name }}</strong><br><span style="font-size:0.75rem; color:var(--text-muted);">{{ r.stage }}</span></td>
|
|
<td style="padding:0.6rem; font-family:var(--font-mono); font-size:0.78rem;">{{ r.prompt_id }} <span class="badge" style="font-size:0.65rem;">v{{ r.prompt_version }}</span></td>
|
|
<td style="padding:0.6rem; font-family:var(--font-mono); font-size:0.78rem;">{{ r.resolved_model }}</td>
|
|
<td style="padding:0.6rem; font-family:var(--font-mono);">{{ r.input_tokens }} / {{ r.output_tokens }} / <strong>{{ r.total_tokens }}</strong></td>
|
|
<td style="padding:0.6rem; font-family:var(--font-mono);">{{ r.duration_ms }}ms</td>
|
|
<td style="padding:0.6rem;"><span class="badge badge-success">{{ r.status }}</span></td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<p style="color:var(--text-muted);">No processor execution runs recorded yet.</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Tab 6: Dossier & Gitea Project -->
|
|
<div id="tab-artifacts" class="tab-panel">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:1rem; flex-wrap:wrap; gap:0.5rem;">
|
|
<div>
|
|
<h3 style="font-size:1.1rem; margin-bottom:0.25rem;">Canonical Dossier & Gitea Project</h3>
|
|
<p style="color:var(--text-secondary); font-size:0.88rem; margin:0;">Every idea is maintained as a full Git repository under the <strong>thinkstorm</strong> organization on Gitea.</p>
|
|
</div>
|
|
<div>
|
|
{% if idea.gitea_repo_url %}
|
|
<a href="{{ idea.gitea_repo_url }}" target="_blank" class="btn btn-primary btn-sm">
|
|
🔗 Open Project on Gitea ↗
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Gitea Project Card -->
|
|
<div style="background:rgba(0,0,0,0.3); border:1px solid var(--border-glass); border-radius:var(--radius-md); padding:1.25rem; margin-bottom:1.25rem;">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:0.75rem;">
|
|
<div>
|
|
<div style="font-weight:700; font-size:1.05rem; margin-bottom:0.25rem; display:flex; align-items:center; gap:0.5rem;">
|
|
<span>🐙 Gitea Project Repository</span>
|
|
<span class="badge" style="background:rgba(99,102,241,0.2); color:#a5b4fc; font-size:0.75rem;">org: thinkstorm</span>
|
|
</div>
|
|
<div style="font-family:var(--font-mono); font-size:0.85rem; color:var(--text-muted);">
|
|
Repo: <span style="color:var(--accent-primary);">{{ idea.gitea_repo_name or "thinkstorm/ts-" ~ idea.id|lower|replace('ts-', '') }}</span>
|
|
</div>
|
|
<div style="font-size:0.8rem; color:var(--text-secondary); margin-top:0.25rem; font-family:var(--font-mono);">
|
|
Clone: <code style="color:#a5b4fc; background:rgba(0,0,0,0.4); padding:0.2rem 0.4rem; border-radius:4px;">git clone https://git.labyricorn.com/{{ idea.gitea_repo_name or "thinkstorm/ts-" ~ idea.id|lower|replace('ts-', '') }}.git</code>
|
|
</div>
|
|
</div>
|
|
<div style="display:flex; gap:0.5rem; flex-wrap:wrap; align-items:center;">
|
|
<button id="sync-gitea-btn" onclick="syncIdeaToGitea('{{ idea.id }}')" class="btn btn-primary btn-sm">
|
|
🔄 Publish / Re-sync to Gitea
|
|
</button>
|
|
{% if idea.gitea_repo_url %}
|
|
<a href="{{ idea.gitea_repo_url }}" target="_blank" class="btn btn-secondary btn-sm">
|
|
Open in Gitea ↗
|
|
</a>
|
|
{% else %}
|
|
<a href="https://git.labyricorn.com/thinkstorm/ts-{{ idea.id|lower|replace('ts-', '') }}" target="_blank" class="btn btn-secondary btn-sm">
|
|
Open in Gitea ↗
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dossier File Tree -->
|
|
<div style="background:rgba(0,0,0,0.25); border:1px solid var(--border-glass); border-radius:var(--radius-md); padding:1.25rem;">
|
|
<h4 style="font-size:0.95rem; margin-bottom:0.75rem; color:var(--text-secondary);">Canonical Dossier Files in Store:</h4>
|
|
<div style="display:flex; flex-direction:column; gap:0.5rem; font-family:var(--font-mono); font-size:0.85rem;">
|
|
<div style="padding:0.4rem 0.6rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-sm); display:flex; justify-content:space-between;">
|
|
<span>📄 idea.md</span>
|
|
<span style="color:var(--text-muted);">Summary & Original Text</span>
|
|
</div>
|
|
<div style="padding:0.4rem 0.6rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-sm); display:flex; justify-content:space-between;">
|
|
<span>📊 metadata.json</span>
|
|
<span style="color:var(--text-muted);">Structured Metadata & State</span>
|
|
</div>
|
|
<div style="padding:0.4rem 0.6rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-sm); display:flex; justify-content:space-between;">
|
|
<span>🔍 research/prior-art.md</span>
|
|
<span style="color:var(--text-muted);">Competitor Analysis</span>
|
|
</div>
|
|
<div style="padding:0.4rem 0.6rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-sm); display:flex; justify-content:space-between;">
|
|
<span>📚 research/analysis.md</span>
|
|
<span style="color:var(--text-muted);">Deep Research Synthesis</span>
|
|
</div>
|
|
<div style="padding:0.4rem 0.6rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-sm); display:flex; justify-content:space-between;">
|
|
<span>⚙️ research/feasibility.md</span>
|
|
<span style="color:var(--text-muted);">Risk & Feasibility Critique</span>
|
|
</div>
|
|
{% for tr in idea.work_tracks %}
|
|
{% for out in tr.outputs %}
|
|
<div style="padding:0.4rem 0.6rem; background:rgba(99,102,241,0.08); border:1px solid rgba(99,102,241,0.2); border-radius:var(--radius-sm); display:flex; justify-content:space-between;">
|
|
<span>🚀 {{ out.artifact_path }} (v{{ out.version }})</span>
|
|
<span style="color:#a5b4fc;">{{ tr.name }}</span>
|
|
</div>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|