feat: processes and process runs CRUD

This commit is contained in:
2026-03-01 22:04:24 +00:00
parent dbd40485ba
commit 21bbb169f9
14 changed files with 1095 additions and 0 deletions

View File

@@ -0,0 +1,183 @@
{% extends "base.html" %}
{% block content %}
<div class="breadcrumb">
<a href="/processes">Processes</a>
<span class="sep">/</span>
<span>{{ item.name }}</span>
</div>
<div class="detail-header">
<h1 class="detail-title">{{ item.name }}</h1>
<div class="flex gap-2">
<a href="/processes/{{ item.id }}/edit" class="btn btn-secondary btn-sm">Edit</a>
<form action="/processes/{{ item.id }}/delete" method="post" data-confirm="Delete this process?" style="display:inline">
<button type="submit" class="btn btn-danger btn-sm">Delete</button>
</form>
</div>
</div>
<div class="detail-meta mt-2">
<span class="status-badge status-{{ item.status }}">{{ item.status }}</span>
<span class="row-tag">{{ item.process_type }}</span>
{% if item.category %}<span class="detail-meta-item">{{ item.category }}</span>{% endif %}
<span class="detail-meta-item">{{ steps|length }} step{{ 's' if steps|length != 1 }}</span>
<span class="detail-meta-item">Created {{ item.created_at.strftime('%Y-%m-%d') }}</span>
{% if item.tags %}
<div class="mt-1">{% for tag in item.tags %}<span class="row-tag">{{ tag }}</span>{% endfor %}</div>
{% endif %}
</div>
{% if item.description %}
<div class="card mt-3">
<div class="card-header"><h3 class="card-title">Description</h3></div>
<div class="detail-body" style="padding: 12px 16px;">{{ item.description }}</div>
</div>
{% endif %}
<!-- Steps -->
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title">Steps<span class="page-count">{{ steps|length }}</span></h3>
</div>
{% for step in steps %}
<div class="list-row" style="align-items: flex-start;">
<span class="row-meta" style="min-width: 28px; text-align: center; font-weight: 600;">{{ loop.index }}</span>
<div style="flex: 1;">
<span class="row-title">{{ step.title }}</span>
{% if step.instructions %}
<div style="color: var(--muted); font-size: 0.82rem; margin-top: 2px;">{{ step.instructions[:120] }}{{ '...' if step.instructions|length > 120 }}</div>
{% endif %}
{% if step.expected_output %}
<div style="color: var(--muted); font-size: 0.82rem; margin-top: 2px;">Output: {{ step.expected_output[:80] }}</div>
{% endif %}
</div>
{% if step.estimated_days %}
<span class="row-meta">{{ step.estimated_days }}d</span>
{% endif %}
<div class="row-actions">
<button type="button" class="btn btn-ghost btn-xs" onclick="toggleEditStep('{{ step.id }}')">Edit</button>
<form action="/processes/{{ item.id }}/steps/{{ step.id }}/delete" method="post" data-confirm="Delete this step?" style="display:inline">
<button type="submit" class="btn btn-ghost btn-xs" style="color: var(--red)">Del</button>
</form>
</div>
</div>
<!-- Inline edit form (hidden by default) -->
<div id="edit-step-{{ step.id }}" style="display: none; border-bottom: 1px solid var(--border); padding: 12px 16px; background: var(--surface2);">
<form action="/processes/{{ item.id }}/steps/{{ step.id }}/edit" method="post">
<div class="form-grid">
<div class="form-group full-width">
<label class="form-label">Title *</label>
<input type="text" name="title" class="form-input" value="{{ step.title }}" required>
</div>
<div class="form-group full-width">
<label class="form-label">Instructions</label>
<textarea name="instructions" class="form-textarea" rows="2">{{ step.instructions or '' }}</textarea>
</div>
<div class="form-group">
<label class="form-label">Expected Output</label>
<input type="text" name="expected_output" class="form-input" value="{{ step.expected_output or '' }}">
</div>
<div class="form-group">
<label class="form-label">Estimated Days</label>
<input type="number" name="estimated_days" class="form-input" min="0" value="{{ step.estimated_days or '' }}">
</div>
</div>
<div class="form-actions" style="margin-top: 8px;">
<button type="submit" class="btn btn-primary btn-sm">Save Step</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="toggleEditStep('{{ step.id }}')">Cancel</button>
</div>
</form>
</div>
{% endfor %}
<!-- Quick add step -->
<form class="quick-add" action="/processes/{{ item.id }}/steps/add" method="post" style="border-top: 1px solid var(--border);">
<input type="text" name="title" placeholder="Add a step..." required>
<button type="submit" class="btn btn-primary btn-sm">Add Step</button>
</form>
</div>
<!-- Runs -->
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title">Runs<span class="page-count">{{ runs|length }}</span></h3>
</div>
{% for run in runs %}
<div class="list-row">
<span class="row-title"><a href="/processes/runs/{{ run.id }}">{{ run.title }}</a></span>
<span class="status-badge status-{{ run.status }}">{{ run.status|replace('_', ' ') }}</span>
{% if run.total_steps > 0 %}
<span class="row-meta">{{ run.completed_steps }}/{{ run.total_steps }} steps</span>
{% endif %}
{% if run.project_name %}
<span class="row-tag">{{ run.project_name }}</span>
{% endif %}
<span class="row-meta">{{ run.created_at.strftime('%Y-%m-%d') }}</span>
<div class="row-actions">
<form action="/processes/runs/{{ run.id }}/delete" method="post" data-confirm="Delete this run?" style="display:inline">
<button type="submit" class="btn btn-ghost btn-xs" style="color: var(--red)">Del</button>
</form>
</div>
</div>
{% endfor %}
{% if not runs %}
<div style="padding: 16px; color: var(--muted); font-size: 0.85rem;">No runs yet</div>
{% endif %}
<!-- Start Run Form -->
{% if steps %}
<div style="border-top: 1px solid var(--border); padding: 12px 16px;">
<button type="button" class="btn btn-primary btn-sm" onclick="document.getElementById('start-run-form').style.display = document.getElementById('start-run-form').style.display === 'none' ? 'block' : 'none'">+ Start Run</button>
<div id="start-run-form" style="display: none; margin-top: 12px;">
<form action="/processes/{{ item.id }}/runs/start" method="post">
<div class="form-grid">
<div class="form-group full-width">
<label class="form-label">Run Title *</label>
<input type="text" name="title" class="form-input" required
value="{{ item.name }} - Run">
</div>
<div class="form-group">
<label class="form-label">Task Generation</label>
<select name="task_generation" class="form-select">
<option value="all_at_once">All at Once</option>
<option value="step_by_step">Step by Step</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Project</label>
<select name="project_id" class="form-select">
<option value="">None</option>
{% for p in projects %}
<option value="{{ p.id }}">{{ p.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label class="form-label">Contact</label>
<select name="contact_id" class="form-select">
<option value="">None</option>
{% for c in contacts %}
<option value="{{ c.id }}">{{ c.first_name }} {{ c.last_name or '' }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-actions" style="margin-top: 8px;">
<button type="submit" class="btn btn-primary btn-sm">Start Run</button>
</div>
</form>
</div>
</div>
{% endif %}
</div>
<script>
function toggleEditStep(stepId) {
var el = document.getElementById('edit-step-' + stepId);
el.style.display = el.style.display === 'none' ? 'block' : 'none';
}
</script>
{% endblock %}