mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-11-09 10:21:45 +00:00
- Scheduled, encrypted backups to S3, SFTP, REST or a local folder (new restic-mailcow container) - Restore of mailboxes and whole domains in the UI, also deleted ones, for admins and domain admins - Scope set by RESTIC_BACKUP_MODE in mailcow.conf (all, data, config) - Optional backup before updates (update.sh), helper-scripts/restic.sh for a full restore
379 lines
25 KiB
Twig
379 lines
25 KiB
Twig
{# Backup with restic: status, actions, settings, jobs and snapshots, filled by js/site/backup.js #}
|
|
{% set legend_style = 'font-family:var(--bs-body-font-family)' %}
|
|
<div class="tab-pane fade" id="tab-config-backup" role="tabpanel" aria-labelledby="tab-config-backup">
|
|
<div class="card mb-4">
|
|
<div class="card-header d-flex align-items-center fs-5">
|
|
<button class="btn d-md-none flex-grow-1 text-start" data-bs-target="#collapse-tab-config-backup" data-bs-toggle="collapse" aria-controls="collapse-tab-config-backup">
|
|
{{ lang.backup.tab }}
|
|
</button>
|
|
<span class="d-none d-md-block">{{ lang.backup.tab }}</span>
|
|
<button type="button" class="btn btn-xs btn-secondary ms-auto backup-refresh" title="{{ lang.backup.refresh }}" aria-label="{{ lang.backup.refresh }}"><i class="bi bi-arrow-clockwise"></i></button>
|
|
</div>
|
|
<div id="collapse-tab-config-backup" class="card-body collapse" data-bs-parent="#admin-content">
|
|
<div class="row mb-4">
|
|
<div class="col-sm-9 offset-sm-3">
|
|
<p class="text-muted">{{ lang.backup.intro }} <a href="/admin/restore">{{ lang.backup.intro_restore_link }}</a></p>
|
|
|
|
<div id="backup_status">
|
|
<div class="backup-status-summary mb-2" aria-live="polite"><span class="text-muted">{{ lang.footer.loading }}</span></div>
|
|
<div class="d-flex flex-wrap gap-2 mb-3">
|
|
<button type="button" class="btn btn-sm btn-xs-lg btn-success backup-job-request" data-type="backup" title="{{ lang.backup.backup_now_info }}"><i class="bi bi-cloud-arrow-up"></i> {{ lang.backup.backup_now }}</button>
|
|
<button type="button" class="btn btn-sm btn-xs-lg btn-secondary backup-job-request" data-type="init" title="{{ lang.backup.test_connection_info }}"><i class="bi bi-plug"></i> {{ lang.backup.test_connection }}</button>
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-sm btn-xs-lg btn-secondary dropdown-toggle backup-maintenance" data-bs-toggle="dropdown" aria-expanded="false"><i class="bi bi-tools"></i> {{ lang.backup.maintenance }}</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item backup-job-request" href="#" data-type="check" title="{{ lang.backup.check_info }}"><i class="bi bi-shield-check"></i> {{ lang.backup.check_now }}</a></li>
|
|
<li><a class="dropdown-item backup-job-request" href="#" data-type="prune" title="{{ lang.backup.prune_info }}"><i class="bi bi-scissors"></i> {{ lang.backup.prune_now }}</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div id="backup_status_alerts"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form class="form-horizontal" id="backup_settings" role="form" autocapitalize="none" autocorrect="off" autocomplete="off">
|
|
<legend class="fs-5 fw-semibold mb-0" style="{{ legend_style }}">{{ lang.backup.settings }}</legend>
|
|
<hr />
|
|
{# RESTIC_BACKUP_MODE of mailcow.conf as the backup container reports it, filled by js/site/backup.js #}
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.scope_info }}"></i>
|
|
<span class="control-label">{{ lang.backup.scope }}</span>
|
|
</div>
|
|
<div class="col-sm-9 pt-sm-2 backup-scope">
|
|
<div><span class="fw-semibold backup-scope-title"></span> <small class="text-muted font-monospace ms-1 backup-scope-var"></small></div>
|
|
<div class="small mt-1 d-none backup-scope-in"><i class="bi bi-check-lg text-success me-1"></i><span></span></div>
|
|
<div class="small d-none backup-scope-out"><i class="bi bi-x-lg text-danger me-1"></i><span></span></div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_target">{{ lang.backup.target }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<select class="form-control" name="target" id="backup_target">
|
|
<option value="s3">{{ lang.backup.target_s3 }}</option>
|
|
<option value="sftp">{{ lang.backup.target_sftp }}</option>
|
|
<option value="rest">{{ lang.backup.target_rest }}</option>
|
|
<option value="local">{{ lang.backup.target_local }}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="backup-target" data-target="s3">
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.s3_endpoint_info }}"></i>
|
|
<label class="control-label" for="backup_s3_endpoint">{{ lang.backup.s3_endpoint }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<input type="url" class="form-control" name="s3_endpoint" id="backup_s3_endpoint" maxlength="255" placeholder="https://s3.eu-central-1.amazonaws.com">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_s3_bucket">{{ lang.backup.s3_bucket }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<input type="text" class="form-control" name="s3_bucket" id="backup_s3_bucket" maxlength="63">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_s3_path">{{ lang.backup.s3_path }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="row g-2">
|
|
<div class="col-md-7"><input type="text" class="form-control" name="s3_path" id="backup_s3_path" maxlength="255" placeholder="{{ lang.backup.optional }}"></div>
|
|
<div class="col-md-5">
|
|
<div class="input-group">
|
|
<label class="input-group-text" for="backup_s3_region">{{ lang.backup.s3_region }}</label>
|
|
<input type="text" class="form-control" name="s3_region" id="backup_s3_region" maxlength="64" placeholder="{{ lang.backup.optional }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_s3_access_key">{{ lang.backup.s3_access_key }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<input type="text" class="form-control" name="s3_access_key" id="backup_s3_access_key" maxlength="255">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_s3_secret_key">{{ lang.backup.s3_secret_key }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<input type="password" class="form-control backup-secret" name="s3_secret_key" id="backup_s3_secret_key" maxlength="255" autocomplete="new-password" data-formcache-skip>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="offset-sm-3 col-sm-9">
|
|
<div class="form-check">
|
|
<input type="checkbox" class="form-check-input" name="s3_path_style" value="1" id="backup_s3_path_style">
|
|
<label class="form-check-label" for="backup_s3_path_style">{{ lang.backup.s3_path_style }}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="backup-target" data-target="sftp">
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_sftp_host">{{ lang.backup.sftp_host }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="row g-2">
|
|
<div class="col-md-8"><input type="text" class="form-control" name="sftp_host" id="backup_sftp_host" maxlength="253" placeholder="backup.example.org"></div>
|
|
<div class="col-md-4">
|
|
<div class="input-group">
|
|
<label class="input-group-text" for="backup_sftp_port">{{ lang.backup.sftp_port }}</label>
|
|
<input type="number" class="form-control" name="sftp_port" id="backup_sftp_port" min="1" max="65535">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_sftp_user">{{ lang.backup.sftp_user }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="row g-2">
|
|
<div class="col-md-5"><input type="text" class="form-control" name="sftp_user" id="backup_sftp_user" maxlength="64"></div>
|
|
<div class="col-md-7">
|
|
<div class="input-group">
|
|
<label class="input-group-text" for="backup_sftp_path">{{ lang.backup.sftp_path }}</label>
|
|
<input type="text" class="form-control" name="sftp_path" id="backup_sftp_path" maxlength="255" placeholder="mailcow" title="{{ lang.backup.sftp_path_info }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.sftp_public_key_info }}"></i>
|
|
<label class="control-label" for="backup_sftp_public_key">{{ lang.backup.sftp_public_key }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="input-group">
|
|
<input type="text" class="form-control font-monospace" id="backup_sftp_public_key" readonly>
|
|
<button class="btn btn-secondary backup-copy" type="button" data-copy="#backup_sftp_public_key"><i class="bi bi-clipboard"></i> {{ lang.backup.copy }}</button>
|
|
</div>
|
|
<small class="text-muted d-none backup-key-missing">{{ lang.backup.sftp_public_key_missing }}</small>
|
|
<small class="text-muted d-none text-break backup-host-key" title="{{ lang.backup.sftp_host_key_info }}">{{ lang.backup.sftp_host_key }}: <code></code></small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="backup-target" data-target="rest">
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.rest_url_info }}"></i>
|
|
<label class="control-label" for="backup_rest_url">{{ lang.backup.rest_url }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<input type="url" class="form-control" name="rest_url" id="backup_rest_url" maxlength="255" placeholder="https://backup.example.org:8000/mailcow">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<label class="control-label" for="backup_rest_user">{{ lang.backup.rest_user }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="row g-2">
|
|
<div class="col-md-5"><input type="text" class="form-control" name="rest_user" id="backup_rest_user" maxlength="64" placeholder="{{ lang.backup.optional }}"></div>
|
|
<div class="col-md-7">
|
|
<div class="input-group">
|
|
<label class="input-group-text" for="backup_rest_password">{{ lang.backup.rest_password }}</label>
|
|
<input type="password" class="form-control backup-secret" name="rest_password" id="backup_rest_password" maxlength="255" autocomplete="new-password" data-formcache-skip>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="backup-target" data-target="local">
|
|
<div class="row mb-3">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.local_path_info }}"></i>
|
|
<label class="control-label" for="backup_local_path">{{ lang.backup.local_path }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<input type="text" class="form-control" name="local_path" id="backup_local_path" maxlength="255" placeholder="mailcow">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.password_info }}"></i>
|
|
<label class="control-label" for="backup_password">{{ lang.backup.password }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="input-group">
|
|
<input type="password" class="form-control backup-secret" name="password" id="backup_password" maxlength="255" autocomplete="new-password" data-formcache-skip>
|
|
<button class="btn btn-secondary backup-password-generate" type="button"><i class="bi bi-arrow-repeat"></i> {{ lang.backup.password_generate }}</button>
|
|
</div>
|
|
<small class="d-none backup-password-change"><i class="bi bi-exclamation-triangle-fill text-warning"></i> {{ lang.backup.password_change }}</small>
|
|
<div class="form-check mt-1 backup-password-confirm">
|
|
<input type="checkbox" class="form-check-input" name="password_confirmed" value="1" id="backup_password_confirmed">
|
|
<label class="form-check-label fw-semibold" for="backup_password_confirmed" title="{{ lang.backup.password_confirmed }}">{{ lang.backup.password_confirmed_short }}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3 mb-4">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.schedule_time_info|format(backup_timezone) }}"></i>
|
|
<label class="control-label" for="backup_enabled">{{ lang.backup.schedule }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="form-check form-switch mb-3">
|
|
<input type="checkbox" class="form-check-input" role="switch" name="enabled" value="1" id="backup_enabled">
|
|
<label class="form-check-label" for="backup_enabled">{{ lang.backup.enabled_label }}</label>
|
|
</div>
|
|
{# a new entry of the schedule (weekdays and time, no names); js/site/backup.js lists the entries below as schedule #}
|
|
<div class="d-flex flex-wrap align-items-center column-gap-4 row-gap-2 backup-schedule-new" data-setting="schedule">
|
|
<div class="btn-group backup-schedule-days" role="group" aria-label="{{ lang.backup.schedule_days }}">
|
|
{% for day in [1, 2, 3, 4, 5, 6, 0] %}
|
|
<input type="checkbox" class="btn-check" id="backup_schedule_day_{{ day }}" value="{{ day }}" autocomplete="off">
|
|
<label class="btn btn-outline-secondary btn-check-label" for="backup_schedule_day_{{ day }}" title="{{ lang.backup['weekday_' ~ day] }}">{{ lang.backup['weekday_' ~ day]|slice(0, 2) }}</label>
|
|
{% endfor %}
|
|
</div>
|
|
<div class="d-flex flex-wrap align-items-center gap-2">
|
|
<span>{{ lang.backup.schedule_at }}</span>
|
|
<input type="time" class="form-control w-auto backup-schedule-time" aria-label="{{ lang.backup.schedule_time }}">
|
|
<button type="button" class="btn btn-secondary backup-schedule-add"><i class="bi bi-plus-lg"></i> {{ lang.backup.schedule_add }}</button>
|
|
</div>
|
|
</div>
|
|
<ol class="mt-3 mb-0 ps-4 backup-schedule-list" aria-label="{{ lang.backup.schedule }}"></ol>
|
|
<div class="mt-3 text-muted d-none backup-schedule-none">{{ lang.backup.schedule_none }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2" role="group" aria-labelledby="backup_keep_label">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.keep_info }}"></i>
|
|
<div class="control-label" id="backup_keep_label">{{ lang.backup.keep }}</div>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="d-flex flex-wrap align-items-center gap-2">
|
|
{% for keep in ['hourly', 'daily', 'weekly', 'monthly', 'yearly'] %}
|
|
<div class="input-group w-auto backup-keep-{{ keep }}">
|
|
<input type="number" class="form-control" style="max-width:5.5rem" name="keep_{{ keep }}" id="backup_keep_{{ keep }}" min="0" max="1000">
|
|
<label class="input-group-text" for="backup_keep_{{ keep }}">{{ lang.backup['keep_' ~ keep] }}</label>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.notify_email_info }}"></i>
|
|
<label class="control-label" for="backup_notify_email">{{ lang.backup.notify_email }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<input type="text" class="form-control" name="notify_email" id="backup_notify_email" placeholder="admin@example.org, ops@example.org">
|
|
</div>
|
|
</div>
|
|
|
|
<legend class="fs-6 fw-semibold mb-0 mt-3" style="{{ legend_style }}">
|
|
<button type="button" class="btn btn-link p-0 text-reset text-decoration-none fw-semibold backup-collapse-toggle" data-bs-toggle="collapse" data-bs-target="#backup_advanced" aria-expanded="false" aria-controls="backup_advanced"><i class="bi bi-plus-square"></i> {{ lang.backup.advanced }}</button>
|
|
<small class="text-muted fw-normal">({{ lang.backup.advanced_info }})</small>
|
|
</legend>
|
|
<hr />
|
|
<div id="backup_advanced" class="collapse">
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.prune_weekday_info }}"></i>
|
|
<label class="control-label" for="backup_prune_weekday">{{ lang.backup.prune_weekday }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<select class="form-control" name="prune_weekday" id="backup_prune_weekday">
|
|
{% for day in [1, 2, 3, 4, 5, 6, 0] %}
|
|
<option value="{{ day }}">{{ lang.backup['weekday_' ~ day] }}</option>
|
|
{% endfor %}
|
|
<option value="">{{ lang.backup.weekday_never }}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.max_unused_info }}"></i>
|
|
<label class="control-label" for="backup_max_unused">{{ lang.backup.max_unused }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="input-group w-auto d-inline-flex">
|
|
<input type="number" class="form-control" style="max-width:6rem" name="max_unused" id="backup_max_unused" min="0" max="100">
|
|
<span class="input-group-text">%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.check_subset_info }}"></i>
|
|
<label class="control-label" for="backup_check_subset">{{ lang.backup.check_subset }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="input-group w-auto d-inline-flex">
|
|
<input type="number" class="form-control" style="max-width:6rem" name="check_subset" id="backup_check_subset" min="0" max="365">
|
|
<span class="input-group-text">{{ lang.backup.check_subset_unit }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-2">
|
|
<div class="offset-sm-3 col-sm-9">
|
|
<div class="form-check">
|
|
<input type="checkbox" class="form-check-input" name="include_index" value="1" id="backup_include_index">
|
|
<label class="form-check-label" for="backup_include_index">{{ lang.backup.include_index }}</label>
|
|
</div>
|
|
<div class="form-check ms-4">
|
|
<input type="checkbox" class="form-check-input" name="include_fts" value="1" id="backup_include_fts">
|
|
<label class="form-check-label" for="backup_include_fts">{{ lang.backup.include_fts }}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-3 d-flex align-items-start justify-content-sm-end pt-sm-2">
|
|
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ lang.backup.limit_upload_info }}"></i>
|
|
<label class="control-label" for="backup_limit_upload">{{ lang.backup.limit_upload }}</label>
|
|
</div>
|
|
<div class="col-sm-9">
|
|
<div class="input-group w-auto d-inline-flex">
|
|
<input type="number" class="form-control" style="max-width:9rem" name="limit_upload" id="backup_limit_upload" min="0" max="100000000">
|
|
<span class="input-group-text">KiB/s</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="offset-sm-3 col-sm-9">
|
|
<button type="submit" class="btn btn-sm btn-xs-lg d-block d-sm-inline btn-success backup-settings-save"><i class="bi bi-check-lg"></i> {{ lang.backup.save }}</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="backup-jobs-section d-none mt-4">
|
|
<legend class="fs-5 fw-semibold mb-0" style="{{ legend_style }}">{{ lang.backup.jobs }}</legend>
|
|
<hr />
|
|
<table id="backup_jobs_table" class="table table-striped dt-responsive w-100"></table>
|
|
</div>
|
|
|
|
<div class="backup-snapshots-section d-none mt-4">
|
|
<legend class="fs-5 fw-semibold mb-0" style="{{ legend_style }}">
|
|
<button type="button" class="btn btn-link p-0 text-reset text-decoration-none fw-semibold fs-5 backup-collapse-toggle" data-bs-toggle="collapse" data-bs-target="#backup_snapshots_collapse" aria-expanded="false" aria-controls="backup_snapshots_collapse"><i class="bi bi-plus-square"></i> {{ lang.backup.snapshots }} (<span class="backup-snapshot-count">0</span>)</button>
|
|
</legend>
|
|
<hr />
|
|
<div id="backup_snapshots_collapse" class="collapse">
|
|
<table id="backup_snapshots_table" class="table table-striped dt-responsive w-100"></table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|