{# Vendor-Assets über asset()-Helper -- siehe index.html für Details. #} {# Data bridge only -- the page logic lives in settings.js. #} {# ---- Macros: one setting = one row (label + hint left, control right). ---- #} {% macro row(key) %}
{{ labels.get(key, key) }}
{% if hints.get(key) %}
{{ hints[key] }}
{% endif %} {{ key }}
{{ caller() }} {# d-block via :class -- a fixed d-block would defeat x-show (Bootstrap !important). #}
{% endmacro %} {# Enum setting as a segmented control; the active option's description below. #} {% macro segmented(key, icons={}) %}
{% for opt in field_choices[key] %} {% endfor %}
{% endmacro %} {# Boolean setting as a switch. on/off are the stored spellings. #} {% macro switch(key, on='true', off='false') %} {% endmacro %} {# Free-text setting (paths, a command line). Saves on Enter or via the button #} {# that appears once the draft differs; Esc reverts; the same slot resets a #} {# stored value to its default. #} {% macro text(key, placeholder='', extra_class='') %}
{% endmacro %}
{# ---- Section rail. Badges carry live state, not decoration. ---- #}
{# ================= General ================= #}

{{ t('General') }}

{{ t('Language, start view and where the UI libraries come from.') }}

{% call row('language') %}{{ segmented('language') }}{% endcall %} {% call row('default_view') %} {{ segmented('default_view', {'list': 'ti-list', 'kanban': 'ti-layout-kanban'}) }} {% endcall %} {% call row('assets_mode') %} {{ segmented('assets_mode', {'auto': 'ti-wand', 'cdn': 'ti-cloud', 'local': 'ti-database'}) }} {% endcall %}

{{ t('Projects') }}

{{ t('Where projects live on disk. Paths may start with ~.') }}

{% call row('projects_base') %}{{ text('projects_base', '~/Projects', 'font-monospace') }}{% endcall %} {% call row('no_project_dir') %}{{ text('no_project_dir', '~/Projects', 'font-monospace') }}{% endcall %}
{# ================= Agents & runs ================= #}

{{ t('Agents & runs') }}

{{ t('How runs start and how the queue hands out work. Configure each agent on the Plugins tab.') }}

{% call row('default_agent') %}
{% endcall %} {% call row('claude_open_terminal') %}{{ switch('claude_open_terminal') }}{% endcall %} {% call row('claude_idle_seconds') %}
{% endcall %}

{{ t('Queue') }}

{{ t('Every run goes through the queue; one task runs per project at a time.') }}

{% call row('queue_enabled') %}{{ switch('queue_enabled') }}{% endcall %} {% call row('dir_locks') %}{{ switch('dir_locks', 'on', 'off') }}{% endcall %} {% call row('require_clean') %}{{ switch('require_clean', 'on', 'off') }}{% endcall %}
{# ================= Plugins ================= #}

{{ t('Plugins') }}

{{ t('Switch optional features and agent integrations on or off. Takes effect immediately; at least one agent stays enabled. A plugin shows its settings only while it is on.') }}

{% for kind, heading in [('agent', t('Agents')), ('feature', t('Features'))] %}
{{ heading }}
{% for p in plugin_cards if p.kind == kind %}
{% if p.image %} {% else %}{% endif %}

{{ p.label }} {% if p.kind == 'agent' %} {% endif %}

{{ p.description }}
{# A plugin without settings is header-only. #} {% if p.kind == 'agent' or p.fields or p.slot_templates %}
{% if p.kind == 'agent' %} {% endif %} {% for key in p.fields %} {% call row(key) %} {{ text(key, '/path/to/' + p.name if key.endswith('_bin') else '', 'font-monospace') }} {% endcall %} {% endfor %} {% if p.name == 'claude' %}
{{ t('Permission mode') }}
{{ t('How a spawned Claude session handles permissions. Passed to the CLI as --permission-mode.') }}
claude_permission_mode
{% for value, label, desc in [ ('default', t('Normal'), t('Claude asks before it edits a file or runs a command.')), ('auto', t('Auto'), t('Claude accepts its own actions automatically.')), ('plan', t('Plan'), t('Claude only plans and makes no changes.')), ('bypassPermissions', t('Bypass permissions'), t('Claude skips every confirmation and runs unattended.')), ] %} {% endfor %}
{{ t('This can be dangerous.') }} {{ t('With permissions bypassed, Claude can change or delete files and run shell commands in the project directory without asking first. Only use it for projects you fully trust.') }}
{% endif %} {% if p.name == 'opencode' %}
opencode_auto
{{ switch('opencode_auto') }}
{% endif %} {% if p.kind == 'agent' %} {# /task integration status -- read-only, installs go through the CLI. #} {% endif %} {% for tpl in p.slot_templates %}{% include tpl %}{% endfor %}
{% endif %}
{% endfor %} {% endfor %}
{# ================= Maintenance ================= #}

{{ t('Maintenance') }}

{{ t('Service, updates and the raw settings store.') }}

{% if can_restart %} {# Restart only recovers under an installed systemd/launchd unit. #}
{{ t('Restart the service') }}
{{ t('Needed to pick up a new version or apply changes that require a fresh start.') }}
{% endif %}
{{ t('Compact the database') }}
{{ t('Reclaim the space left by deleted and archived tasks and refresh the query optimizer.') }}
{% call row('update_command') %}{{ text('update_command', 'uv tool upgrade ntasker', 'font-monospace') }}{% endcall %}

{{ t('Stored values') }}

{{ t('Everything in the settings table, including keys written by the UI or the CLI. Deleting a row resets that key to its default.') }}

{{ t('Key') }} {{ t('Value') }} {{ t('updated') }}

{{ t('No settings configured.') }}

{{ t('Everything runs on defaults. Change a setting on any tab, or via CLI:') }} ntasker config set <key> <value>

{# Toast container -- reuses Tabler toast styling. #}