disallow to disable guard during focus
docker / image (push) Failing after 24s
lint / ruff (push) Failing after 28s
tests / backend (push) Successful in 37s
tests / desktop (push) Successful in 22s
tests / android-core (push) Successful in 49s
tests / web (push) Successful in 1m20s
android / apk (push) Successful in 8m49s
docker / image (push) Failing after 24s
lint / ruff (push) Failing after 28s
tests / backend (push) Successful in 37s
tests / desktop (push) Successful in 22s
tests / android-core (push) Successful in 49s
tests / web (push) Successful in 1m20s
android / apk (push) Successful in 8m49s
This commit is contained in:
21 files changed
+481
-43
No files matched your search
@@ -88,7 +88,10 @@ export interface BlockerPolicy {
|
||||
reason: string;
|
||||
mode: string;
|
||||
enabled: boolean;
|
||||
strict: boolean;
|
||||
/** The guard is on and an interval is live, so it may not be switched off. Not the same as `active`: scheduled mode outside its window is inactive and still locked. */
|
||||
locked: boolean;
|
||||
/** Why it is locked, in the server's words — `""` when it is not. */
|
||||
lock_reason: string;
|
||||
redirect_ip: string;
|
||||
domains: string[];
|
||||
apps: string[];
|
||||
@@ -209,7 +212,6 @@ export interface AppSettings {
|
||||
blocked_apps: string[];
|
||||
kill_blocked_apps: boolean;
|
||||
schedule: { label: string; start: string; end: string; days: number[] }[];
|
||||
strict: boolean;
|
||||
redirect_ip: string;
|
||||
app_poll_seconds: number;
|
||||
notify_on_block: boolean;
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
* are answered by the desktop app's local DNS stub for the zones it can route.
|
||||
* The stats show what is really in force (`domains` is empty while blocking is
|
||||
* off) and every banner says plainly what could not be enforced.
|
||||
*
|
||||
* The switch is one-way while you work: the server refuses to turn the guard off
|
||||
* while an interval is running or paused, so `policy.locked` greys it — turning
|
||||
* it *on* is never refused.
|
||||
*/
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
@@ -97,6 +101,8 @@ export default function BlockerPage({ onToast }: { onToast: (message: string) =>
|
||||
[unexpandable],
|
||||
);
|
||||
const badExpansions = policy.data?.invalid_expansions ?? [];
|
||||
/** The server has already folded "and the guard is on" in, so an off guard stays switchable on. */
|
||||
const locked = policy.data?.locked ?? false;
|
||||
const top = useMemo(() => events.data?.by_target.slice(0, 8) ?? [], [events.data]);
|
||||
|
||||
return (
|
||||
@@ -106,15 +112,23 @@ export default function BlockerPage({ onToast }: { onToast: (message: string) =>
|
||||
title={policy.data?.active ? "Blocking is on" : "Blocking is off"}
|
||||
caption="Rules live here; the desktop app enforces them on your machine."
|
||||
actions={
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={blocker?.enabled ?? false}
|
||||
onChange={(event) => void patch({ enabled: event.target.checked })}
|
||||
/>
|
||||
}
|
||||
label="Enabled"
|
||||
/>
|
||||
<Stack alignItems="flex-end">
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={blocker?.enabled ?? false}
|
||||
disabled={locked}
|
||||
onChange={(event) => void patch({ enabled: event.target.checked })}
|
||||
/>
|
||||
}
|
||||
label="Enabled"
|
||||
/>
|
||||
{locked && (
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{policy.data?.lock_reason}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
Reference in new issue
Block a user