{% extends "utilities/_base.html" %} {% from "components/page_header.html" import page_header %} {% from "components/collapsible_panel.html" import collapsible_panel %} {% from "components/modal.html" import render_modal with context %} {% from "components/switch.html" import switch %} {% from "macros/automation_forms.html" import render_edit_automation_form with context %} {% from "macros/local_datetime.html" import local_datetime %} {% from "utilities/_sign_in_fields.html" import api_key_field, server_address_field %} {# A sync automation's page. The setup steps are Settings-style cards; a finished step folds to its heading and a one-line summary, so a running sync shows what it does, its run history and its Items. Every form posts to the sync routes (routes/utilities/sync_views.py) and comes back here. #} {% macro option_field(field) %}
{% if field.type == 'local_folder' %}
{% if field.help %} {% set folder_help = (_("Want to keep these photos where they are? Add the folder as a media folder in Settings instead.") ~ ' ' if sync.role == 'source' else '') ~ field.help %} {% endif %}
{% if field.problem %}

{{ field.problem }}

{% endif %} {% elif field.type == 'select' %}
{% if field.help %} {% endif %}
{% elif field.type in ('remote_folder', 'remote_collection') %}
{% if field.help %} {% endif %}
{% elif field.type == 'bool' %} {% else %} {% endif %} {% if field.help and field.type not in ('local_folder', 'select', 'remote_folder', 'remote_collection') %}

{{ field.help }}

{% endif %}
{% endmacro %} {% block title %}{{ _("Automations - Yaffo") }}{% endblock %} {% block utility_styles %} {# The pager's styles stay loaded while it's swapped (its macro links them too). #} {% endblock %} {% block utility_content %} {% set config = sync.column.config %} {% set is_on = selected.enabled and sync.consented %} {% set setup_done = sync.options_done and sync.where_done and sync.consented %} {% set header_actions %}
{% if sync.reviews_before_enable and not is_on %} {{ switch(selected.display_name, false, id='sync-enable-review', disabled=sync.missing) }} {% else %}
{{ switch(selected.display_name, is_on, button_type='submit', disabled=not is_on and sync.missing) }}
{% endif %} {% if is_on %} {% endif %} {% if not sync.missing %} {% endif %}
{% endset %} {% call page_header(selected.display_name, actions=header_actions) %} {{ sync.summary }} {% if is_on and config.consented_at %} {{ _("Since") }} {{ local_datetime(config.consented_at) }} {% endif %} {% endcall %} {% if sync_error_text %} {% endif %} {% if sync.attention %}
{{ sync.status_text }}
{% endif %} {% macro secret_form(account, submit_label) %}
{% if account.instance %} {{ server_address_field('sync-base-url', account.instance_url) }} {% endif %} {% if account.auth_kind == 'basic' %}

{{ _("Yaffo keeps it in your system's keychain to sign in again. Use an app password or a dedicated user if the service offers one.") }}

{% else %} {{ api_key_field('sync-api-key', account.key_label, account.key_help) }} {% endif %}
{% endmacro %}
{% if sync.account %} {% set account = sync.account %} {% call collapsible_panel('sync-step-account', _('Account'), is_open=not account.done, done=account.done, value=(account.provider_label ~ ' · ' ~ account.label) if account.label else none) %} {% if account.connection_key %}
{% if not account.uses_form %} {% endif %}
{% if account.problem_text %}{% endif %} {% if account.uses_form %}
{{ _("Enter a new key or a different account") if account.auth_kind == 'api_key' else _("Enter the password again or use a different account") }} {{ secret_form(account, _("Connect")) }}
{% endif %} {% elif account.uses_form %}

{{ _("Connect Yaffo to %(service)s with a key from your account. Yaffo only uses it for this service.", service=account.provider_label) if account.auth_kind == 'api_key' else _("Sign in to %(service)s with a username and password.", service=account.provider_label) }}

{{ secret_form(account, _("Connect to %(service)s", service=account.provider_label)) }} {% else %}

{{ _("Sign in to %(service)s in your browser. Yaffo only reads from it; your password never reaches Yaffo.", service=account.provider_label) }}

{% endif %} {% if account.others %}
{% endif %} {% if account.device_code %}
{{ _("Signing in on another device?") }}

{{ _("Use this when this browser can't reach Yaffo directly, such as when Yaffo runs on another computer.") }}

{% endif %} {% endcall %} {% endif %} {% call collapsible_panel('sync-step-options', _('Device and options') if sync.peer_source else _('Folder and options'), is_open=not sync.options_done and not sync.options_locked, done=sync.options_done, value=sync.options_summary) %} {% if sync.options_locked %}

{{ _("Sign in first: the folder is chosen from your account.") }}

{% else %} {% if sync.role != 'source' %}

{{ _("Where the copies go, and in what form.") }}

{% elif sync.peer_source %}

{{ _("Choose a paired device and one of its shared folders or albums.") }} {{ _("Pair a device on the Sharing page") }}.

{% endif %}
{% for field in sync.options %}{{ option_field(field) }}{% endfor %} {# Choosing a remote folder saves at once; Save is for the other fields. #} {% if sync.options | rejectattr('type', 'in', ['remote_folder', 'remote_collection']) | list %}
{% endif %}
{% endif %} {% endcall %} {% if sync.peer_source %} {% set filtered = config.selection is not none and config.selection.kind == 'query' %} {% call collapsible_panel('sync-step-import', _('What to import'), is_open=false, done=true, value=sync.import_summary) %}

{{ _("Photos the device adds to the share later are imported too.") }}

{{ _("Choose what to import") }}

{{ _("Every photo and video the device shares here.") }}

{{ _("Choose filters on the next screen, from the device's own people, labels, and dates.") }} {% if filtered %}{{ _("Change the filter") }}{% endif %}

{% endcall %} {% endif %} {% if sync.role == 'target' %} {% call collapsible_panel('sync-step-where', _('What to send'), is_open=not sync.where_done, done=sync.where_done, value=sync.where_summary) %}

{{ _("Photos added later are sent too; photos taken out are removed.") }}

{{ _("Choose what to send") }}
{% if sync.albums %} {% else %}

{{ _("You have no albums yet.") }} {{ _("Create one") }}

{% endif %}

{{ _("Choose filters on the next screen. New matching photos are sent too.") }}

{{ _("Describe which photos to send, then publish the rule.") }}

{% endcall %} {% else %} {% call collapsible_panel('sync-step-where', _('Where to put them'), is_open=not sync.where_done, done=sync.where_done, value=sync.where_summary) %}
{% set layout_help = _("How new photos are arranged in that folder. Keep the source's folders mirrors the folders inside the one you import from; the others go by each photo's capture date. Photos already imported stay where they are.") %}
{% set current_layout = config.import_root.layout if config.import_root else 'source_folders' %}
{% endcall %} {% endif %} {% include "utilities/automations_trigger_panel.html" %} {# Test's result: what a run would do, computed without doing it (sync.js renders it). #} {% include "utilities/automations_runs.html" %} {# The ledger: what this sync imported or sent. Folded to its counts unless something failed; the body pages, filters, and searches on the server. #} {% call collapsible_panel('sync-items', _('Items'), is_open=sync.counts.get('failed', 0) > 0, value=sync.items_summary) %} {# One form carries the search, the status, and the page size, so the chips, the search box, and the pagination component all send the current view. #}
{% if sync.counts %}
{% endif %}

{{ _("Loading…") }}

{# Outside the swapped body: each items response updates it out of band. #}
{% endcall %}
{% if sync.reviews_before_enable and not is_on %} {% macro render_enable_review() %}

{{ _("Turning this sync on lets Yaffo do this, on its schedule, until you turn it off:") }}

{% for term in sync.consent_terms %}
{{ term.label }}
{{ term.value }}
{% endfor %}
{% if sync.peer_source %}

{{ _("Changing the device, what it shares, or where photos go turns the sync off until you review it again.") }}

{% else %}

{{ _("Changing the account, folder, or where photos go turns the sync off until you review it again.") }}

{% endif %} {% endmacro %} {{ render_modal('syncEnableModal', _('Turn on this sync?'), url_for('sync_turn_on', slug=selected.slug), render_enable_review, _('Enable')) }} {% endif %} {{ render_modal('editAutomationModal', _('Edit automation'), url_for('automations_update_details', slug=selected.slug), render_edit_automation_form, _('Save')) }} {% endblock %} {% block scripts %} {% endblock %}