Pause blocking, blocked clients and a blocked line in the statistics, compact view picker

jarl block pause|resume (and the Blocking page) lets every name through
for a while; jarld resumes on time. The lists stay loaded: the rules zone
just passes everything. Statistics gain the clients with the most blocked
queries and blocked queries on the queries chart. The view choice in the
blocking forms is a dropdown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adamandClaude Opus 5.5 committed 2026-10-10 11:10:44 +00:00
1 parent 9fc23310bd
commit 27d1f9e538
31 files changed
+417 -45

No files matched your search

+36
View File
@@ -1,12 +1,14 @@
package engine
import (
"context"
"encoding/json"
"fmt"
"net/url"
"regexp"
"slices"
"strings"
"time"
"jarl/internal/auth"
"jarl/internal/blocking"
@@ -270,3 +272,37 @@ func (x *expander) blockRuleCreate(req Request) ([]model.Op, error) {
return ruleLabel(r), nil
})
}
func applyBlockingPause(st *model.State, op model.Op, c *applyCtx) error {
if err := c.require(blockingAction()); err != nil {
return err
}
var in BlockingPauseInput
if err := decode(op.Data, &in); err != nil {
return err
}
if in.Until != nil && in.Until.Sub(c.now) > MaxBlockingPause+time.Minute {
return errf(KindBadRequest, "blocking can be paused for at most %s; disable lists to stop using them", MaxBlockingPause)
}
st.Settings.BlockingPausedUntil = in.Until
return nil
}
// ResumeBlocking ends a pause whose time is up, and returns when the
// current pause ends (zero when blocking isn't paused).
func (e *Engine) ResumeBlocking(ctx context.Context) time.Time {
st, err := e.store.LoadState(ctx)
if err != nil || st.Settings.BlockingPausedUntil == nil {
return time.Time{}
}
until := *st.Settings.BlockingPausedUntil
if e.Now().Before(until) {
return until
}
if _, err := e.Submit(ctx, []Request{NewRequest(OpBlockingPause, 0, BlockingPauseInput{})}, auth.System, "system", "resume blocking after the pause", ApplyOptions{}); err != nil {
e.log.Warn("resuming blocking after the pause failed; it will be tried again", "err", err)
return e.Now().Add(time.Minute)
}
e.log.Info("blocking resumed after the pause")
return time.Time{}
}