2026-08-14 13:04:55 +01:00
{{define "webmail_rules.html"}}
<!DOCTYPE html>
< html lang = "en" data-bs-theme = "dark" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Filter Rules - Webmail</ title >
< link href = "/webmail/static/vendor/bootstrap/css/bootstrap.min.css" rel = "stylesheet" >
< link href = "/webmail/static/vendor/bootstrap-icons/font/bootstrap-icons.css" rel = "stylesheet" >
< style >
body { background-color : #1a1a1a ; color : #e0e0e0 ; }
. card { background-color : #2d2d2d ; border : 1 px solid #404040 ; }
. table-dark { --bs-table-bg : #2d2d2d ; --bs-table-border-color : #404040 ; }
</ style >
</ head >
< body >
{{template "csrf_script" .}}
< nav class = "navbar navbar-expand-lg navbar-dark bg-dark mb-4" >
< div class = "container-fluid" >
< span class = "navbar-brand mb-0 h1" >< i class = "bi bi-inbox-fill me-2" ></ i > Webmail < small class = "text-muted" > {{.mailbox.Email}}</ small ></ span >
< div class = "navbar-nav flex-row gap-2 ms-auto" >
< a href = "/webmail/mail/INBOX" class = "btn btn-outline-light btn-sm" >< i class = "bi bi-envelope me-1" ></ i > Mail</ a >
< button type = "button" onclick = "openCompose('/webmail/mail/compose')" class = "btn btn-outline-light btn-sm" >< i class = "bi bi-pencil-square me-1" ></ i > Compose</ button >
< a href = "/webmail/rules" class = "btn btn-light btn-sm" >< i class = "bi bi-funnel me-1" ></ i > Rules</ a >
< a href = "/webmail/certs" class = "btn btn-outline-light btn-sm" >< i class = "bi bi-shield-lock me-1" ></ i > Certs</ a >
2026-08-15 16:31:27 +01:00
< a href = "/webmail/signatures" class = "btn btn-outline-light btn-sm" >< i class = "bi bi-pen me-1" ></ i > Signatures</ a >
2026-08-14 13:04:55 +01:00
< a href = "/webmail/account" class = "btn btn-outline-light btn-sm" >< i class = "bi bi-gear me-1" ></ i > Account</ a >
< form method = "post" action = "/webmail/logout" class = "d-inline" >
< button type = "submit" class = "btn btn-outline-light btn-sm" >< i class = "bi bi-box-arrow-right me-1" ></ i > Sign out</ button >
</ form >
</ div >
</ div >
</ nav >
< div class = "toast-container position-fixed top-0 end-0 p-3" style = "z-index: 1090;" >
{{range .flashes}}
2026-08-15 16:31:27 +01:00
< div class = "toast align-items-center text-bg-{{if eq .Category " error "}} danger {{ else }}{{. Category }}{{ end }} border-0 " role = "alert" aria-live = "assertive" aria-atomic = "true" >
2026-08-14 13:04:55 +01:00
< div class = "d-flex" >
< div class = "toast-body" >
< i class = "bi bi-{{if eq .Category " error "}} exclamation-triangle {{ else if eq . Category " success "}} check-circle {{ else }} info-circle {{ end }} me-2 " ></ i >
{{.Message}}
</ div >
< button type = "button" class = "btn-close btn-close-white me-2 m-auto" data-bs-dismiss = "toast" aria-label = "Close" ></ button >
</ div >
</ div >
{{end}}
</ div >
< div class = "container pb-5" >
< div class = "d-flex justify-content-between align-items-center mb-4" >
< h4 class = "mb-0" >< i class = "bi bi-funnel me-2" ></ i > Filter Rules</ h4 >
</ div >
< div class = "alert alert-info" >
< i class = "bi bi-info-circle me-2" ></ i > Rules run in priority order (lowest first) at delivery time; the first match wins. "Move to folder" delivers into a separate folder instead of INBOX — check < a href = "/webmail/mail/INBOX" class = "alert-link" > Mail</ a > once something's actually landed there.
</ div >
< div class = "card mb-4" >
< div class = "card-header" >< h5 class = "mb-0" >< i class = "bi bi-plus-circle me-2" ></ i > Add Rule</ h5 ></ div >
< div class = "card-body" >
< form method = "POST" action = "/webmail/rules/add" >
< div class = "row g-2 align-items-end mb-3" >
< div class = "col-auto" >
< label class = "form-label" > Priority</ label >
< input type = "number" class = "form-control" name = "priority" value = "0" style = "width: 90px;" >
</ div >
< div class = "col-auto" >
< label class = "form-label" > Match</ label >
< select class = "form-select" name = "match_type" >
< option value = "all" > ALL of the following (AND)</ option >
< option value = "any" > ANY of the following (OR)</ option >
</ select >
</ div >
</ div >
< div id = "conditions_container" ></ div >
< button type = "button" id = "add_condition" class = "btn btn-outline-light btn-sm mb-3" >< i class = "bi bi-plus-lg me-1" ></ i > Add condition</ button >
< div class = "row g-2 align-items-end" >
< div class = "col-auto" >
< label class = "form-label" > Then</ label >
< select class = "form-select" name = "action" id = "rule_action" >
< option value = "move_to_folder" > Move to folder</ option >
2026-08-15 16:31:27 +01:00
< option value = "mark_as_spam" > Mark as Junk</ option >
2026-08-14 13:04:55 +01:00
< option value = "delete" > Delete</ option >
< option value = "mark_read" > Mark as read</ option >
</ select >
</ div >
< div class = "col-auto" >
< input type = "text" class = "form-control" name = "action_value" id = "rule_action_value" placeholder = "folder name" >
</ div >
< div class = "col-auto" >
< button type = "submit" class = "btn btn-success" >< i class = "bi bi-funnel me-2" ></ i > Add Rule</ button >
</ div >
</ div >
</ form >
< template id = "condition_row_template" >
< div class = "row g-2 align-items-end mb-2 condition-row" >
< div class = "col-auto" >
< label class = "form-label" > If</ label >
< select class = "form-select" name = "condition_field" >
< option value = "from" > From</ option >
< option value = "to" > To</ option >
< option value = "subject" > Subject</ option >
</ select >
</ div >
< div class = "col-auto" >
< select class = "form-select" name = "condition_op" >
< option value = "contains" > contains</ option >
< option value = "equals" > equals</ option >
< option value = "starts_with" > starts with</ option >
</ select >
</ div >
< div class = "col-auto" >
< input type = "text" class = "form-control" name = "condition_value" placeholder = "value" required >
</ div >
< div class = "col-auto" >
< button type = "button" class = "btn btn-outline-danger btn-sm remove-condition" title = "Remove condition" >< i class = "bi bi-x-lg" ></ i ></ button >
</ div >
</ div >
</ template >
</ div >
</ div >
< div class = "card" >
< div class = "card-header" >< h5 class = "mb-0" >< i class = "bi bi-list-ul me-2" ></ i > Existing Rules</ h5 ></ div >
< div class = "card-body p-0" >
{{if .rules}}
< div class = "table-responsive" >
< table class = "table table-dark table-hover mb-0" >
< thead >< tr >< th > Priority</ th >< th > Condition</ th >< th > Action</ th >< th > Status</ th >< th > Actions</ th ></ tr ></ thead >
< tbody >
{{range .rules}}
< tr >
< td > {{.Priority}}</ td >
< td >< code > {{ruleSummary .}}</ code ></ td >
< td >
{{if eq .Action "move_to_folder"}}Move to < strong > {{.ActionValue}}</ strong >
2026-08-15 16:31:27 +01:00
{{else if eq .Action "mark_as_spam"}}< span class = "text-warning" > Mark as Junk</ span >
2026-08-14 13:04:55 +01:00
{{else if eq .Action "delete"}}< span class = "text-danger" > Delete</ span >
{{else}}Mark as read{{end}}
</ td >
< td > {{if .IsActive}}< span class = "badge bg-success" > Active</ span > {{else}}< span class = "badge bg-secondary" > Inactive</ span > {{end}}</ td >
< td >
< form method = "post" action = "/webmail/rules/{{.ID}}/remove" class = "d-inline" >
< button type = "submit" class = "btn btn-outline-danger btn-sm" title = "Remove" data-confirm = "Remove this rule?" >< i class = "bi bi-trash" ></ i ></ button >
</ form >
</ td >
</ tr >
{{end}}
</ tbody >
</ table >
</ div >
{{else}}
< div class = "text-center py-5" >
< i class = "bi bi-funnel text-muted" style = "font-size: 4rem;" ></ i >
< h4 class = "text-muted mt-3" > No rules yet</ h4 >
< p class = "text-muted" > Add one above to automatically sort or act on incoming mail.</ p >
</ div >
{{end}}
</ div >
</ div >
</ div >
< div class = "modal fade" id = "confirmationModal" tabindex = "-1" aria-hidden = "true" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h5 class = "modal-title" >< i class = "bi bi-question-circle me-2" ></ i > Confirm Action</ h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Close" ></ button >
</ div >
< div class = "modal-body" id = "confirmationModalBody" > Are you sure you want to proceed?</ div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal" > Cancel</ button >
< button type = "button" class = "btn btn-danger" id = "confirmationModalConfirm" > Confirm</ button >
</ div >
</ div >
</ div >
</ div >
{{template "compose_widget" .}}
< script src = "/webmail/static/vendor/bootstrap/js/bootstrap.bundle.min.js" ></ script >
< script >
document . addEventListener ( 'DOMContentLoaded' , function () {
document . querySelectorAll ( '.toast' ). forEach ( function ( el ) { new bootstrap . Toast ( el , { delay : 5000 }). show (); });
});
function showConfirmation ( message ) {
return new Promise (( resolve ) => {
const modal = document . getElementById ( 'confirmationModal' );
document . getElementById ( 'confirmationModalBody' ). textContent = message ;
const confirmButton = document . getElementById ( 'confirmationModalConfirm' );
const handleConfirm = () => { resolve ( true ); bootstrap . Modal . getInstance ( modal ). hide (); cleanup (); };
const handleCancel = () => { resolve ( false ); cleanup (); };
const cleanup = () => {
confirmButton . removeEventListener ( 'click' , handleConfirm );
modal . removeEventListener ( 'hidden.bs.modal' , handleCancel );
};
confirmButton . addEventListener ( 'click' , handleConfirm );
modal . addEventListener ( 'hidden.bs.modal' , handleCancel , { once : true });
new bootstrap . Modal ( modal ). show ();
});
}
document . addEventListener ( 'DOMContentLoaded' , function () {
document . querySelectorAll ( '[data-confirm]' ). forEach ( function ( button ) {
button . addEventListener ( 'click' , async function ( e ) {
e . preventDefault ();
if ( await showConfirmation ( this . getAttribute ( 'data-confirm' ))) {
const form = this . closest ( 'form' );
if ( form ) form . submit ();
}
});
});
});
document . getElementById ( 'rule_action' ). addEventListener ( 'change' , function ( e ) {
const valueInput = document . getElementById ( 'rule_action_value' );
valueInput . style . display = e . target . value === 'move_to_folder' ? '' : 'none' ;
});
function addConditionRow () {
const tpl = document . getElementById ( 'condition_row_template' );
const container = document . getElementById ( 'conditions_container' );
const clone = document . importNode ( tpl . content , true );
clone . querySelector ( '.remove-condition' ). addEventListener ( 'click' , function () {
if ( container . children . length > 1 ) {
this . closest ( '.condition-row' ). remove ();
}
});
container . appendChild ( clone );
}
document . getElementById ( 'add_condition' ). addEventListener ( 'click' , addConditionRow );
addConditionRow ();
</ script >
</ body >
</ html >
{{end}}