{% extends "base.html" %} {% from '_upsell.html' import crown_badge, max_badge %} {% block title %}{{ _("Settings") }}{% endblock %} {% block content %}

{{ _("Settings") }}

{# Historical Thread Indexing Section #}

history {{ _("Historical Thread Indexing") }}

{% trans %}Index historical threads from the Addons Marketplace to ensure all messages are synchronized, even from older threads with recent activity.{% endtrans %}

{# ── Live Status Banner (shown when running) ── #} {% set fetched = last_sync.total_threads_fetched if last_sync and last_sync.total_threads_fetched else 0 %} {% set target = last_sync.session_target if last_sync and last_sync.session_target else 0 %} {% set new_count = last_sync.new_threads_count if last_sync and last_sync.new_threads_count else 0 %} {% set upd_count = last_sync.updated_threads_count if last_sync and last_sync.updated_threads_count else 0 %} {% set pct = ((fetched / target * 100) | int) if target else 0 %}

{{ _("Sync in progress...") }}

{{ fetched }} {{ _("of") }} {{ target }} {{ _("fetched") }} · {{ new_count }} new · {{ upd_count }} updated

{% if target %}{{ pct }}%{% endif %}
{# Progress bar #}
{# ── Stats grid ── #}

{{ _("Status") }}

{% if last_sync and last_sync.status %} {% if last_sync.status == 'running' %} {{ _("Running") }} {% elif last_sync.status == 'completed' %} {{ _("Completed") }} {% elif last_sync.status == 'failed' %} {{ _("Failed") }} {% elif last_sync.status == 'paused' %} {{ _("Paused") }} {% else %} {{ last_sync.status }} {% endif %} {% else %} {{ _("Not Started") }} {% endif %}

{# Timestamp below the status word — distinguishes a stale historical result from a live one #}

{% if last_sync and last_sync.completed_at %} {{ last_sync.completed_at|localdt('%b %d, %H:%M') }} {% elif last_sync and last_sync.started_at and last_sync.status == 'running' %} {{ _("In progress...") }} {% elif last_sync and last_sync.started_at %} {% set start_time = last_sync.started_at|localdt('%b %d, %H:%M') %} {% trans start_time=start_time %}Started {{ start_time }}{% endtrans %} {% endif %}

{{ _("Fetched") }}

{{ fetched }} {% if target %} / {{ target }}{% endif %}

{{ _("New threads") }}

{{ new_count }}

{{ _("Updated") }}

{{ upd_count }}

{{ _("Total in DB") }}

{{ last_sync.threads_in_db if last_sync else 0 }}

{{ _("Total Available") }}

{% if last_sync and last_sync.total_threads_available %} {{ last_sync.total_threads_available }} {% else %} - {% endif %}

{# ── "Fully Synced" banner ── #} {# Shown when DB coverage equals total available threads and the last sync completed #} {% set db_count = last_sync.threads_in_db if last_sync else 0 %} {% set avail_count = last_sync.total_threads_available if last_sync and last_sync.total_threads_available else 0 %} {% set is_fully_synced = (avail_count > 0 and db_count >= avail_count and last_sync and last_sync.status == 'completed') %}
check_circle

{{ _("All threads are synced — your database is up to date.") }}

{# Error message (hidden by JS when a new sync starts) #}

{{ _("The last sync stopped with an error:") }}

{{ last_sync.error_message if last_sync and last_sync.error_message else '' }}

{# ── Control buttons ── #}
{{ _("Advanced Options") }}

{{ _("100 threads/page") }}

{% trans %}Paste an Addons thread ID or full URL (e.g. 891159 or …?ict=891159){% endtrans %}

{# Auto-Close Settings Section #} {% if has_feature('auto_close') %}

timer_off {{ _("Auto-Close Settings") }}

{% trans %}Automatically close stale tickets that have had no activity for a configurable number of days. Unread inbound tickets use double the threshold before being closed.{% endtrans %}

{{ _("Enable auto-close") }}
{{ _("days of inactivity") }}

{% trans %}Tickets with an outbound last message or a read inbound last message are closed after X days. Unread inbound tickets are closed after 2X days.{% endtrans %}

{% else %}

timer_off {{ _("Auto-Close Settings") }}{{ crown_badge() }}

{% trans %}Automatically close stale tickets — available on the Premium plan and above.{% endtrans %}

{% endif %} {# Auto-Response Settings Section #} {% if has_feature('autoresponse_static') %}

schedule_send {{ _("Auto-Response") }}

{{ _("Automatically reply to incoming messages that arrive out of hours or while away mode is on.") }}

{{ _("Auto-responses are sent during the next scheduled sync (up to 15 min for Max, 1 hour for Premium).") }}

{{ _("Enable auto-response") }}
{# ── Language tab bar ── #}
{# Default tab #} {# Existing translation tabs (server-rendered) #} {% for lang, body in (autoresponse.translations or {}).items() %} {% endfor %} {# + Add language control #}
{# Tab border bottom line #}
{# Caption #}

{{ _("Customers get the message matching their ticket's language; Default otherwise.") }}

{# Default textarea #}

{{ _("Sent as plain text.") }}

{# Language-variant textareas (server-rendered for existing translations) #} {% for lang, body in (autoresponse.translations or {}).items() %} {% endfor %} {# AI translate button #}
{{ _("Away mode (always auto-respond)") }}
{% else %}

schedule_send {{ _("Auto-Response") }}{{ crown_badge() }}

{% trans %}Automatically reply to out-of-hours messages — available on the Premium plan and above.{% endtrans %}

{% endif %} {# Language Preferences Section #}

translate {{ _("Language Preferences") }}

{% trans %}Configure which languages are used for translating messages and replies. The preferred language is used as the default translation target.{% endtrans %}

{{ _("Used as the default target for message translation.") }}

{# Display Timezone Section #}

schedule {{ _("Display Timezone") }}

{% trans %}Times across ModuleDesk are shown in this timezone. Timestamps are always stored in UTC, so changing this only changes what you see — including on messages already in your inbox.{% endtrans %}

{% set display_tz = current_user.display_timezone %} {% set current_time = now_utc|localdt('%H:%M') %} {% trans display_tz=display_tz, current_time=current_time %}Currently showing times in {{ display_tz }} — right now that is {{ current_time }}.{% endtrans %}

{# Reply Signature Section #}

signature {{ _("Reply Signature") }}

{% trans %}This signature is automatically appended to every reply in the ticket editor. You can edit it per-message before sending.{% endtrans %}

{% if has_feature('signature_multilang') %}

{{ _("Language variants") }}

{{ _("Per-language signatures override the default for tickets in that language.") }}

{% endif %}
{# Documentation Sources Section #}

travel_explore {{ _("Documentation Sources") }}

{% trans %}Index external documentation URLs so the AI can reference official docs in its replies. Add a sitemap.xml URL to index an entire documentation site (up to 200 pages).{% endtrans %}

{# Pages already scraped are KEPT when a plan no longer includes doc scraping — re-scraping costs real money and the user may upgrade again. So we show the counts (the value is still there) and say plainly that they are not being used for answers on this plan, rather than hiding them as if they were lost. #} {% set doc_page_total = doc_sources | map(attribute='page_count') | select | sum %} {% if not has_feature('doc_scraping') and doc_sources %}
pause_circle
{% set plan_label = org_plan|replace('max_trial', 'trial')|capitalize %}

{% trans plan_label=plan_label %}Your indexed documentation is inactive on the {{ plan_label }} plan.{% endtrans %}

{% set n_sources = doc_sources|length %} {% set n_pages = doc_page_total %} {% set sources_word = ngettext('source', 'sources', n_sources) %} {% set pages_word = ngettext('page', 'pages', n_pages) %}

{% trans n_sources=n_sources, sources_word=sources_word, n_pages=n_pages, pages_word=pages_word %}Your {{ n_sources }} {{ sources_word }} and {{ n_pages }} indexed {{ pages_word }} are kept safe, but they are not used in AI replies on this plan, and new scraping is paused. Upgrade to switch them back on — nothing needs re-indexing.{% endtrans %}

{% endif %} {# Add Source Form #}
{# Sources Table #} {% if doc_sources %}
{% for src in doc_sources %} {% endfor %}
{{ _("Label / URL") }} {{ _("Type") }} {{ _("Pages") }} {{ _("Last Scraped") }} {{ _("Actions") }}

{{ src.label or src.url[:60] }}

{{ src.url[:80] }}{% if src.url|length > 80 %}…{% endif %}

{{ src.doc_system }} {{ src.page_count }} {{ src.last_scraped_at|localdt('%Y-%m-%d %H:%M') if src.last_scraped_at else _('Never') }}
{% else %}

{{ _("No documentation sources added yet.") }}

{% endif %}

{{ _("Linking a source to a module makes the AI prioritise that module's own documentation when drafting replies.") }}

{% endblock %}