diff --git a/backend/alert/service.go b/backend/alert/service.go
index 96745d7..e4fe8af 100644
--- a/backend/alert/service.go
+++ b/backend/alert/service.go
@@ -141,6 +141,7 @@ func (s *Service) SendTest(ctx context.Context, alertType, name, webhook string)
})
if err != nil {
log.Error("Failed to send test alert via %s: %v", service.GetServiceName(), err)
+ return err
}
break
}
diff --git a/client/src/components/header/BlockingTimer.tsx b/client/src/components/header/BlockingTimer.tsx
new file mode 100644
index 0000000..aa66933
--- /dev/null
+++ b/client/src/components/header/BlockingTimer.tsx
@@ -0,0 +1,51 @@
+import { GetRequest } from "@/util";
+import { useEffect, useState } from "react";
+import { toast } from "sonner";
+
+export default function BlockingTimer() {
+ const [timeLeft, setTimeLeft] = useState(0);
+
+ useEffect(() => {
+ async function fetchNotifications() {
+ try {
+ const [code, response] = await GetRequest("pause");
+ if (code !== 200) {
+ toast.warning("Unable to fetch blocking status", {
+ id: "fetch-notifications-error"
+ });
+ return;
+ }
+
+ setTimeLeft(response.timeLeft || 0);
+ } catch {
+ toast.error("Error while fetching notifications");
+ }
+ }
+
+ fetchNotifications();
+
+ const intervalId = setInterval(() => {
+ fetchNotifications();
+ }, 1000);
+
+ return () => clearInterval(intervalId);
+ }, []);
+
+ return (
+
+ {timeLeft === 0 ? (
+
+ Blocking active
+
+ ) : (
+
+ Blocking paused:{" "}
+ {Math.floor(timeLeft / 60)
+ .toString()
+ .padStart(2, "0")}
+ :{(timeLeft % 60).toString().padStart(2, "0")}
+
+ )}
+
+ );
+}
diff --git a/client/src/components/nav-actions.tsx b/client/src/components/header/nav-actions.tsx
similarity index 81%
rename from client/src/components/nav-actions.tsx
rename to client/src/components/header/nav-actions.tsx
index 7a74efa..d057994 100644
--- a/client/src/components/nav-actions.tsx
+++ b/client/src/components/header/nav-actions.tsx
@@ -6,7 +6,6 @@ import {
DialogClose,
DialogContent,
DialogDescription,
- DialogFooter,
DialogHeader,
DialogTitle
} from "@/components/ui/dialog";
@@ -38,8 +37,9 @@ import {
import { compare } from "compare-versions";
import { JSX, useEffect, useState } from "react";
import { toast } from "sonner";
-import { Metrics } from "./server-statistics";
-import { Input } from "./ui/input";
+import { Metrics } from "../server-statistics";
+import { Input } from "../ui/input";
+import { ToggleGroup, ToggleGroupItem } from "../ui/toggle-group";
const data = [
[
@@ -290,28 +290,74 @@ export default function PauseBlockingDialog({
}
};
+ const formatTime = (seconds: number) => {
+ const mins = Math.floor(seconds / 60);
+ const secs = seconds % 60;
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
+ };
+
return (
-
+
{pauseStatus?.paused ? "Blocking Paused" : "Pause Blocking"}
-
+
{pauseStatus?.paused
- ? `Blocking is currently paused. Remaining time: ${remainingTime} seconds.`
- : "This will temporarily pause domain blocking, allowing all traffic to pass through."}
+ ? "Blocking is currently paused"
+ : "Temporarily allow all traffic through"}
- {!pauseStatus?.paused ? (
- <>
-
-
+ ) : (
+
+
+
+
- Duration (seconds)
+ setPauseTime(10)}>
+ 10s
+
+ setPauseTime(30)}>
+ 30s
+
+ setPauseTime(60)}>
+ 1m
+
+ setPauseTime(300)}>
+ 5m
+
+ setPauseTime(600)}>
+ 10m
+
+
+
+
+
+
setPauseTime(e.target.valueAsNumber)}
- className="w-full"
/>
-
-
)}
);
diff --git a/client/src/components/notifications.tsx b/client/src/components/header/notifications.tsx
similarity index 100%
rename from client/src/components/notifications.tsx
rename to client/src/components/header/notifications.tsx
diff --git a/client/src/app/theme/theme-context.tsx b/client/src/components/header/theme/theme-context.tsx
similarity index 100%
rename from client/src/app/theme/theme-context.tsx
rename to client/src/components/header/theme/theme-context.tsx
diff --git a/client/src/app/theme/theme-provider.tsx b/client/src/components/header/theme/theme-provider.tsx
similarity index 100%
rename from client/src/app/theme/theme-provider.tsx
rename to client/src/components/header/theme/theme-provider.tsx
diff --git a/client/src/app/theme/toggle-theme.tsx b/client/src/components/header/theme/toggle-theme.tsx
similarity index 100%
rename from client/src/app/theme/toggle-theme.tsx
rename to client/src/components/header/theme/toggle-theme.tsx
diff --git a/client/src/app/theme/use-theme.ts b/client/src/components/header/theme/use-theme.ts
similarity index 100%
rename from client/src/app/theme/use-theme.ts
rename to client/src/components/header/theme/use-theme.ts
diff --git a/client/src/components/site-header.tsx b/client/src/components/site-header.tsx
index 81aa6ed..6e625ff 100644
--- a/client/src/components/site-header.tsx
+++ b/client/src/components/site-header.tsx
@@ -1,9 +1,10 @@
import { Separator } from "@/components/ui/separator";
import { SidebarTrigger } from "@/components/ui/sidebar";
import { useLocation } from "react-router-dom";
-import { NavActions } from "./nav-actions";
-import Notifications from "./notifications";
-import { ModeToggle } from "@/app/theme/toggle-theme";
+import { NavActions } from "./header/nav-actions";
+import Notifications from "./header/notifications";
+import { ModeToggle } from "@/components/header/theme/toggle-theme";
+import BlockingTimer from "./header/BlockingTimer";
interface PageInfo {
title: string;
@@ -96,6 +97,7 @@ export function SiteHeader() {
+
diff --git a/client/src/pages/app.tsx b/client/src/pages/app.tsx
index 56970c6..0fcf9ec 100644
--- a/client/src/pages/app.tsx
+++ b/client/src/pages/app.tsx
@@ -15,7 +15,7 @@ import { Whitelist } from "./whitelist";
import { GenerateQuote } from "@/quotes";
import Login from "./login";
import { FileXIcon } from "@phosphor-icons/react";
-import { ThemeProvider } from "@/app/theme/theme-provider";
+import { ThemeProvider } from "@/components/header/theme/theme-provider";
function NotFound() {
return (