sendword 0.8.7

Simple HTTP webhook to command runner sidecar. Frontend for managing hooks, JSON state for config portability, SQLite for execution history and logs.
Documentation
{% extends "base.html" %}

{% block title %}sendword — execution {{ id[:8] }}{% endblock %}

{% block crumbs %}
<div class="wf-crumbs">
  <a href="/">HOOKS</a><span class="sep">/</span>
  <a href="/hooks/{{ hook_slug }}">{{ hook_slug | upper }}</a><span class="sep">/</span>
  <span aria-current="page">{{ id[:8] | upper }}</span>
</div>
{% endblock %}

{% block actions %}
<form method="post" style="display: inline;"
  hx-post="/executions/{{ id }}/replay" hx-swap="none"
  hx-on::after-request="if(event.detail.successful){var d=JSON.parse(event.detail.xhr.responseText);location.href='/executions/'+d.execution_id;}">
  <button type="submit" class="wf-btn sm">REPLAY</button>
</form>
{% endblock %}

{% block content %}
<div class="wf-f wf-ai-b wf-gap-4 wf-mb-2">
  <h1 class="wf-pagetitle wf-p-0">Execution {{ id[:8] }}</h1>
  <span id="exec-status" class="wf-tag {% if status == 'success' %}ok{% elif status == 'failed' %}err{% elif status == 'running' %}warn{% endif %}">
    <span class="dot"></span>{{ status | upper }}
  </span>
</div>

<div class="wf-panel" style="margin-bottom: 20px;">
  <div class="wf-panel-head"><span class="wf-panel-title">DETAILS</span></div>
  <dl class="wf-dl flush">
    <div class="wf-dl-row"><dt>ID</dt><dd><code>{{ id }}</code></dd></div>
    <div class="wf-dl-row"><dt>HOOK</dt><dd><a href="/hooks/{{ hook_slug }}">{{ hook_slug }}</a></dd></div>
    {% if exit_code is defined and exit_code is not none %}<div class="wf-dl-row"><dt>EXIT CODE</dt><dd>{{ exit_code }}</dd></div>{% endif %}
    <div class="wf-dl-row"><dt>SOURCE</dt><dd>{{ trigger_source }}</dd></div>
    <div class="wf-dl-row"><dt>TRIGGERED</dt><dd><span data-ts="{{ triggered_at }}">{{ triggered_at }}</span></dd></div>
    {% if started_at %}<div class="wf-dl-row"><dt>STARTED</dt><dd><span data-ts="{{ started_at }}">{{ started_at }}</span></dd></div>{% endif %}
    {% if completed_at %}<div class="wf-dl-row"><dt>COMPLETED</dt><dd><span data-ts="{{ completed_at }}">{{ completed_at }}</span></dd></div>{% endif %}
    {% if duration %}<div class="wf-dl-row"><dt>DURATION</dt><dd>{{ duration }}</dd></div>{% endif %}
    {% if retry_count and retry_count > 0 %}
      <div class="wf-dl-row"><dt>RETRY</dt><dd>#{{ retry_count }}{% if retry_of %} of <a href="/executions/{{ retry_of }}">{{ retry_of[:8] }}</a>{% endif %}</dd></div>
    {% endif %}
  </dl>
</div>

{% if status == 'running' %}
<div hx-ext="sse" sse-connect="/executions/{{ id }}/logs/stream">
  <div class="wf-panel" style="margin-bottom: 20px;">
    <div class="wf-panel-head"><span class="wf-panel-title">STDOUT</span></div>
    <div class="wf-panel-body">
      <pre id="log-stdout" sse-swap="stdout" hx-swap="beforeend" style="min-height: 80px; max-height: 600px; overflow: auto; margin: 0;"></pre>
    </div>
  </div>
  <div class="wf-panel" style="margin-bottom: 20px;">
    <div class="wf-panel-head"><span class="wf-panel-title">STDERR</span></div>
    <div class="wf-panel-body">
      <pre id="log-stderr" sse-swap="stderr" hx-swap="beforeend" style="min-height: 40px; max-height: 400px; overflow: auto; margin: 0;"></pre>
    </div>
  </div>
  <div sse-swap="done" hx-swap="innerHTML" style="display: none;"
    hx-on::after-settle="setTimeout(function(){location.reload()},500)"></div>
</div>
{% else %}
<div class="wf-panel" style="margin-bottom: 20px;">
  <div class="wf-panel-head"><span class="wf-panel-title">STDOUT</span></div>
  <div class="wf-panel-body">
    <pre style="min-height: 80px; max-height: 600px; overflow: auto; margin: 0;">{{ stdout }}</pre>
  </div>
</div>
{% if stderr %}
<div class="wf-panel" style="margin-bottom: 20px;">
  <div class="wf-panel-head"><span class="wf-panel-title">STDERR</span></div>
  <div class="wf-panel-body">
    <pre style="min-height: 40px; max-height: 400px; overflow: auto; margin: 0;">{{ stderr }}</pre>
  </div>
</div>
{% endif %}
{% endif %}
{% endblock %}