Implement executing tasks

This commit is contained in:
2026-03-03 16:41:28 +00:00
parent d6bd56dace
commit 9c14e51b43
42 changed files with 3410 additions and 121 deletions

View File

@@ -0,0 +1,128 @@
{% extends "base.html" %}
{% block content %}
<section class="section">
<div class="container">
<h1 class="title is-4">Availability Settings</h1>
<form method="post" class="box">
{% csrf_token %}
<div class="columns is-multiline">
<div class="column is-3"><label class="checkbox"><input type="checkbox" name="enabled" {% if settings_row.enabled %}checked{% endif %}> Enabled</label></div>
<div class="column is-3"><label class="checkbox"><input type="checkbox" name="show_in_chat" {% if settings_row.show_in_chat %}checked{% endif %}> Show In Chat</label></div>
<div class="column is-3"><label class="checkbox"><input type="checkbox" name="show_in_groups" {% if settings_row.show_in_groups %}checked{% endif %}> Show In Groups</label></div>
<div class="column is-3"><label class="checkbox"><input type="checkbox" name="inference_enabled" {% if settings_row.inference_enabled %}checked{% endif %}> Inference Enabled</label></div>
<div class="column is-3">
<label class="label is-size-7">Retention Days</label>
<input class="input is-small" type="number" min="1" name="retention_days" value="{{ settings_row.retention_days }}">
</div>
<div class="column is-3">
<label class="label is-size-7">Fade Threshold (seconds)</label>
<input class="input is-small" type="number" min="30" name="fade_threshold_seconds" value="{{ settings_row.fade_threshold_seconds }}">
</div>
</div>
<button class="button is-link is-small" type="submit">Save</button>
</form>
<form method="get" class="box">
<h2 class="title is-6">Timeline Filters</h2>
<div class="columns is-multiline">
<div class="column is-3">
<label class="label is-size-7">Person</label>
<div class="select is-small is-fullwidth">
<select name="person">
<option value="">All</option>
{% for person in people %}
<option value="{{ person.id }}" {% if filters.person == person.id|stringformat:"s" %}selected{% endif %}>{{ person.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="column is-2">
<label class="label is-size-7">Service</label>
<div class="select is-small is-fullwidth">
<select name="service">
<option value="">All</option>
{% for item in service_choices %}
<option value="{{ item }}" {% if filters.service == item %}selected{% endif %}>{{ item }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="column is-2">
<label class="label is-size-7">State</label>
<div class="select is-small is-fullwidth">
<select name="state">
<option value="">All</option>
{% for item in state_choices %}
<option value="{{ item }}" {% if filters.state == item %}selected{% endif %}>{{ item }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="column is-2">
<label class="label is-size-7">Source</label>
<div class="select is-small is-fullwidth">
<select name="source_kind">
<option value="">All</option>
{% for item in source_kind_choices %}
<option value="{{ item }}" {% if filters.source_kind == item %}selected{% endif %}>{{ item }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="column is-2">
<label class="label is-size-7">Start (ISO)</label>
<input class="input is-small" type="datetime-local" name="start" value="{{ filters.start }}">
</div>
<div class="column is-2">
<label class="label is-size-7">End (ISO)</label>
<input class="input is-small" type="datetime-local" name="end" value="{{ filters.end }}">
</div>
</div>
<button class="button is-light is-small" type="submit">Apply</button>
</form>
<div class="box">
<h2 class="title is-6">Availability Events</h2>
<table class="table is-fullwidth is-striped is-size-7">
<thead><tr><th>ts</th><th>person</th><th>service</th><th>source</th><th>state</th><th>confidence</th></tr></thead>
<tbody>
{% for row in events %}
<tr>
<td>{{ row.ts }}</td>
<td>{{ row.person.name }}</td>
<td>{{ row.service }}</td>
<td>{{ row.source_kind }}</td>
<td>{{ row.availability_state }}</td>
<td>{{ row.confidence|floatformat:2 }}</td>
</tr>
{% empty %}
<tr><td colspan="6">No events in range.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="box">
<h2 class="title is-6">Availability Spans</h2>
<table class="table is-fullwidth is-striped is-size-7">
<thead><tr><th>person</th><th>service</th><th>state</th><th>start</th><th>end</th><th>confidence</th></tr></thead>
<tbody>
{% for row in spans %}
<tr>
<td>{{ row.person.name }}</td>
<td>{{ row.service }}</td>
<td>{{ row.state }}</td>
<td>{{ row.start_ts }}</td>
<td>{{ row.end_ts }}</td>
<td>{{ row.confidence_start|floatformat:2 }} -> {{ row.confidence_end|floatformat:2 }}</td>
</tr>
{% empty %}
<tr><td colspan="6">No spans in range.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</section>
{% endblock %}

View File

@@ -150,10 +150,10 @@
{% if variant.warn_verbatim_plan %}
<tr>
<td colspan="9">
<p class="help has-text-warning-dark">
Warning: <strong>{{ variant.variant_label }}</strong> is in <code>verbatim</code> mode with plan fanout enabled.
<article class="command-variant-warning">
<strong>Warning:</strong> <strong>{{ variant.variant_label }}</strong> is in <code>verbatim</code> mode with plan fanout enabled.
Recipients will get raw transcript-style output.
</p>
</article>
</td>
</tr>
{% endif %}
@@ -188,12 +188,15 @@
<h4 class="title is-7" style="margin-top: 0.95rem;">Effective Destinations</h4>
{% if profile.enabled_egress_bindings %}
<ul class="is-size-7">
<ul class="command-destination-list is-size-7">
{% for row in profile.enabled_egress_bindings %}
<li>{{ row.service }} · <code>{{ row.channel_identifier }}</code></li>
<li class="command-destination-item">
<span class="tag is-link is-light is-rounded is-small">{{ row.service }}</span>
<code>{{ row.channel_identifier }}</code>
</li>
{% endfor %}
</ul>
<p class="help">{{ profile.enabled_egress_bindings|length }} enabled egress destination{{ profile.enabled_egress_bindings|length|pluralize }}.</p>
<p class="command-destination-summary">{{ profile.enabled_egress_bindings|length }} enabled egress destination{{ profile.enabled_egress_bindings|length|pluralize }}.</p>
{% else %}
<article class="notification is-warning is-light is-size-7">No enabled egress destinations. Plan fanout will show sent:0.</article>
{% endif %}
@@ -383,7 +386,7 @@
<article class="notification is-light">No command profiles configured.</article>
{% endfor %}
<article class="box">
<article class="box" id="bp-documents">
<h2 class="title is-6">Business Plan Documents</h2>
<table class="table is-fullwidth is-striped is-size-7">
<thead>
@@ -436,5 +439,44 @@
.command-order-capsule-form + .command-order-capsule-form .command-order-btn {
border-top: 1px solid #dbdbdb;
}
.command-variant-warning {
border: 1px solid rgba(171, 109, 17, 0.45);
background: linear-gradient(180deg, rgba(255, 246, 226, 0.98), rgba(255, 238, 204, 0.95));
color: #6e450e;
border-radius: 8px;
padding: 0.48rem 0.62rem;
font-size: 0.78rem;
line-height: 1.35;
}
.command-destination-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.28rem;
}
.command-destination-item {
display: inline-flex;
align-items: center;
gap: 0.42rem;
background: rgba(244, 248, 255, 0.85);
border: 1px solid rgba(58, 103, 165, 0.2);
border-radius: 7px;
padding: 0.26rem 0.38rem;
width: fit-content;
max-width: 100%;
}
.command-destination-summary {
margin-top: 0.44rem;
display: inline-flex;
align-items: center;
border-radius: 999px;
background: rgba(239, 247, 255, 0.95);
border: 1px solid rgba(58, 103, 165, 0.25);
padding: 0.16rem 0.52rem;
font-size: 0.73rem;
color: #284d7c;
}
</style>
{% endblock %}

View File

@@ -316,21 +316,112 @@
<div class="column is-6">
<section class="tasks-panel">
<h3 class="title is-7">Provider</h3>
<h3 class="title is-7">Providers</h3>
<p class="help">Controls outbound sync to external tracking systems. If disabled, tasks are still derived and visible inside GIA only.</p>
<form method="post">
{% csrf_token %}
<input type="hidden" name="action" value="provider_update">
<input type="hidden" name="provider" value="mock">
<label class="checkbox"><input type="checkbox" name="enabled" value="1" {% if provider_configs and provider_configs.0.enabled %}checked{% endif %}> Enable mock provider</label>
<label class="checkbox"><input type="checkbox" name="enabled" value="1" {% if mock_provider_config and mock_provider_config.enabled %}checked{% endif %}> Enable mock provider</label>
<p class="help">Mock provider logs sync events without writing to a real third-party system.</p>
<div style="margin-top:0.5rem;">
<button class="button is-small is-link is-light" type="submit">Save</button>
</div>
</form>
<hr>
<form method="post">
{% csrf_token %}
<input type="hidden" name="action" value="provider_update">
<input type="hidden" name="provider" value="codex_cli">
<label class="checkbox"><input type="checkbox" name="enabled" value="1" {% if codex_provider_config and codex_provider_config.enabled %}checked{% endif %}> Enable Codex CLI provider</label>
<p class="help">Codex task-sync runs in a dedicated worker (<code>python manage.py codex_worker</code>).</p>
<div class="field" style="margin-top:0.5rem;">
<label class="label is-size-7">Command</label>
<input class="input is-small" name="command" value="{{ codex_provider_settings.command }}" placeholder="codex">
</div>
<div class="field">
<label class="label is-size-7">Workspace Root</label>
<input class="input is-small" name="workspace_root" value="{{ codex_provider_settings.workspace_root }}" placeholder="/code/xf">
</div>
<div class="field">
<label class="label is-size-7">Default Profile</label>
<input class="input is-small" name="default_profile" value="{{ codex_provider_settings.default_profile }}" placeholder="default">
</div>
<div class="field">
<label class="label is-size-7">Timeout Seconds</label>
<input class="input is-small" type="number" min="1" name="timeout_seconds" value="{{ codex_provider_settings.timeout_seconds }}">
</div>
<div style="margin-top:0.5rem;">
<button class="button is-small is-link is-light" type="submit">Save Codex Provider</button>
</div>
</form>
<p class="help">Browse all derived tasks in <a href="{% url 'tasks_hub' %}">Tasks Hub</a>.</p>
</section>
</div>
<div class="column is-12">
<section class="tasks-panel">
<h3 class="title is-7">External Chat Links</h3>
<p class="help">Map a contact to an external Codex chat/session ID for task-sync metadata.</p>
<form method="post" class="block">
{% csrf_token %}
<input type="hidden" name="action" value="external_chat_link_upsert">
<div class="columns tasks-settings-inline-columns">
<div class="column is-2">
<label class="label is-size-7">Provider</label>
<div class="select is-small is-fullwidth">
<select name="provider">
<option value="codex_cli" selected>codex_cli</option>
</select>
</div>
</div>
<div class="column is-5">
<label class="label is-size-7">Contact Identifier</label>
<div class="select is-small is-fullwidth">
<select name="person_identifier_id">
<option value="">Unlinked</option>
{% for row in person_identifiers %}
<option value="{{ row.id }}">{{ row.person.name }} · {{ row.service }} · {{ row.identifier }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="column is-3">
<label class="label is-size-7">External Chat ID</label>
<input class="input is-small" name="external_chat_id" placeholder="codex-chat-...">
</div>
<div class="column is-2">
<label class="label is-size-7">Enabled</label>
<label class="checkbox"><input type="checkbox" name="enabled" value="1" checked> Active</label>
</div>
</div>
<button class="button is-small is-link is-light" type="submit">Save Link</button>
</form>
<table class="table is-fullwidth is-striped is-size-7">
<thead><tr><th>Provider</th><th>Person</th><th>Identifier</th><th>External Chat</th><th>Enabled</th><th></th></tr></thead>
<tbody>
{% for row in external_chat_links %}
<tr>
<td>{{ row.provider }}</td>
<td>{% if row.person %}{{ row.person.name }}{% else %}-{% endif %}</td>
<td>{% if row.person_identifier %}{{ row.person_identifier.service }} · {{ row.person_identifier.identifier }}{% else %}-{% endif %}</td>
<td>{{ row.external_chat_id }}</td>
<td>{{ row.enabled }}</td>
<td>
<form method="post">
{% csrf_token %}
<input type="hidden" name="action" value="external_chat_link_delete">
<input type="hidden" name="external_link_id" value="{{ row.id }}">
<button class="button is-danger is-light is-small" type="submit">Delete</button>
</form>
</td>
</tr>
{% empty %}
<tr><td colspan="6">No external chat links.</td></tr>
{% endfor %}
</tbody>
</table>
</section>
</div>
</div>
</details>
</div>