{# The whole workspace — crate::pages::admin::table_definition::ui::WorkspaceFragment, and what table_definition.html embeds on first load. Which panels appear follows how much has been selected: the copy and invoice template panels need a profile, everything else needs a table, and a backend-managed ("system") table gets none of the write panels at all, because the server refuses every one of them for it. #} {% import "ui/alert.html" as alert %} {% import "ui/dialog.html" as dialog %} {% import "ui/toast.html" as toast %} {%- if let Some(message) = page.error %}{% call alert::error("Could not continue", message) %}{% endcall %}{% endif -%} {%- if let Some(message) = page.status %}{% call toast::success("Done", message) %}{% endcall %}{% endif -%} {%- if let Some(message) = page.error %}{% call dialog::error("Could not continue", message) %}{% endcall %}{% endif -%} {% if let Some(sql) = page.sql %} {% if !sql.is_empty() %}

SQL the backend ran

{{ sql }}
{% endif %} {% endif %} {% if !page.generated.is_empty() %}

Tables created from the template

{% for generated in page.generated %} {% endfor %}
TableCollectionParent
{{ generated.table_name }} {% if generated.collection_path.is_empty() %}root{% else %}{{ generated.collection_path }}{% endif %} {% if generated.parent_table_name.is_empty() %}{% else %}{{ generated.parent_table_name }}{% endif %}
{% endif %}

Selection

{% if page.selection.has_profile() %} {% endif %}
{% if page.selection.has_profile() %}
{% if page.selection.is_global() %} + Create a global table {% else %} + Create a table in this profile {% endif %}
{% if page.tables.is_empty() %}

This profile has no tables yet.

{% else %} {% for table in page.tables %} {% endfor %}
TableKindDepends onRow display
{{ table.name }} {{ table.table_kind }} {% if table.depends_on.is_empty() %}{% else %}{{ table.depends_on|join(", ") }}{% endif %} {% if table.row_display_columns.is_empty() %}id{% else %}{{ table.row_display_columns|join(", ") }}{% endif %}
{% endif %} {% else %}

Nothing is selected yet. Every panel below acts on one profile, and most of them on one table inside it.

{% endif %}
{% if let Some(detail) = page.detail %}

{{ detail.name }} {{ detail.columns.len() }} columns

Identified by {%- if detail.row_display_columns.is_empty() %} its id {%- else %} {{ detail.row_display_columns|join(", ") }}{% endif -%} {%- if let Some(summary) = page.selected_table() -%} {%- if !summary.depends_on.is_empty() %} · depends on {{ summary.depends_on|join(", ") }}{% endif -%} {%- endif -%} .

{% if detail.is_system() %}

This table is backend-managed. Its definition is shown here, but it can only be changed through the backend's own APIs.

{% endif %} {% for column in detail.columns %} {% endfor %}
ColumnTypeNotes
{{ column.name }} {{ column.field_type }}{% if !column.sql_type.is_empty() %} {{ column.sql_type }}{% endif %} {%- for flag in column.flags() %}{{ flag }}{% endfor -%}
{% if !detail.scripts.is_empty() %}

Scripts

{% for script in detail.scripts %} {% endfor %}
Target columnTypeDescription
{{ script.target_column }} {{ script.target_column_type }} {{ script.description }}
source
{{ script.script }}
{% endif %}
{% endif %} {% if !page.permission_object.is_empty() %}

Data permissions for {{ page.selection.table }}

These grants cover this table family and take effect on subsequent requests without replacing the current session. Wider access — a whole profile, or every table at once — is on the Permissions page.

{% for role in page.role_permissions %}{% endfor %}
RoleActions
{{ role.role }}
{% for permission in role.actions %} {% if permission.direct %}
{% else if permission.effective %} {{ permission.action }} · inherited {% else %}
{% endif %} {% endfor %}
{% endif %} {% if page.table_is_writable() %} {# Append columns. The panel stages columns without writing anything; the selection travels in the URL so the posted fields are exactly the ones the Add-table builder posts, and both are decoded by the same code. #}

Add columns to {{ page.selection.table }}

Columns are appended. Nothing that already exists is changed, and the new columns can be indexed as they are added.

{% include "pages/admin/table_definition/column_panel.html" %}
{% if let Some(detail) = page.detail %}

Rename a column

Renames what the column is called, not the physical column underneath, so stored data and scripts are untouched. Only possible while the table has no rows.

{% endif %}

Delete {{ page.selection.table }}

Drops the table and its definition, and the profile too when this was its last table. The backend refuses to delete a table that still has rows.

{% endif %} {% if page.selection.has_profile() && !page.selection.is_global() %}

Copy {{ page.selection.profile }} into a new profile

Copies structure — tables, links and scripts — and no rows. Leave every table unticked to copy the whole profile.

{% if !page.copy_candidates().is_empty() %}
{% for table in page.copy_candidates() %} {% endfor %}
{% endif %}

Create tables from an invoice template

Reads the #let komp_ac_fields = (…) contract out of a Typst template. A path that matches an existing table and column becomes a reference to it; anything else becomes a TEXT column to refine later, and every [] becomes a child table.

Column rename history

{% if page.history.is_empty() %}

No column in {% if page.selection.has_table() %}{{ page.selection.table }}{% else %}this profile{% endif %} has been renamed.

{% else %} {% for entry in page.history %} {% endfor %}
TableWasIsWhen
{{ entry.table_name }} {{ entry.old_column_name }} {{ entry.new_column_name }} {{ entry.created_at }}
{% endif %}
{% endif %}