display what accouting would create

This commit is contained in:
Priec
2026-08-12 18:57:10 +02:00
parent 719bae0cd2
commit cdaa1b2b7d
11 changed files with 668 additions and 22 deletions

View File

@@ -86,10 +86,17 @@
<input type="hidden" name="accounting_currency" value="{{ page.draft.accounting_currency }}">
{% endif %}
{#
No hx-trigger here. A text input fires `change` on blur, so mousing into
the next field would swap the whole builder out from under the click that
is still in flight: the click lands on a detached node and the field only
takes focus on a second click. Nothing rendered depends on the table name
on its own — it filters the table out of its own link-target list, and
that list is only rendered after a column-type `change`, which posts the
current name along with the rest of the form.
#}
<label>Table name
<input name="table_name" value="{{ page.draft.table_name }}" placeholder="invoice"
hx-post="/admin/tables/builder" hx-trigger="change" hx-include="#table-form"
hx-target="#builder" hx-swap="innerHTML" hx-vals='{"action": "refresh"}'>
<input name="table_name" value="{{ page.draft.table_name }}" placeholder="invoice">
</label>
</div>
@@ -98,10 +105,17 @@
<section class="builder-section">
<h2>Add a column</h2>
<div class="form-grid">
{#
A compound choice is a definition row, not a column: it is named after
its own type and expands into companions the server creates. There is
nothing to name, so the field is replaced by what the choice will add.
#}
{% if !page.draft.columns.pending_is_compound() %}
<label>{% if page.draft.columns.show_link_target() %}Link alias{% else %}Column name{% endif %}
<input name="column_name_input" value="{{ page.draft.columns.name_input }}" placeholder="number">
{% if page.draft.columns.show_link_target() %}<small>The alias is the column name used to distinguish this relationship.</small>{% endif %}
</label>
{% endif %}
<label>Column type
<select name="column_type_input" hx-post="/admin/tables/builder" hx-trigger="change"
hx-include="#table-form" hx-target="#builder" hx-swap="innerHTML"
@@ -191,6 +205,9 @@
</label>
{% endif %}
{# Neither applies to a definition row: it leaves no column to index, and
nothing to keep a quantity ledger on. #}
{% if !page.draft.columns.pending_is_compound() %}
<label>Indexing
<select name="column_indexing_input">
<option value="no" {% if page.draft.columns.indexing_input != "yes" %}selected{% endif %}>no</option>
@@ -204,7 +221,26 @@
</select>
<small>{{ page.draft.columns.quantity_ledger_types() }} only.</small>
</label>
{% endif %}
</div>
{% if page.draft.columns.pending_is_compound() %}
<div class="compound-note">
<p><code>{{ page.draft.columns.pending_compound_name() }}</code> is a definition row, not a column of its own. Adding it gives the table:</p>
<ul>
{% for generated in page.draft.columns.pending_generated_columns() %}
{# The currency and rounding are named rather than shown: those two
inputs sit above with no `change` trigger of their own, so their
current values are only known here on the next render. #}
<li><code>{{ generated.name }}</code> <span class="hint">{{ generated.data_type }}{% if generated.inherits_currency %} — kept in the currency and rounding chosen above{% endif %}</span></li>
{% endfor %}
{% if page.draft.columns.pending_compound_name() == "accounting" %}
<li><code>account_id</code> <span class="hint">system column — the account each row is posted to, written as <code>account</code></span></li>
{% endif %}
</ul>
<p class="hint">These names are reserved: no column of your own may use them, and the table may hold only one <code>{{ page.draft.columns.pending_compound_name() }}</code>. They land where this row sits in the column list, and can be moved with it.</p>
</div>
{% endif %}
<button type="button" class="secondary" hx-post="/admin/tables/builder" hx-include="#table-form"
hx-target="#builder" hx-swap="innerHTML" hx-vals='{"action": "add-column"}'>Add column</button>
</section>
@@ -214,34 +250,58 @@
{% if page.draft.columns.is_empty() %}
<p class="hint">No columns yet. Describe one above and press <em>Add column</em>.</p>
{% else %}
<p class="hint">Columns are created in this order. Use the arrows to move one.</p>
<table class="builder-table">
<thead><tr><th>Name</th><th>Type</th><th>Indexed</th><th>Options</th><th></th></tr></thead>
<thead><tr><th>Order</th><th>Name</th><th>Type</th><th>Indexed</th><th>Options</th><th></th></tr></thead>
<tbody>
{% for column in page.draft.columns.added %}
<tr>
<td><code>{{ column.name }}</code></td>
<td>{{ column.data_type }}</td>
{#
Every declared column, each followed by the columns the server will
generate from it. `row.index` is what says which is which: a
generated column has none, because it is not the user's to move,
index or remove — it belongs to the definition row above it.
#}
{% for row in page.column_rows() %}
<tr {% if row.index.is_none() %}class="generated-row"{% endif %}>
<td class="order">
{% if let Some(index) = row.index %}
<button type="button" class="toggle move" aria-label="Move {{ row.name }} up"
{% if row.first %}disabled{% else %}hx-post="/admin/tables/builder" hx-include="#table-form"
hx-target="#builder" hx-swap="innerHTML"
hx-vals='{"action": "move-column-up", "index": "{{ index }}"}'{% endif %}>&uarr;</button>
<button type="button" class="toggle move" aria-label="Move {{ row.name }} down"
{% if row.last %}disabled{% else %}hx-post="/admin/tables/builder" hx-include="#table-form"
hx-target="#builder" hx-swap="innerHTML"
hx-vals='{"action": "move-column-down", "index": "{{ index }}"}'{% endif %}>&darr;</button>
{% else %}
<span class="hint">&#8627;</span>
{% endif %}
</td>
<td><code>{{ row.name }}</code></td>
<td>{{ row.data_type }}</td>
<td>
{# A compound column expands into schema-managed companions, so
there is no column of its own name to index. #}
{% if page.draft.columns.is_indexable(*loop.index0) %}
{% if row.indexable %}
{% if let Some(index) = row.index %}
<button type="button" class="toggle" hx-post="/admin/tables/builder" hx-include="#table-form"
hx-target="#builder" hx-swap="innerHTML"
hx-vals='{"action": "toggle-index", "index": "{{ loop.index0 }}"}'>
{% if column.indexed %}[x]{% else %}[ ]{% endif %}
hx-vals='{"action": "toggle-index", "index": "{{ index }}"}'>
{% if row.indexed %}[x]{% else %}[ ]{% endif %}
</button>
{% endif %}
{% else if row.indexed %}
<span class="tag">indexed</span>
{% else %}
<span class="hint"></span>
<span class="hint">&mdash;</span>
{% endif %}
</td>
<td>{% for tag in row.tags %}<span class="tag">{{ tag }}</span>{% endfor %}</td>
<td>
{% if column.quantity_ledger %}<span class="tag">quantity ledger</span>{% endif %}
{% if !column.option_label().is_empty() %}<span class="tag">{{ column.option_label() }}</span>{% endif %}
</td>
<td>
{% if let Some(index) = row.index %}
<button type="button" class="danger" hx-post="/admin/tables/builder" hx-include="#table-form"
hx-target="#builder" hx-swap="innerHTML"
hx-vals='{"action": "remove-column", "index": "{{ loop.index0 }}"}'>Remove</button>
hx-vals='{"action": "remove-column", "index": "{{ index }}"}'>Remove</button>
{% endif %}
</td>
</tr>
{% endfor %}