diff --git a/frontend/src/pages/Nodes.tsx b/frontend/src/pages/Nodes.tsx
index e0f6529..114ba9b 100644
--- a/frontend/src/pages/Nodes.tsx
+++ b/frontend/src/pages/Nodes.tsx
@@ -5,6 +5,7 @@ import { useState } from "react";
import { AgentInstallInfo, api, Node } from "../api/client";
import { DataTable } from "../components/DataTable";
import { iconButtonClass, secondaryButtonClass } from "../components/FormControls";
+import { LoadingOverlay } from "../components/LoadingOverlay";
import { Modal } from "../components/Modal";
import { PageHeader } from "../components/PageHeader";
@@ -47,6 +48,7 @@ export function Nodes() {
return (
<>
+
{nodes.isLoading ?
Loading...
: null}
{nodes.error ?
Failed to load nodes.
: null}
{!nodes.isLoading && !nodes.error ? (
diff --git a/frontend/src/pages/Policies.tsx b/frontend/src/pages/Policies.tsx
index ccc631b..3208c84 100644
--- a/frontend/src/pages/Policies.tsx
+++ b/frontend/src/pages/Policies.tsx
@@ -5,6 +5,7 @@ import { Eye, GitBranch, Pencil, Play, Plus, Trash2 } from "lucide-react";
import { api, Policy, Project, ServiceCatalogItem } from "../api/client";
import { DataTable } from "../components/DataTable";
import { buttonClass, Field, iconButtonClass, inputClass, selectClass } from "../components/FormControls";
+import { LoadingOverlay } from "../components/LoadingOverlay";
import { Modal } from "../components/Modal";
import { PageHeader } from "../components/PageHeader";
@@ -45,6 +46,7 @@ export function Policies() {
const [open, setOpen] = useState(false);
const [editing, setEditing] = useState
(null);
const [form, setForm] = useState(defaultPolicyForm);
+ const [busyMessage, setBusyMessage] = useState("");
const save = useMutation({
mutationFn: () => {
@@ -85,14 +87,24 @@ export function Policies() {
}
async function compile(policy: Policy) {
- const data = await api(`/policies/${policy.id}/compile`, { method: "POST" });
- setPreview(JSON.stringify(data.last_compiled, null, 2));
- await queryClient.invalidateQueries({ queryKey: ["policies"] });
+ setBusyMessage(`Compiling ${policy.name}...`);
+ try {
+ const data = await api(`/policies/${policy.id}/compile`, { method: "POST" });
+ setPreview(JSON.stringify(data.last_compiled, null, 2));
+ await queryClient.invalidateQueries({ queryKey: ["policies"] });
+ } finally {
+ setBusyMessage("");
+ }
}
async function firewallPreview(policy: Policy) {
- const data = await api>(`/firewall/preview/${policy.id}`, { method: "POST" });
- setPreview(JSON.stringify(data, null, 2));
+ setBusyMessage(`Generating preview for ${policy.name}...`);
+ try {
+ const data = await api>(`/firewall/preview/${policy.id}`, { method: "POST" });
+ setPreview(JSON.stringify(data, null, 2));
+ } finally {
+ setBusyMessage("");
+ }
}
function addPolicy() {
@@ -140,6 +152,7 @@ export function Policies() {
return (
<>
+
setOpen(false)}>