mail/app/templates/rules/index.html
deeily 5024bf9a8d init: full mail stack — phases 0..8 (web client, admin, IMAP/SMTP,
sieve, search, sessions, dramatiq, deploy/install, ELK, monitoring)
2026-04-29 16:30:43 +03:00

160 lines
8.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'layout/base.html' %}
{% block title %}Правила{% endblock %}
{% block body %}
<div class="content">
<div class="card">
<div class="card-head"><div class="card-title">Правила обработки входящих</div></div>
<table class="tbl">
<thead>
<tr><th style="width:20px"></th><th>Название</th><th>Условие</th><th>Действие</th><th style="width:160px"></th></tr>
</thead>
<tbody>
{% for r in rules %}
<tr>
<td><span class="dot dot-{{ 'green' if r.enabled else 'gray' }}"></span></td>
<td>
<strong>{{ r.name }}</strong>
<div style="display:flex;gap:4px;margin-top:3px;flex-wrap:wrap">
{% if r.apply_to_existing %}<span class="badge badge-gray" title="Применяется к уже существующим письмам">к существующим</span>{% endif %}
{% if r.continue_chain %}<span class="badge badge-gray" title="После срабатывания применяются следующие правила">цепочка</span>{% endif %}
{% if r.apply_to_spam %}<span class="badge badge-amber" title="Фильтр применяется к спаму">спам</span>{% endif %}
</div>
</td>
<td style="color:var(--color-text-secondary);font-size:12px">
{{ fields[r.field] }} {{ ops[r.op] }} «<em>{{ r.value }}</em>»
</td>
<td style="font-size:12px">
{{ actions[r.action] }}
{% if r.action == 'move' %} <span class="badge badge-blue">{{ r.target }}</span>
{% elif r.action in ('forward_copy', 'autoreply') %} <span style="color:var(--color-text-secondary)">→ {{ r.target[:50] }}{% if r.target|length > 50 %}…{% endif %}</span>
{% endif %}
</td>
<td style="text-align:right;white-space:nowrap">
<div style="display:inline-flex;gap:6px;align-items:center;justify-content:flex-end">
<form method="post" action="{{ url_for('rules.toggle', rid=r.id) }}" style="display:inline">
<button class="btn btn-sm" type="submit">{{ 'Выкл' if r.enabled else 'Вкл' }}</button>
</form>
<form method="post" action="{{ url_for('rules.delete', rid=r.id) }}" style="display:inline"
onsubmit="return confirm('Удалить правило?')">
<button class="btn btn-sm btn-danger" type="submit">Удалить</button>
</form>
</div>
</td>
</tr>
{% else %}
<tr><td colspan="5" style="text-align:center;color:var(--color-text-tertiary);padding:20px">Правил нет</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="card">
<div class="card-head"><div class="card-title">Новое правило</div></div>
<form method="post" action="{{ url_for('rules.create') }}" id="rule-form">
<div class="card-body">
<div class="form-row">
<label>Название</label>
<input type="text" name="name" placeholder="Например: Счета в отдельную папку" required>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 2fr;gap:10px">
<div class="form-row">
<label>Поле</label>
<select name="field">
{% for k, t in fields_list %}<option value="{{ k }}">{{ t }}</option>{% endfor %}
</select>
</div>
<div class="form-row">
<label>
Оператор
<span title="содержит — ищет подстроку; равно — точное совпадение; начинается с — префикс; больше, чем — только для размера"
style="color:var(--color-text-tertiary);cursor:help"></span>
</label>
<select name="op">
{% for k, t in ops_list %}<option value="{{ k }}">{{ t }}</option>{% endfor %}
</select>
</div>
<div class="form-row">
<label>Значение</label>
<input type="text" name="value" placeholder="что искать" required>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 2fr;gap:10px">
<div class="form-row">
<label>Действие</label>
<select name="action" id="rule-action">
{% for k, t in actions_list %}<option value="{{ k }}">{{ t }}</option>{% endfor %}
</select>
</div>
<div class="form-row" id="rule-target-row">
<label id="rule-target-label">Параметр действия</label>
<input type="text" name="target" id="rule-target-input" placeholder="">
<select name="target_folder" id="rule-target-folder" style="display:none">
{% for key, title, ic, is_user in folders %}<option value="{{ key }}">{{ title }}</option>{% endfor %}
</select>
<textarea name="target_text" id="rule-target-text" rows="4" style="display:none;font-family:inherit" placeholder="Текст автоответа…"></textarea>
</div>
</div>
<div style="margin-top:12px;padding:12px;background:var(--color-background-secondary);border-radius:var(--border-radius-md)">
<label style="display:flex;gap:8px;align-items:center;padding:4px 0;text-transform:none;letter-spacing:0;color:var(--color-text-primary);font-size:13px">
<input type="checkbox" name="apply_to_existing" style="width:auto">
Применить к письмам, которые уже находятся в папке
</label>
<label style="display:flex;gap:8px;align-items:center;padding:4px 0;text-transform:none;letter-spacing:0;color:var(--color-text-primary);font-size:13px">
<input type="checkbox" name="continue_chain" style="width:auto" checked>
После срабатывания этого фильтра применять другие фильтры
</label>
<label style="display:flex;gap:8px;align-items:center;padding:4px 0;text-transform:none;letter-spacing:0;color:var(--color-text-primary);font-size:13px">
<input type="checkbox" name="apply_to_spam" style="width:auto">
Применять фильтр к спаму
</label>
</div>
</div>
<div class="card-head" style="border-top:0.5px solid var(--color-border-tertiary);border-bottom:none;justify-content:flex-end">
<button type="submit" class="btn btn-primary">Добавить правило</button>
</div>
</form>
</div>
</div>
<script>
(function(){
const sel = document.getElementById('rule-action');
const label = document.getElementById('rule-target-label');
const inp = document.getElementById('rule-target-input');
const fld = document.getElementById('rule-target-folder');
const ta = document.getElementById('rule-target-text');
function sync(){
inp.style.display = 'none'; fld.style.display = 'none'; ta.style.display = 'none';
inp.name = '__off'; fld.name = '__off'; ta.name = '__off';
switch(sel.value){
case 'move':
label.textContent = 'Папка';
fld.style.display = 'block'; fld.name = 'target';
break;
case 'forward_copy':
label.textContent = 'Адрес для пересылки';
inp.style.display = 'block'; inp.name = 'target';
inp.placeholder = 'email@domain';
break;
case 'autoreply':
label.textContent = 'Текст авто-ответа';
ta.style.display = 'block'; ta.name = 'target';
break;
default:
label.textContent = '—';
inp.style.display = 'block'; inp.name = 'target';
inp.placeholder = '(не требуется)';
}
}
sel.addEventListener('change', sync);
sync();
})();
</script>
{% endblock %}