<${Icon} name="lock" className="h-4 w-4" />
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
index 21fc7c41270..12bcf28065d 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
@@ -184,7 +184,16 @@ export function useChat(threadId) {
} = useHistory(threadId, { getPendingMessages, setPendingMessages });
const [isProcessing, setIsProcessing] = React.useState(false);
- const [pendingGate, setPendingGate] = React.useState(null);
+ const [pendingGate, setPendingGateState] = React.useState(null);
+ const pendingGateRef = React.useRef(pendingGate);
+ const setPendingGate = React.useCallback((next) => {
+ const current = pendingGateRef.current;
+ const value =
+ typeof next === "function" ? next(current) : next;
+ if (Object.is(value, current)) return;
+ pendingGateRef.current = value;
+ setPendingGateState(value);
+ }, []);
const [stateThreadId, setStateThreadId] = React.useState(threadId);
const toolActivityStateRef = React.useRef(createToolActivityState());
const locallyResolvedGatesRef = React.useRef(new Map());
@@ -224,11 +233,15 @@ export function useChat(threadId) {
if (stateThreadId !== threadId) {
setStateThreadId(threadId);
setIsProcessing(false);
- setPendingGate(null);
+ setPendingGateState(null);
setActiveRunState(null);
setChannelConnectAction(null);
}
+ React.useEffect(() => {
+ pendingGateRef.current = pendingGate;
+ }, [pendingGate]);
+
React.useEffect(() => {
resetToolActivityState(toolActivityStateRef);
locallyResolvedGatesRef.current.clear();
@@ -353,7 +366,7 @@ export function useChat(threadId) {
const wireAttachments = stagedAttachments.map(toWireAttachment);
const renderAttachments = stagedAttachments.map(toRenderAttachment);
- if (pendingGate) {
+ if (pendingGateRef.current) {
throw approvalGatePendingSendError();
}
@@ -380,6 +393,10 @@ export function useChat(threadId) {
}
}
+ if (pendingGateRef.current) {
+ throw approvalGatePendingSendError();
+ }
+
const pendingKey = sendThreadId;
const pendingRecord = {
id: `pending-${pendingSeqRef.current++}`,
@@ -416,7 +433,9 @@ export function useChat(threadId) {
updateCurrentRunState(() => {
setIsProcessing(true);
- setPendingGate(null);
+ if (!pendingGateRef.current) {
+ setPendingGate(null);
+ }
});
try {
@@ -516,7 +535,7 @@ export function useChat(threadId) {
removePending(pendingMessagesRef.current, pendingKey, optimisticId);
}
},
- [threadId, pendingGate, setMessages, seedThreadMessages],
+ [threadId, setMessages, seedThreadMessages],
);
// v2 resolveGate signature: `(resolution, { always?, credentialRef? })`.
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
index 978761f8c00..8708b15d64e 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
@@ -52,7 +52,11 @@ function runUseChatSource(context) {
vm.runInNewContext(useChatSourceForTest(), context);
}
-function createReactStub({ initialByIndex = new Map(), setCalls = [] } = {}) {
+function createReactStub({
+ initialByIndex = new Map(),
+ setCalls = [],
+ stateSlots = new Map(),
+} = {}) {
let stateIndex = 0;
return {
useCallback: (fn) => fn,
@@ -60,16 +64,19 @@ function createReactStub({ initialByIndex = new Map(), setCalls = [] } = {}) {
useRef: (value) => ({ current: value }),
useState: (initial) => {
const index = stateIndex++;
- let value = initialByIndex.has(index)
- ? initialByIndex.get(index)
- : typeof initial === "function"
- ? initial()
- : initial;
+ const slot = stateSlots.get(index) || {
+ value: initialByIndex.has(index)
+ ? initialByIndex.get(index)
+ : typeof initial === "function"
+ ? initial()
+ : initial,
+ };
+ stateSlots.set(index, slot);
return [
- value,
+ slot.value,
(next) => {
- value = typeof next === "function" ? next(value) : next;
- setCalls.push({ index, value });
+ slot.value = typeof next === "function" ? next(slot.value) : next;
+ setCalls.push({ index, value: slot.value });
},
];
},
@@ -560,7 +567,7 @@ test("useChat.send: target-thread thrown errors update seeded cache", async () =
});
test("useChat.send: pending approval blocks before sendMessage", async () => {
- const threadId = "thread-approval";
+ const threadId = "thread-1";
const pendingGate = {
runId: "run-gated",
gateRef: "gate-shell",
@@ -568,7 +575,6 @@ test("useChat.send: pending approval blocks before sendMessage", async () => {
toolName: "builtin.shell",
};
const stateUpdates = [];
- let sendCalls = 0;
let renderedMessages = [];
const context = {
@@ -594,12 +600,12 @@ test("useChat.send: pending approval blocks before sendMessage", async () => {
},
globalThis: {},
listConnectableChannels: async () => {
- throw new Error("approval-gated sends should not fetch connectable channels");
+ throw new Error("ordinary prompts should not fetch connectable channels");
},
looksLikeChannelConnectCommand,
queryClient: {
fetchQuery: async () => {
- throw new Error("approval-gated sends should not fetch connectable channels");
+ throw new Error("ordinary prompts should not fetch connectable channels");
},
invalidateQueries: () => {},
},
@@ -608,7 +614,6 @@ test("useChat.send: pending approval blocks before sendMessage", async () => {
resolveChannelConnectCommand,
resolveGateRequest: async () => {},
sendMessage: async () => {
- sendCalls += 1;
throw new Error("sendMessage should not be called");
},
setInterval,
@@ -634,15 +639,203 @@ test("useChat.send: pending approval blocks before sendMessage", async () => {
const chat = context.globalThis.__testExports.useChat(threadId);
await assert.rejects(
- chat.send("new request while approval is open"),
+ chat.send("another request"),
(error) =>
error?.safeErrorCode === "approval_gate_pending_send_blocked" &&
/Resolve the approval request/.test(error.message),
);
- assert.equal(sendCalls, 0);
- assert.deepEqual(renderedMessages, []);
assert.deepEqual(stateUpdates, []);
+ assert.equal(renderedMessages.length, 0);
+});
+
+test("useChat.send: accepted send does not clear a gate received while in flight", async () => {
+ const threadId = "thread-1";
+ const replacementGate = {
+ runId: "run-replacement",
+ gateRef: "gate-replacement",
+ kind: "gate",
+ toolName: "nearai.web_search",
+ };
+ const stateUpdates = [];
+ const stateSlots = new Map();
+ let renderedMessages = [];
+ let setPendingGateFromEvents = null;
+ const context = {
+ AbortController,
+ Date,
+ Error,
+ Map,
+ Math,
+ React: createReactStub({
+ initialByIndex: new Map([
+ [4, false],
+ [5, null],
+ ]),
+ setCalls: stateUpdates,
+ stateSlots,
+ }),
+ addPending,
+ toRenderAttachment,
+ toWireAttachment,
+ cancelRunRequest: async () => {},
+ clearTimeout,
+ createThreadRequest: async () => {
+ throw new Error("thread should already exist");
+ },
+ globalThis: {},
+ listConnectableChannels: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ looksLikeChannelConnectCommand,
+ queryClient: {
+ fetchQuery: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ invalidateQueries: () => {},
+ },
+ recordAcceptedMessageRef,
+ removePending,
+ timelineMessageIdFromAcceptedRef,
+ resolveChannelConnectCommand,
+ resolveGateRequest: async () => {},
+ sendMessage: async () => {
+ setPendingGateFromEvents(replacementGate);
+ return {
+ accepted_message_ref: "msg:message-accepted",
+ run_id: "run-accepted",
+ status: "queued",
+ thread_id: threadId,
+ };
+ },
+ setInterval,
+ setTimeout,
+ submitManualToken: async () => {},
+ useChatEvents: ({ setPendingGate }) => {
+ setPendingGateFromEvents = setPendingGate;
+ return () => {};
+ },
+ useHistory: () => ({
+ messages: renderedMessages,
+ hasMore: false,
+ nextCursor: null,
+ isLoading: false,
+ loadHistory: () => {},
+ seedThreadMessages: () => {},
+ setMessages: (updater) => {
+ renderedMessages =
+ typeof updater === "function" ? updater(renderedMessages) : updater;
+ },
+ }),
+ useSSE: () => ({ status: "idle" }),
+ };
+
+ runUseChatSource(context);
+
+ const chat = context.globalThis.__testExports.useChat(threadId);
+ await chat.send("accepted after gate changed");
+
+ assert.deepEqual(
+ stateUpdates.filter((call) => call.index === 5).map((call) => call.value),
+ [replacementGate],
+ "non-busy success must not clear a gate that changed while send was in flight",
+ );
+ assert.equal(stateSlots.get(5).value, replacementGate);
+});
+
+test("useChat.send: rejected busy does not clear a gate received while in flight", async () => {
+ const threadId = "thread-1";
+ const replacementGate = {
+ runId: "run-replacement",
+ gateRef: "gate-replacement",
+ kind: "gate",
+ toolName: "nearai.web_search",
+ };
+ const stateUpdates = [];
+ const stateSlots = new Map();
+ let renderedMessages = [];
+ let setPendingGateFromEvents = null;
+
+ const context = {
+ AbortController,
+ Date,
+ Error,
+ Map,
+ Math,
+ React: createReactStub({
+ initialByIndex: new Map([
+ [4, false],
+ [5, null],
+ ]),
+ setCalls: stateUpdates,
+ stateSlots,
+ }),
+ addPending,
+ toRenderAttachment,
+ toWireAttachment,
+ cancelRunRequest: async () => {},
+ clearTimeout,
+ createThreadRequest: async () => {
+ throw new Error("thread should already exist");
+ },
+ globalThis: {},
+ listConnectableChannels: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ looksLikeChannelConnectCommand,
+ queryClient: {
+ fetchQuery: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ invalidateQueries: () => {},
+ },
+ recordAcceptedMessageRef,
+ removePending,
+ timelineMessageIdFromAcceptedRef,
+ resolveChannelConnectCommand,
+ resolveGateRequest: async () => {},
+ sendMessage: async () => {
+ setPendingGateFromEvents(replacementGate);
+ return {
+ outcome: "rejected_busy",
+ accepted_message_ref: "msg:busy-message-1",
+ notice: "Thread is busy, please try again.",
+ thread_id: threadId,
+ };
+ },
+ setInterval,
+ setTimeout,
+ submitManualToken: async () => {},
+ useChatEvents: ({ setPendingGate }) => {
+ setPendingGateFromEvents = setPendingGate;
+ return () => {};
+ },
+ useHistory: () => ({
+ messages: renderedMessages,
+ hasMore: false,
+ nextCursor: null,
+ isLoading: false,
+ loadHistory: () => {},
+ seedThreadMessages: () => {},
+ setMessages: (updater) => {
+ renderedMessages =
+ typeof updater === "function" ? updater(renderedMessages) : updater;
+ },
+ }),
+ useSSE: () => ({ status: "idle" }),
+ };
+
+ runUseChatSource(context);
+
+ const chat = context.globalThis.__testExports.useChat(threadId);
+ await chat.send("busy after gate changed");
+
+ assert.deepEqual(
+ stateUpdates.filter((call) => call.index === 5).map((call) => call.value),
+ [replacementGate],
+ "busy rejection must leave a concurrently replaced gate untouched",
+ );
+ assert.equal(stateSlots.get(5).value, replacementGate);
});
test("useChat.cancelRun clears local state before cancel request resolves", async () => {
diff --git a/tests/e2e/helpers.py b/tests/e2e/helpers.py
index 867b71ab870..073954e2b73 100644
--- a/tests/e2e/helpers.py
+++ b/tests/e2e/helpers.py
@@ -236,7 +236,7 @@
"msg_user": "[data-testid='msg-user']", # user message bubble
"msg_assistant": "[data-testid='msg-assistant']", # assistant message bubble
"msg_system": "[data-testid='msg-system']", # system notice bubble
- "approval_card": "text=Approval required", # approval gate card headline
+ "approval_card": "[data-testid='approval-card']", # approval gate card
# Download chip for an agent-produced workspace file; `{path}` selects one.
# Clicking a chip opens the shared attachment preview modal, whose footer
# carries the Download action.
From 47307e111f09b517175f58358370891b77e08e67 Mon Sep 17 00:00:00 2001
From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com>
Date: Thu, 25 Jun 2026 23:25:08 +0800
Subject: [PATCH 03/11] test(webui): cover late approval gate busy send
---
.../js/pages/chat/lib/useChat-send.test.mjs | 95 +++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
index 8708b15d64e..88c7fc38b5b 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
@@ -838,6 +838,101 @@ test("useChat.send: rejected busy does not clear a gate received while in flight
assert.equal(stateSlots.get(5).value, replacementGate);
});
+test("useChat.send: rejected busy keeps a gate received after callback creation", async () => {
+ const threadId = "thread-1";
+ const pendingGate = {
+ runId: "run-gated",
+ gateRef: "gate-shell",
+ kind: "gate",
+ toolName: "builtin.shell",
+ };
+ const stateUpdates = [];
+ const stateSlots = new Map();
+ let renderedMessages = [];
+ let setPendingGateFromEvents = null;
+
+ const context = {
+ AbortController,
+ Date,
+ Error,
+ Map,
+ Math,
+ React: createReactStub({
+ initialByIndex: new Map([
+ [4, false],
+ [5, null],
+ ]),
+ setCalls: stateUpdates,
+ stateSlots,
+ }),
+ addPending,
+ toRenderAttachment,
+ toWireAttachment,
+ cancelRunRequest: async () => {},
+ clearTimeout,
+ createThreadRequest: async () => {
+ throw new Error("thread should already exist");
+ },
+ globalThis: {},
+ listConnectableChannels: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ looksLikeChannelConnectCommand,
+ queryClient: {
+ fetchQuery: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ invalidateQueries: () => {},
+ },
+ recordAcceptedMessageRef,
+ removePending,
+ timelineMessageIdFromAcceptedRef,
+ resolveChannelConnectCommand,
+ resolveGateRequest: async () => {},
+ sendMessage: async () => ({
+ outcome: "rejected_busy",
+ accepted_message_ref: "msg:busy-message-1",
+ notice: "Thread is busy, please try again.",
+ thread_id: threadId,
+ }),
+ setInterval,
+ setTimeout,
+ submitManualToken: async () => {},
+ useChatEvents: ({ setPendingGate }) => {
+ setPendingGateFromEvents = setPendingGate;
+ return () => {};
+ },
+ useHistory: () => ({
+ messages: renderedMessages,
+ hasMore: false,
+ nextCursor: null,
+ isLoading: false,
+ loadHistory: () => {},
+ seedThreadMessages: () => {},
+ setMessages: (updater) => {
+ renderedMessages =
+ typeof updater === "function" ? updater(renderedMessages) : updater;
+ },
+ }),
+ useSSE: () => ({ status: "idle" }),
+ };
+
+ runUseChatSource(context);
+
+ const chat = context.globalThis.__testExports.useChat(threadId);
+ setPendingGateFromEvents(pendingGate);
+ await chat.send("busy after gate arrived");
+
+ assert.deepEqual(
+ stateUpdates.filter((call) => call.index === 5).map((call) => call.value),
+ [pendingGate],
+ "send must read the latest gate from SSE instead of a stale null callback closure",
+ );
+ assert.equal(stateSlots.get(5).value, pendingGate);
+ assert.equal(renderedMessages[0].status, "error");
+ assert.equal(renderedMessages[1].role, "system");
+});
+
test("useChat.cancelRun clears local state before cancel request resolves", async () => {
const threadId = "thread-1";
const stateUpdates = [];
From 8dbed7e5e1e8aa3cf0c6cd797d0b47422532f5a4 Mon Sep 17 00:00:00 2001
From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com>
Date: Thu, 25 Jun 2026 23:29:59 +0800
Subject: [PATCH 04/11] fix(webui): dedupe busy approval notices
---
.../static/js/pages/chat/hooks/useChat.js | 15 +++-
.../js/pages/chat/lib/useChat-send.test.mjs | 89 +++++++++++++++++++
2 files changed, 100 insertions(+), 4 deletions(-)
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
index 12bcf28065d..ca1e13f4dd7 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
@@ -69,6 +69,11 @@ function threadNeedsSidebarRefresh(threadId) {
return !thread?.title;
}
+function busyNoticeKey(threadId, gate) {
+ if (!threadId || !gate?.runId || !gate?.gateRef) return null;
+ return `${threadId}\n${gate.runId}\n${gate.gateRef}`;
+}
+
function submitResponseResumedTurnGate(response) {
return response?.continuation?.type === "turn_gate_resume";
}
@@ -487,17 +492,19 @@ export function useChat(threadId) {
updateCurrentThread(markRejected);
updateSeededTarget(markRejected);
if (response?.notice) {
+ const noticeKey = busyNoticeKey(sendThreadId, gateBeforeSend);
const noticeMessage = {
id: `system-rejected-${pendingSeqRef.current++}`,
role: "system",
content: response.notice,
timestamp: new Date().toISOString(),
isOptimistic: false,
+ busyGateKey: noticeKey,
};
- const appendNotice = (prev) => [
- ...prev,
- noticeMessage,
- ];
+ const appendNotice = (prev) =>
+ noticeKey && prev.some((m) => m.busyGateKey === noticeKey)
+ ? prev
+ : [...prev, noticeMessage];
updateCurrentThread(appendNotice);
updateSeededTarget(appendNotice);
}
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
index 88c7fc38b5b..0bb64b9b39d 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
@@ -933,6 +933,95 @@ test("useChat.send: rejected busy keeps a gate received after callback creation"
assert.equal(renderedMessages[1].role, "system");
});
+test("useChat.send: repeated busy rejection under the same gate dedupes notice", async () => {
+ const threadId = "thread-1";
+ const pendingGate = {
+ runId: "run-gated",
+ gateRef: "gate-shell",
+ kind: "gate",
+ toolName: "builtin.shell",
+ };
+ const stateUpdates = [];
+ let renderedMessages = [];
+
+ const context = {
+ AbortController,
+ Date,
+ Error,
+ Map,
+ Math,
+ React: createReactStub({
+ initialByIndex: new Map([
+ [4, false],
+ [5, pendingGate],
+ ]),
+ setCalls: stateUpdates,
+ }),
+ addPending,
+ toRenderAttachment,
+ toWireAttachment,
+ cancelRunRequest: async () => {},
+ clearTimeout,
+ createThreadRequest: async () => {
+ throw new Error("thread should already exist");
+ },
+ globalThis: {},
+ listConnectableChannels: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ looksLikeChannelConnectCommand,
+ queryClient: {
+ fetchQuery: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ invalidateQueries: () => {},
+ },
+ recordAcceptedMessageRef,
+ removePending,
+ timelineMessageIdFromAcceptedRef,
+ resolveChannelConnectCommand,
+ resolveGateRequest: async () => {},
+ sendMessage: async () => ({
+ outcome: "rejected_busy",
+ accepted_message_ref: "msg:busy-message-1",
+ notice:
+ "An approval gate is open on this thread -- resolve it before continuing.",
+ thread_id: threadId,
+ }),
+ setInterval,
+ setTimeout,
+ submitManualToken: async () => {},
+ useChatEvents: () => () => {},
+ useHistory: () => ({
+ messages: renderedMessages,
+ hasMore: false,
+ nextCursor: null,
+ isLoading: false,
+ loadHistory: () => {},
+ seedThreadMessages: () => {},
+ setMessages: (updater) => {
+ renderedMessages =
+ typeof updater === "function" ? updater(renderedMessages) : updater;
+ },
+ }),
+ useSSE: () => ({ status: "idle" }),
+ };
+
+ runUseChatSource(context);
+
+ const chat = context.globalThis.__testExports.useChat(threadId);
+ await chat.send("first blocked send");
+ await chat.send("second blocked send");
+
+ const userMessages = renderedMessages.filter((m) => m.role === "user");
+ const systemMessages = renderedMessages.filter((m) => m.role === "system");
+ assert.equal(userMessages.length, 2);
+ assert.equal(userMessages[0].status, "error");
+ assert.equal(userMessages[1].status, "error");
+ assert.equal(systemMessages.length, 1);
+ assert.match(systemMessages[0].content, /approval gate is open/i);
+});
+
test("useChat.cancelRun clears local state before cancel request resolves", async () => {
const threadId = "thread-1";
const stateUpdates = [];
From fa99125debce36c3237a418619f9fd2267ead994 Mon Sep 17 00:00:00 2001
From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com>
Date: Thu, 25 Jun 2026 23:34:19 +0800
Subject: [PATCH 05/11] fix(webui): show busy gate notice below approval card
---
.../static/js/pages/chat/chat.js | 11 +++++
.../static/js/pages/chat/hooks/useChat.js | 41 ++++++++++++-------
.../js/pages/chat/lib/useChat-send.test.mjs | 23 +++++++----
tests/e2e/helpers.py | 1 +
4 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
index 9ac58dec029..1bfc9bbddc7 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
@@ -51,6 +51,7 @@ export function Chat({
messages,
isProcessing,
pendingGate,
+ busyGateNotice,
channelConnectAction,
suggestions,
sseStatus,
@@ -308,6 +309,16 @@ export function Chat({
approve(pendingGate.requestId, "always", pendingGate.kind)}
/>
`)}
+ ${busyGateNotice &&
+ html`
+
+ ${busyGateNotice.content}
+
+ `}
/>
<${SuggestionChips}
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
index ca1e13f4dd7..a32f211e454 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
@@ -191,6 +191,7 @@ export function useChat(threadId) {
const [isProcessing, setIsProcessing] = React.useState(false);
const [pendingGate, setPendingGateState] = React.useState(null);
const pendingGateRef = React.useRef(pendingGate);
+ const [busyGateNotice, setBusyGateNotice] = React.useState(null);
const setPendingGate = React.useCallback((next) => {
const current = pendingGateRef.current;
const value =
@@ -239,6 +240,7 @@ export function useChat(threadId) {
setStateThreadId(threadId);
setIsProcessing(false);
setPendingGateState(null);
+ setBusyGateNotice(null);
setActiveRunState(null);
setChannelConnectAction(null);
}
@@ -247,6 +249,13 @@ export function useChat(threadId) {
pendingGateRef.current = pendingGate;
}, [pendingGate]);
+ React.useEffect(() => {
+ const currentKey = busyNoticeKey(threadId, pendingGate);
+ setBusyGateNotice((current) =>
+ current && current.gateKey !== currentKey ? null : current,
+ );
+ }, [pendingGate, threadId]);
+
React.useEffect(() => {
resetToolActivityState(toolActivityStateRef);
locallyResolvedGatesRef.current.clear();
@@ -493,20 +502,23 @@ export function useChat(threadId) {
updateSeededTarget(markRejected);
if (response?.notice) {
const noticeKey = busyNoticeKey(sendThreadId, gateBeforeSend);
- const noticeMessage = {
- id: `system-rejected-${pendingSeqRef.current++}`,
- role: "system",
- content: response.notice,
- timestamp: new Date().toISOString(),
- isOptimistic: false,
- busyGateKey: noticeKey,
- };
- const appendNotice = (prev) =>
- noticeKey && prev.some((m) => m.busyGateKey === noticeKey)
- ? prev
- : [...prev, noticeMessage];
- updateCurrentThread(appendNotice);
- updateSeededTarget(appendNotice);
+ if (noticeKey && shouldRenderInCurrentThread) {
+ setBusyGateNotice({ gateKey: noticeKey, content: response.notice });
+ } else {
+ const noticeMessage = {
+ id: `system-rejected-${pendingSeqRef.current++}`,
+ role: "system",
+ content: response.notice,
+ timestamp: new Date().toISOString(),
+ isOptimistic: false,
+ };
+ const appendNotice = (prev) => [
+ ...prev,
+ noticeMessage,
+ ];
+ updateCurrentThread(appendNotice);
+ updateSeededTarget(appendNotice);
+ }
}
updateCurrentRunState(() => setIsProcessing(false));
}
@@ -717,6 +729,7 @@ export function useChat(threadId) {
messages,
isProcessing,
pendingGate,
+ busyGateNotice,
channelConnectAction,
activeRun,
sseStatus,
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
index 0bb64b9b39d..47d42f34a8f 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
@@ -930,7 +930,10 @@ test("useChat.send: rejected busy keeps a gate received after callback creation"
);
assert.equal(stateSlots.get(5).value, pendingGate);
assert.equal(renderedMessages[0].status, "error");
- assert.equal(renderedMessages[1].role, "system");
+ assert.deepEqual(
+ stateUpdates.filter((call) => call.index === 6).map((call) => call.value?.content),
+ ["Thread is busy, please try again."],
+ );
});
test("useChat.send: repeated busy rejection under the same gate dedupes notice", async () => {
@@ -1018,8 +1021,11 @@ test("useChat.send: repeated busy rejection under the same gate dedupes notice",
assert.equal(userMessages.length, 2);
assert.equal(userMessages[0].status, "error");
assert.equal(userMessages[1].status, "error");
- assert.equal(systemMessages.length, 1);
- assert.match(systemMessages[0].content, /approval gate is open/i);
+ assert.equal(systemMessages.length, 0);
+ assert.equal(
+ stateUpdates.filter((call) => call.index === 6).at(-1)?.value?.content,
+ "An approval gate is open on this thread -- resolve it before continuing.",
+ );
});
test("useChat.cancelRun clears local state before cancel request resolves", async () => {
@@ -1117,13 +1123,15 @@ test("useChat clears transient run and gate state during thread switch render",
Math,
React: createReactStub({
// useChat state call order: cooldownUntil, now, activeRun,
- // channelConnectAction, isProcessing, pendingGate, stateThreadId.
+ // channelConnectAction, isProcessing, pendingGate, busyGateNotice,
+ // stateThreadId.
initialByIndex: new Map([
[2, { runId: "run-old", threadId: "thread-old", status: "awaiting_gate" }],
[3, { channel: "slack" }],
[4, true],
[5, { runId: "run-old", gateRef: "gate-old" }],
- [6, "thread-old"],
+ [6, { gateKey: "thread-old\nrun-old\ngate-old", content: "busy" }],
+ [7, "thread-old"],
]),
setCalls: stateUpdates,
}),
@@ -1168,10 +1176,11 @@ test("useChat clears transient run and gate state during thread switch render",
runUseChatSource(context);
context.globalThis.__testExports.useChat("thread-new");
- assert.deepEqual(stateUpdates.slice(0, 5), [
- { index: 6, value: "thread-new" },
+ assert.deepEqual(stateUpdates.slice(0, 6), [
+ { index: 7, value: "thread-new" },
{ index: 4, value: false },
{ index: 5, value: null },
+ { index: 6, value: null },
{ index: 2, value: null },
{ index: 3, value: null },
]);
diff --git a/tests/e2e/helpers.py b/tests/e2e/helpers.py
index 073954e2b73..b7be2cd7237 100644
--- a/tests/e2e/helpers.py
+++ b/tests/e2e/helpers.py
@@ -237,6 +237,7 @@
"msg_assistant": "[data-testid='msg-assistant']", # assistant message bubble
"msg_system": "[data-testid='msg-system']", # system notice bubble
"approval_card": "[data-testid='approval-card']", # approval gate card
+ "busy_gate_notice": "[data-testid='busy-gate-notice']", # gate busy notice
# Download chip for an agent-produced workspace file; `{path}` selects one.
# Clicking a chip opens the shared attachment preview modal, whose footer
# carries the Download action.
From 45482f30d2535febb8a4d9a2db5eed1b8713da56 Mon Sep 17 00:00:00 2001
From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com>
Date: Thu, 25 Jun 2026 23:49:45 +0800
Subject: [PATCH 06/11] fix(webui): avoid stale busy gate notices
---
.../static/js/pages/chat/hooks/useChat.js | 4 +-
.../js/pages/chat/lib/useChat-send.test.mjs | 102 ++++++++++++++++++
2 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
index a32f211e454..da31fc4d5b4 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
@@ -503,7 +503,9 @@ export function useChat(threadId) {
if (response?.notice) {
const noticeKey = busyNoticeKey(sendThreadId, gateBeforeSend);
if (noticeKey && shouldRenderInCurrentThread) {
- setBusyGateNotice({ gateKey: noticeKey, content: response.notice });
+ if (pendingGateRef.current === gateBeforeSend) {
+ setBusyGateNotice({ gateKey: noticeKey, content: response.notice });
+ }
} else {
const noticeMessage = {
id: `system-rejected-${pendingSeqRef.current++}`,
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
index 47d42f34a8f..cd3c85bba0f 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
@@ -836,6 +836,108 @@ test("useChat.send: rejected busy does not clear a gate received while in flight
"busy rejection must leave a concurrently replaced gate untouched",
);
assert.equal(stateSlots.get(5).value, replacementGate);
+ assert.deepEqual(
+ stateUpdates.filter((call) => call.index === 6).map((call) => call.value),
+ [],
+ "busy rejection must not attach a notice to a stale gate snapshot",
+ );
+});
+
+test("useChat.send: rejected busy does not strand notice after gate resolves in flight", async () => {
+ const threadId = "thread-1";
+ const pendingGate = {
+ runId: "run-gated",
+ gateRef: "gate-shell",
+ kind: "gate",
+ toolName: "builtin.shell",
+ };
+ const stateUpdates = [];
+ const stateSlots = new Map();
+ let renderedMessages = [];
+ let setPendingGateFromEvents = null;
+
+ const context = {
+ AbortController,
+ Date,
+ Error,
+ Map,
+ Math,
+ React: createReactStub({
+ initialByIndex: new Map([
+ [4, false],
+ [5, pendingGate],
+ ]),
+ setCalls: stateUpdates,
+ stateSlots,
+ }),
+ addPending,
+ toRenderAttachment,
+ toWireAttachment,
+ cancelRunRequest: async () => {},
+ clearTimeout,
+ createThreadRequest: async () => {
+ throw new Error("thread should already exist");
+ },
+ globalThis: {},
+ listConnectableChannels: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ looksLikeChannelConnectCommand,
+ queryClient: {
+ fetchQuery: async () => {
+ throw new Error("ordinary prompts should not fetch connectable channels");
+ },
+ invalidateQueries: () => {},
+ },
+ recordAcceptedMessageRef,
+ removePending,
+ timelineMessageIdFromAcceptedRef,
+ resolveChannelConnectCommand,
+ resolveGateRequest: async () => {},
+ sendMessage: async () => {
+ setPendingGateFromEvents(null);
+ return {
+ outcome: "rejected_busy",
+ accepted_message_ref: "msg:busy-message-1",
+ notice: "Thread is busy, please try again.",
+ thread_id: threadId,
+ };
+ },
+ setInterval,
+ setTimeout,
+ submitManualToken: async () => {},
+ useChatEvents: ({ setPendingGate }) => {
+ setPendingGateFromEvents = setPendingGate;
+ return () => {};
+ },
+ useHistory: () => ({
+ messages: renderedMessages,
+ hasMore: false,
+ nextCursor: null,
+ isLoading: false,
+ loadHistory: () => {},
+ seedThreadMessages: () => {},
+ setMessages: (updater) => {
+ renderedMessages =
+ typeof updater === "function" ? updater(renderedMessages) : updater;
+ },
+ }),
+ useSSE: () => ({ status: "idle" }),
+ };
+
+ runUseChatSource(context);
+
+ const chat = context.globalThis.__testExports.useChat(threadId);
+ await chat.send("busy after gate resolved");
+
+ assert.equal(stateSlots.get(5).value, null);
+ assert.equal(renderedMessages.length, 1);
+ assert.equal(renderedMessages[0].status, "error");
+ assert.deepEqual(
+ stateUpdates.filter((call) => call.index === 6).map((call) => call.value),
+ [],
+ "a resolved gate should not get a lingering busy notice",
+ );
});
test("useChat.send: rejected busy keeps a gate received after callback creation", async () => {
From 3630edb157c6d7fa3ec4bd37a713ace967826751 Mon Sep 17 00:00:00 2001
From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com>
Date: Fri, 26 Jun 2026 00:04:16 +0800
Subject: [PATCH 07/11] fix(webui): keep busy notices visible across gate
changes
---
.../static/js/pages/chat/hooks/useChat.js | 21 +++--
.../js/pages/chat/lib/useChat-send.test.mjs | 86 +++++++++----------
2 files changed, 54 insertions(+), 53 deletions(-)
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
index da31fc4d5b4..e00549be0b1 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/hooks/useChat.js
@@ -501,12 +501,7 @@ export function useChat(threadId) {
updateCurrentThread(markRejected);
updateSeededTarget(markRejected);
if (response?.notice) {
- const noticeKey = busyNoticeKey(sendThreadId, gateBeforeSend);
- if (noticeKey && shouldRenderInCurrentThread) {
- if (pendingGateRef.current === gateBeforeSend) {
- setBusyGateNotice({ gateKey: noticeKey, content: response.notice });
- }
- } else {
+ const appendSystemNotice = () => {
const noticeMessage = {
id: `system-rejected-${pendingSeqRef.current++}`,
role: "system",
@@ -520,6 +515,20 @@ export function useChat(threadId) {
];
updateCurrentThread(appendNotice);
updateSeededTarget(appendNotice);
+ };
+ const noticeKey = busyNoticeKey(sendThreadId, gateBeforeSend);
+ if (noticeKey && shouldRenderInCurrentThread) {
+ const currentNoticeKey = busyNoticeKey(sendThreadId, pendingGateRef.current);
+ if (currentNoticeKey) {
+ setBusyGateNotice({
+ gateKey: currentNoticeKey,
+ content: response.notice,
+ });
+ } else {
+ appendSystemNotice();
+ }
+ } else {
+ appendSystemNotice();
}
}
updateCurrentRunState(() => setIsProcessing(false));
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
index cd3c85bba0f..27de65ef7d9 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/useChat-send.test.mjs
@@ -743,7 +743,7 @@ test("useChat.send: accepted send does not clear a gate received while in flight
assert.equal(stateSlots.get(5).value, replacementGate);
});
-test("useChat.send: rejected busy does not clear a gate received while in flight", async () => {
+test("useChat.send: rejected busy attaches notice to a gate replaced while in flight", async () => {
const threadId = "thread-1";
const replacementGate = {
runId: "run-replacement",
@@ -836,21 +836,16 @@ test("useChat.send: rejected busy does not clear a gate received while in flight
"busy rejection must leave a concurrently replaced gate untouched",
);
assert.equal(stateSlots.get(5).value, replacementGate);
- assert.deepEqual(
- stateUpdates.filter((call) => call.index === 6).map((call) => call.value),
- [],
- "busy rejection must not attach a notice to a stale gate snapshot",
- );
+ const busyNoticeUpdates = stateUpdates
+ .filter((call) => call.index === 6)
+ .map((call) => call.value);
+ assert.equal(busyNoticeUpdates.length, 1);
+ assert.equal(busyNoticeUpdates[0].content, "Thread is busy, please try again.");
+ assert.match(busyNoticeUpdates[0].gateKey, /run-replacement\ngate-replacement$/);
});
-test("useChat.send: rejected busy does not strand notice after gate resolves in flight", async () => {
+test("useChat.send: rejected busy appends system notice after gate resolves in flight", async () => {
const threadId = "thread-1";
- const pendingGate = {
- runId: "run-gated",
- gateRef: "gate-shell",
- kind: "gate",
- toolName: "builtin.shell",
- };
const stateUpdates = [];
const stateSlots = new Map();
let renderedMessages = [];
@@ -865,7 +860,7 @@ test("useChat.send: rejected busy does not strand notice after gate resolves in
React: createReactStub({
initialByIndex: new Map([
[4, false],
- [5, pendingGate],
+ [5, null],
]),
setCalls: stateUpdates,
stateSlots,
@@ -931,16 +926,18 @@ test("useChat.send: rejected busy does not strand notice after gate resolves in
await chat.send("busy after gate resolved");
assert.equal(stateSlots.get(5).value, null);
- assert.equal(renderedMessages.length, 1);
+ assert.equal(renderedMessages.length, 2);
assert.equal(renderedMessages[0].status, "error");
+ assert.equal(renderedMessages[1].role, "system");
+ assert.equal(renderedMessages[1].content, "Thread is busy, please try again.");
assert.deepEqual(
stateUpdates.filter((call) => call.index === 6).map((call) => call.value),
[],
- "a resolved gate should not get a lingering busy notice",
+ "a resolved gate should not get a lingering card-level busy notice",
);
});
-test("useChat.send: rejected busy keeps a gate received after callback creation", async () => {
+test("useChat.send: gate received after callback creation blocks before send", async () => {
const threadId = "thread-1";
const pendingGate = {
runId: "run-gated",
@@ -991,12 +988,9 @@ test("useChat.send: rejected busy keeps a gate received after callback creation"
timelineMessageIdFromAcceptedRef,
resolveChannelConnectCommand,
resolveGateRequest: async () => {},
- sendMessage: async () => ({
- outcome: "rejected_busy",
- accepted_message_ref: "msg:busy-message-1",
- notice: "Thread is busy, please try again.",
- thread_id: threadId,
- }),
+ sendMessage: async () => {
+ throw new Error("sendMessage should not run");
+ },
setInterval,
setTimeout,
submitManualToken: async () => {},
@@ -1023,7 +1017,12 @@ test("useChat.send: rejected busy keeps a gate received after callback creation"
const chat = context.globalThis.__testExports.useChat(threadId);
setPendingGateFromEvents(pendingGate);
- await chat.send("busy after gate arrived");
+ await assert.rejects(
+ chat.send("busy after gate arrived"),
+ (error) =>
+ error?.safeErrorCode === "approval_gate_pending_send_blocked" &&
+ /Resolve the approval request/.test(error.message),
+ );
assert.deepEqual(
stateUpdates.filter((call) => call.index === 5).map((call) => call.value),
@@ -1031,14 +1030,14 @@ test("useChat.send: rejected busy keeps a gate received after callback creation"
"send must read the latest gate from SSE instead of a stale null callback closure",
);
assert.equal(stateSlots.get(5).value, pendingGate);
- assert.equal(renderedMessages[0].status, "error");
+ assert.equal(renderedMessages.length, 0);
assert.deepEqual(
stateUpdates.filter((call) => call.index === 6).map((call) => call.value?.content),
- ["Thread is busy, please try again."],
+ [],
);
});
-test("useChat.send: repeated busy rejection under the same gate dedupes notice", async () => {
+test("useChat.send: repeated sends under the same pending gate stay blocked locally", async () => {
const threadId = "thread-1";
const pendingGate = {
runId: "run-gated",
@@ -1083,16 +1082,11 @@ test("useChat.send: repeated busy rejection under the same gate dedupes notice",
},
recordAcceptedMessageRef,
removePending,
- timelineMessageIdFromAcceptedRef,
resolveChannelConnectCommand,
resolveGateRequest: async () => {},
- sendMessage: async () => ({
- outcome: "rejected_busy",
- accepted_message_ref: "msg:busy-message-1",
- notice:
- "An approval gate is open on this thread -- resolve it before continuing.",
- thread_id: threadId,
- }),
+ sendMessage: async () => {
+ throw new Error("sendMessage should not run");
+ },
setInterval,
setTimeout,
submitManualToken: async () => {},
@@ -1115,19 +1109,17 @@ test("useChat.send: repeated busy rejection under the same gate dedupes notice",
runUseChatSource(context);
const chat = context.globalThis.__testExports.useChat(threadId);
- await chat.send("first blocked send");
- await chat.send("second blocked send");
-
- const userMessages = renderedMessages.filter((m) => m.role === "user");
- const systemMessages = renderedMessages.filter((m) => m.role === "system");
- assert.equal(userMessages.length, 2);
- assert.equal(userMessages[0].status, "error");
- assert.equal(userMessages[1].status, "error");
- assert.equal(systemMessages.length, 0);
- assert.equal(
- stateUpdates.filter((call) => call.index === 6).at(-1)?.value?.content,
- "An approval gate is open on this thread -- resolve it before continuing.",
+ await assert.rejects(
+ chat.send("first blocked send"),
+ /Resolve the approval request/,
+ );
+ await assert.rejects(
+ chat.send("second blocked send"),
+ /Resolve the approval request/,
);
+
+ assert.equal(renderedMessages.length, 0);
+ assert.deepEqual(stateUpdates, []);
});
test("useChat.cancelRun clears local state before cancel request resolves", async () => {
From 33dfd373f944f8f15a12ce417e70889af930209a Mon Sep 17 00:00:00 2001
From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com>
Date: Fri, 26 Jun 2026 00:19:13 +0800
Subject: [PATCH 08/11] fix(webui): block sends while composer stays editable
---
.../static/js/pages/chat/chat.js | 3 +-
.../static/js/pages/chat/lib/chat.test.mjs | 36 +++++++++++++++++++
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
index 1bfc9bbddc7..6a920f5b432 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
@@ -111,6 +111,7 @@ export function Chat({
: null;
const handleSend = React.useCallback(
async (content, { images = [], attachments = [] } = {}) => {
+ if (composerSendDisabled) return null;
const response = await send(content, {
images,
attachments,
@@ -122,7 +123,7 @@ export function Chat({
}
return response;
},
- [activeThreadId, onSelectThread, send]
+ [activeThreadId, composerSendDisabled, onSelectThread, send]
);
const handleSuggestion = React.useCallback(
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs
index 6383f3c4de8..94b3fa4590f 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs
@@ -175,6 +175,42 @@ test("Chat leaves the composer editable while a run is processing", () => {
assert.equal(props.sendDisabled, true);
});
+test("Chat blocks sends while a run is processing", async () => {
+ let sendCount = 0;
+ const { tree, components } = renderChat({
+ hookState: {
+ messages: [{ id: "message-1" }],
+ isProcessing: true,
+ pendingGate: null,
+ channelConnectAction: null,
+ suggestions: [],
+ sseStatus: "open",
+ historyLoading: false,
+ hasMore: false,
+ cooldownSeconds: 0,
+ recoveryNotice: null,
+ activeRun: { runId: "run-1", threadId: "thread-1", status: "running" },
+ send: async () => {
+ sendCount += 1;
+ return {};
+ },
+ cancelRun: async () => {},
+ retryMessage: () => {},
+ approve: () => {},
+ recoverHistory: () => {},
+ loadMore: () => {},
+ setSuggestions: () => {},
+ submitAuthToken: async () => {},
+ dismissChannelConnectAction: () => {},
+ },
+ });
+
+ const chatInput = findComponent(tree, components.ChatInput);
+ const props = componentProps(chatInput, components.ChatInput);
+ assert.equal(await props.onSend("draft while running"), null);
+ assert.equal(sendCount, 0);
+});
+
test("Chat cancel button ignores active runs from another thread", () => {
const { tree, components } = renderChat({
hookState: {
From 4b2213b5f4d381f71b0385d2c92c1453cb1786be Mon Sep 17 00:00:00 2001
From: Robert Yan
Date: Thu, 25 Jun 2026 16:19:55 +0000
Subject: [PATCH 09/11] fix(webui): block sends while approval is pending
---
.../static/js/pages/chat/chat.js | 12 +++++++++---
.../js/pages/chat/components/suggestion-chips.js | 9 ++++++---
.../static/js/pages/chat/lib/chat.test.mjs | 5 +++++
3 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
index 6a920f5b432..9434c7f8f6b 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/chat.js
@@ -86,10 +86,14 @@ export function Chat({
// error banner instead so the user is not misled into thinking the thread
// is empty.
const showLanding = !historyLoading && !hasMessages && !historyLoadError;
+ const approvalSubmitWarning = pendingGate
+ ? "Resolve the approval request before sending another message."
+ : "";
const composerSendDisabled =
- (isProcessing && !pendingGate) || cooldownSeconds > 0;
+ Boolean(pendingGate) || (isProcessing && !pendingGate) || cooldownSeconds > 0;
const composerStatusText =
- cooldownSeconds > 0 ? `Retry in ${cooldownSeconds}s` : undefined;
+ approvalSubmitWarning ||
+ (cooldownSeconds > 0 ? `Retry in ${cooldownSeconds}s` : undefined);
// Scope the persisted composer draft to the open thread (or the
// shared new-conversation slot when there's no active thread yet).
const composerDraftKey = activeThreadId || NEW_DRAFT_KEY;
@@ -128,10 +132,11 @@ export function Chat({
const handleSuggestion = React.useCallback(
async (text) => {
+ if (composerSendDisabled) return;
setSuggestions([]);
await handleSend(text);
},
- [handleSend, setSuggestions]
+ [composerSendDisabled, handleSend, setSuggestions]
);
const handleCancelRun = React.useCallback(
@@ -325,6 +330,7 @@ export function Chat({
<${SuggestionChips}
suggestions=${suggestions}
onSelect=${handleSuggestion}
+ disabled=${composerSendDisabled}
/>
<${ChatInput}
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/components/suggestion-chips.js b/crates/ironclaw_webui_v2_static/static/js/pages/chat/components/suggestion-chips.js
index a12a65aa63f..0349e121f04 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/components/suggestion-chips.js
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/components/suggestion-chips.js
@@ -1,6 +1,6 @@
import { html } from "../../../lib/html.js";
-export function SuggestionChips({ suggestions, onSelect }) {
+export function SuggestionChips({ suggestions, onSelect, disabled = false }) {
if (!suggestions || suggestions.length === 0) return null;
return html`
@@ -10,8 +10,11 @@ export function SuggestionChips({ suggestions, onSelect }) {
(text) => html`
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs
index 94b3fa4590f..ff94f2b2546 100644
--- a/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs
+++ b/crates/ironclaw_webui_v2_static/static/js/pages/chat/lib/chat.test.mjs
@@ -274,6 +274,11 @@ test("Chat keeps composer cancel disabled while a gate owns the run decision", (
const chatInput = findComponent(tree, components.ChatInput);
const props = componentProps(chatInput, components.ChatInput);
assert.equal(props.canCancel, false);
+ assert.equal(props.sendDisabled, true);
+ assert.equal(
+ props.statusText,
+ "Resolve the approval request before sending another message.",
+ );
});
test("Chat renders a timeline load failure as an alert instead of the empty landing", () => {
From 687a0437be19476e0e234e866bf1e7a88c379502 Mon Sep 17 00:00:00 2001
From: Robert Yan
Date: Thu, 25 Jun 2026 16:35:48 +0000
Subject: [PATCH 10/11] fix(webui): reject sends during approval gates
---
.../static/dist/app.js | 2166 +++++++++--------
.../static/js/pages/chat/chat.js | 12 +-
.../static/js/pages/chat/hooks/useChat.js | 3 +-
.../static/js/pages/chat/lib/chat.test.mjs | 13 +-
.../js/pages/chat/lib/useChat-send.test.mjs | 12 +-
5 files changed, 1123 insertions(+), 1083 deletions(-)
diff --git a/crates/ironclaw_webui_v2_static/static/dist/app.js b/crates/ironclaw_webui_v2_static/static/dist/app.js
index 0e6aae8e8bf..9eedb7085fc 100644
--- a/crates/ironclaw_webui_v2_static/static/dist/app.js
+++ b/crates/ironclaw_webui_v2_static/static/dist/app.js
@@ -1,14 +1,14 @@
-import{a as Sn,b as qe,c as Qe,d as h,e as l,f as Ih,g as Kh,h as il,i as k,j as ol}from"./chunks/chunk-IGTNS7XG.js";var uv=Sn(vl=>{"use strict";var hR=Symbol.for("react.transitional.element"),vR=Symbol.for("react.fragment");function lv(e,t,a){var n=null;if(a!==void 0&&(n=""+a),t.key!==void 0&&(n=""+t.key),"key"in t){a={};for(var r in t)r!=="key"&&(a[r]=t[r])}else a=t;return t=a.ref,{$$typeof:hR,type:e,key:n,ref:t!==void 0?t:null,props:a}}vl.Fragment=vR;vl.jsx=lv;vl.jsxs=lv});var wd=Sn((DL,cv)=>{"use strict";cv.exports=uv()});var Nv=Sn(Oe=>{"use strict";function Ed(e,t){var a=e.length;e.push(t);e:for(;0>>1,r=e[n];if(0<_l(r,t))e[n]=t,e[a]=r,a=n;else break e}}function Aa(e){return e.length===0?null:e[0]}function Rl(e){if(e.length===0)return null;var t=e[0],a=e.pop();if(a!==t){e[0]=a;e:for(var n=0,r=e.length,s=r>>>1;n_l(o,a))u_l(c,o)?(e[n]=c,e[u]=a,n=u):(e[n]=o,e[i]=a,n=i);else if(u_l(c,a))e[n]=c,e[u]=a,n=u;else break e}}return t}function _l(e,t){var a=e.sortIndex-t.sortIndex;return a!==0?a:e.id-t.id}Oe.unstable_now=void 0;typeof performance=="object"&&typeof performance.now=="function"?(hv=performance,Oe.unstable_now=function(){return hv.now()}):(kd=Date,vv=kd.now(),Oe.unstable_now=function(){return kd.now()-vv});var hv,kd,vv,Ja=[],kn=[],xR=1,sa=null,yt=3,Td=!1,_i=!1,ki=!1,Ad=!1,bv=typeof setTimeout=="function"?setTimeout:null,xv=typeof clearTimeout=="function"?clearTimeout:null,gv=typeof setImmediate<"u"?setImmediate:null;function kl(e){for(var t=Aa(kn);t!==null;){if(t.callback===null)Rl(kn);else if(t.startTime<=e)Rl(kn),t.sortIndex=t.expirationTime,Ed(Ja,t);else break;t=Aa(kn)}}function Dd(e){if(ki=!1,kl(e),!_i)if(Aa(Ja)!==null)_i=!0,Jr||(Jr=!0,Yr());else{var t=Aa(kn);t!==null&&Md(Dd,t.startTime-e)}}var Jr=!1,Ri=-1,$v=5,wv=-1;function Sv(){return Ad?!0:!(Oe.unstable_now()-wv<$v)}function Rd(){if(Ad=!1,Jr){var e=Oe.unstable_now();wv=e;var t=!0;try{e:{_i=!1,ki&&(ki=!1,xv(Ri),Ri=-1),Td=!0;var a=yt;try{t:{for(kl(e),sa=Aa(Ja);sa!==null&&!(sa.expirationTime>e&&Sv());){var n=sa.callback;if(typeof n=="function"){sa.callback=null,yt=sa.priorityLevel;var r=n(sa.expirationTime<=e);if(e=Oe.unstable_now(),typeof r=="function"){sa.callback=r,kl(e),t=!0;break t}sa===Aa(Ja)&&Rl(Ja),kl(e)}else Rl(Ja);sa=Aa(Ja)}if(sa!==null)t=!0;else{var s=Aa(kn);s!==null&&Md(Dd,s.startTime-e),t=!1}}break e}finally{sa=null,yt=a,Td=!1}t=void 0}}finally{t?Yr():Jr=!1}}}var Yr;typeof gv=="function"?Yr=function(){gv(Rd)}:typeof MessageChannel<"u"?(Cd=new MessageChannel,yv=Cd.port2,Cd.port1.onmessage=Rd,Yr=function(){yv.postMessage(null)}):Yr=function(){bv(Rd,0)};var Cd,yv;function Md(e,t){Ri=bv(function(){e(Oe.unstable_now())},t)}Oe.unstable_IdlePriority=5;Oe.unstable_ImmediatePriority=1;Oe.unstable_LowPriority=4;Oe.unstable_NormalPriority=3;Oe.unstable_Profiling=null;Oe.unstable_UserBlockingPriority=2;Oe.unstable_cancelCallback=function(e){e.callback=null};Oe.unstable_forceFrameRate=function(e){0>e||125n?(e.sortIndex=a,Ed(kn,e),Aa(Ja)===null&&e===Aa(kn)&&(ki?(xv(Ri),Ri=-1):ki=!0,Md(Dd,a-n))):(e.sortIndex=r,Ed(Ja,e),_i||Td||(_i=!0,Jr||(Jr=!0,Yr()))),e};Oe.unstable_shouldYield=Sv;Oe.unstable_wrapCallback=function(e){var t=yt;return function(){var a=yt;yt=t;try{return e.apply(this,arguments)}finally{yt=a}}}});var kv=Sn((p6,_v)=>{"use strict";_v.exports=Nv()});var Cv=Sn(kt=>{"use strict";var $R=Qe();function Rv(e){var t="https://react.dev/errors/"+e;if(1{"use strict";function Ev(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Ev)}catch(e){console.error(e)}}Ev(),Tv.exports=Cv()});var M0=Sn(Ju=>{"use strict";var rt=kv(),Wg=Qe(),NR=Av();function P(e){var t="https://react.dev/errors/"+e;if(1rs||(e.current=vm[rs],vm[rs]=null,rs--)}function Pe(e,t){rs++,vm[rs]=e.current,e.current=t}var La=ja(null),to=ja(null),zn=ja(null),su=ja(null);function iu(e,t){switch(Pe(zn,t),Pe(to,e),Pe(La,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Fg(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Fg(t),e=$0(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}dt(La),Pe(La,e)}function Ss(){dt(La),dt(to),dt(zn)}function gm(e){e.memoizedState!==null&&Pe(su,e);var t=La.current,a=$0(t,e.type);t!==a&&(Pe(to,e),Pe(La,a))}function ou(e){to.current===e&&(dt(La),dt(to)),su.current===e&&(dt(su),mo._currentValue=fr)}var ym=Object.prototype.hasOwnProperty,uf=rt.unstable_scheduleCallback,Od=rt.unstable_cancelCallback,TR=rt.unstable_shouldYield,AR=rt.unstable_requestPaint,Pa=rt.unstable_now,DR=rt.unstable_getCurrentPriorityLevel,sy=rt.unstable_ImmediatePriority,iy=rt.unstable_UserBlockingPriority,lu=rt.unstable_NormalPriority,MR=rt.unstable_LowPriority,oy=rt.unstable_IdlePriority,OR=rt.log,LR=rt.unstable_setDisableYieldValue,go=null,Qt=null;function Pn(e){if(typeof OR=="function"&&LR(e),Qt&&typeof Qt.setStrictMode=="function")try{Qt.setStrictMode(go,e)}catch{}}var Vt=Math.clz32?Math.clz32:jR,PR=Math.log,UR=Math.LN2;function jR(e){return e>>>=0,e===0?32:31-(PR(e)/UR|0)|0}var Tl=256,Al=4194304;function cr(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194048;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Lu(e,t,a){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var o=n&134217727;return o!==0?(n=o&~s,n!==0?r=cr(n):(i&=o,i!==0?r=cr(i):a||(a=o&~e,a!==0&&(r=cr(a))))):(o=n&~s,o!==0?r=cr(o):i!==0?r=cr(i):a||(a=n&~e,a!==0&&(r=cr(a)))),r===0?0:t!==0&&t!==r&&(t&s)===0&&(s=r&-r,a=t&-t,s>=a||s===32&&(a&4194048)!==0)?t:r}function yo(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function FR(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function ly(){var e=Tl;return Tl<<=1,(Tl&4194048)===0&&(Tl=256),e}function uy(){var e=Al;return Al<<=1,(Al&62914560)===0&&(Al=4194304),e}function Ld(e){for(var t=[],a=0;31>a;a++)t.push(e);return t}function bo(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function zR(e,t,a,n,r,s){var i=e.pendingLanes;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=a,e.entangledLanes&=a,e.errorRecoveryDisabledLanes&=a,e.shellSuspendCounter=0;var o=e.entanglements,u=e.expirationTimes,c=e.hiddenUpdates;for(a=i&~a;0{"use strict";var gR=Symbol.for("react.transitional.element"),yR=Symbol.for("react.fragment");function uv(e,t,a){var n=null;if(a!==void 0&&(n=""+a),t.key!==void 0&&(n=""+t.key),"key"in t){a={};for(var r in t)r!=="key"&&(a[r]=t[r])}else a=t;return t=a.ref,{$$typeof:gR,type:e,key:n,ref:t!==void 0?t:null,props:a}}vl.Fragment=yR;vl.jsx=uv;vl.jsxs=uv});var Sd=kn((LL,dv)=>{"use strict";dv.exports=cv()});var _v=kn(Le=>{"use strict";function Td(e,t){var a=e.length;e.push(t);e:for(;0>>1,r=e[n];if(0<_l(r,t))e[n]=t,e[a]=r,a=n;else break e}}function Oa(e){return e.length===0?null:e[0]}function Rl(e){if(e.length===0)return null;var t=e[0],a=e.pop();if(a!==t){e[0]=a;e:for(var n=0,r=e.length,s=r>>>1;n_l(o,a))u_l(c,o)?(e[n]=c,e[u]=a,n=u):(e[n]=o,e[i]=a,n=i);else if(u_l(c,a))e[n]=c,e[u]=a,n=u;else break e}}return t}function _l(e,t){var a=e.sortIndex-t.sortIndex;return a!==0?a:e.id-t.id}Le.unstable_now=void 0;typeof performance=="object"&&typeof performance.now=="function"?(vv=performance,Le.unstable_now=function(){return vv.now()}):(Rd=Date,gv=Rd.now(),Le.unstable_now=function(){return Rd.now()-gv});var vv,Rd,gv,Wa=[],En=[],wR=1,oa=null,St=3,Ad=!1,ki=!1,Ri=!1,Dd=!1,xv=typeof setTimeout=="function"?setTimeout:null,$v=typeof clearTimeout=="function"?clearTimeout:null,yv=typeof setImmediate<"u"?setImmediate:null;function kl(e){for(var t=Oa(En);t!==null;){if(t.callback===null)Rl(En);else if(t.startTime<=e)Rl(En),t.sortIndex=t.expirationTime,Td(Wa,t);else break;t=Oa(En)}}function Md(e){if(Ri=!1,kl(e),!ki)if(Oa(Wa)!==null)ki=!0,Xr||(Xr=!0,Jr());else{var t=Oa(En);t!==null&&Od(Md,t.startTime-e)}}var Xr=!1,Ci=-1,wv=5,Sv=-1;function Nv(){return Dd?!0:!(Le.unstable_now()-Sve&&Nv());){var n=oa.callback;if(typeof n=="function"){oa.callback=null,St=oa.priorityLevel;var r=n(oa.expirationTime<=e);if(e=Le.unstable_now(),typeof r=="function"){oa.callback=r,kl(e),t=!0;break t}oa===Oa(Wa)&&Rl(Wa),kl(e)}else Rl(Wa);oa=Oa(Wa)}if(oa!==null)t=!0;else{var s=Oa(En);s!==null&&Od(Md,s.startTime-e),t=!1}}break e}finally{oa=null,St=a,Ad=!1}t=void 0}}finally{t?Jr():Xr=!1}}}var Jr;typeof yv=="function"?Jr=function(){yv(Cd)}:typeof MessageChannel<"u"?(Ed=new MessageChannel,bv=Ed.port2,Ed.port1.onmessage=Cd,Jr=function(){bv.postMessage(null)}):Jr=function(){xv(Cd,0)};var Ed,bv;function Od(e,t){Ci=xv(function(){e(Le.unstable_now())},t)}Le.unstable_IdlePriority=5;Le.unstable_ImmediatePriority=1;Le.unstable_LowPriority=4;Le.unstable_NormalPriority=3;Le.unstable_Profiling=null;Le.unstable_UserBlockingPriority=2;Le.unstable_cancelCallback=function(e){e.callback=null};Le.unstable_forceFrameRate=function(e){0>e||125n?(e.sortIndex=a,Td(En,e),Oa(Wa)===null&&e===Oa(En)&&(Ri?($v(Ci),Ci=-1):Ri=!0,Od(Md,a-n))):(e.sortIndex=r,Td(Wa,e),ki||Ad||(ki=!0,Xr||(Xr=!0,Jr()))),e};Le.unstable_shouldYield=Nv;Le.unstable_wrapCallback=function(e){var t=St;return function(){var a=St;St=t;try{return e.apply(this,arguments)}finally{St=a}}}});var Rv=kn((g6,kv)=>{"use strict";kv.exports=_v()});var Ev=kn(Et=>{"use strict";var SR=Ve();function Cv(e){var t="https://react.dev/errors/"+e;if(1{"use strict";function Tv(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Tv)}catch(e){console.error(e)}}Tv(),Av.exports=Ev()});var O0=kn(Ju=>{"use strict";var it=Rv(),ey=Ve(),kR=Dv();function U(e){var t="https://react.dev/errors/"+e;if(1ss||(e.current=gm[ss],gm[ss]=null,ss--)}function Ue(e,t){ss++,gm[ss]=e.current,e.current=t}var ja=za(null),ao=za(null),In=za(null),su=za(null);function iu(e,t){switch(Ue(In,t),Ue(ao,e),Ue(ja,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Bg(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Bg(t),e=w0(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}ht(ja),Ue(ja,e)}function Ns(){ht(ja),ht(ao),ht(In)}function ym(e){e.memoizedState!==null&&Ue(su,e);var t=ja.current,a=w0(t,e.type);t!==a&&(Ue(ao,e),Ue(ja,a))}function ou(e){ao.current===e&&(ht(ja),ht(ao)),su.current===e&&(ht(su),fo._currentValue=vr)}var bm=Object.prototype.hasOwnProperty,cf=it.unstable_scheduleCallback,Ld=it.unstable_cancelCallback,DR=it.unstable_shouldYield,MR=it.unstable_requestPaint,Fa=it.unstable_now,OR=it.unstable_getCurrentPriorityLevel,iy=it.unstable_ImmediatePriority,oy=it.unstable_UserBlockingPriority,lu=it.unstable_NormalPriority,LR=it.unstable_LowPriority,ly=it.unstable_IdlePriority,PR=it.log,UR=it.unstable_setDisableYieldValue,yo=null,Yt=null;function Fn(e){if(typeof PR=="function"&&UR(e),Yt&&typeof Yt.setStrictMode=="function")try{Yt.setStrictMode(yo,e)}catch{}}var Jt=Math.clz32?Math.clz32:BR,jR=Math.log,FR=Math.LN2;function BR(e){return e>>>=0,e===0?32:31-(jR(e)/FR|0)|0}var Tl=256,Al=4194304;function fr(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194048;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Lu(e,t,a){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var o=n&134217727;return o!==0?(n=o&~s,n!==0?r=fr(n):(i&=o,i!==0?r=fr(i):a||(a=o&~e,a!==0&&(r=fr(a))))):(o=n&~s,o!==0?r=fr(o):i!==0?r=fr(i):a||(a=n&~e,a!==0&&(r=fr(a)))),r===0?0:t!==0&&t!==r&&(t&s)===0&&(s=r&-r,a=t&-t,s>=a||s===32&&(a&4194048)!==0)?t:r}function bo(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function zR(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function uy(){var e=Tl;return Tl<<=1,(Tl&4194048)===0&&(Tl=256),e}function cy(){var e=Al;return Al<<=1,(Al&62914560)===0&&(Al=4194304),e}function Pd(e){for(var t=[],a=0;31>a;a++)t.push(e);return t}function xo(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function qR(e,t,a,n,r,s){var i=e.pendingLanes;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=a,e.entangledLanes&=a,e.errorRecoveryDisabledLanes&=a,e.shellSuspendCounter=0;var o=e.entanglements,u=e.expirationTimes,c=e.hiddenUpdates;for(a=i&~a;0)":-1r||u[n]!==c[r]){var d=`
-`+u[n].replace(" at new "," at ");return e.displayName&&d.includes("")&&(d=d.replace("",e.displayName)),d}while(1<=n&&0<=r);break}}}finally{Ud=!1,Error.prepareStackTrace=a}return(a=e?e.displayName||e.name:"")?es(a):""}function QR(e){switch(e.tag){case 26:case 27:case 5:return es(e.type);case 16:return es("Lazy");case 13:return es("Suspense");case 19:return es("SuspenseList");case 0:case 15:return jd(e.type,!1);case 11:return jd(e.type.render,!1);case 1:return jd(e.type,!0);case 31:return es("Activity");default:return""}}function jv(e){try{var t="";do t+=QR(e),e=e.return;while(e);return t}catch(a){return`
+`+u[n].replace(" at new "," at ");return e.displayName&&d.includes("")&&(d=d.replace("",e.displayName)),d}while(1<=n&&0<=r);break}}}finally{jd=!1,Error.prepareStackTrace=a}return(a=e?e.displayName||e.name:"")?ts(a):""}function GR(e){switch(e.tag){case 26:case 27:case 5:return ts(e.type);case 16:return ts("Lazy");case 13:return ts("Suspense");case 19:return ts("SuspenseList");case 0:case 15:return Fd(e.type,!1);case 11:return Fd(e.type.render,!1);case 1:return Fd(e.type,!0);case 31:return ts("Activity");default:return""}}function Fv(e){try{var t="";do t+=GR(e),e=e.return;while(e);return t}catch(a){return`
Error generating stack: `+a.message+`
-`+a.stack}}function oa(e){switch(typeof e){case"bigint":case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function hy(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function VR(e){var t=hy(e)?"checked":"value",a=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),n=""+e[t];if(!e.hasOwnProperty(t)&&typeof a<"u"&&typeof a.get=="function"&&typeof a.set=="function"){var r=a.get,s=a.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return r.call(this)},set:function(i){n=""+i,s.call(this,i)}}),Object.defineProperty(e,t,{enumerable:a.enumerable}),{getValue:function(){return n},setValue:function(i){n=""+i},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function uu(e){e._valueTracker||(e._valueTracker=VR(e))}function vy(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var a=t.getValue(),n="";return e&&(n=hy(e)?e.checked?"true":"false":e.value),e=n,e!==a?(t.setValue(e),!0):!1}function cu(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var GR=/[\n"\\]/g;function ca(e){return e.replace(GR,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function xm(e,t,a,n,r,s,i,o){e.name="",i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"?e.type=i:e.removeAttribute("type"),t!=null?i==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+oa(t)):e.value!==""+oa(t)&&(e.value=""+oa(t)):i!=="submit"&&i!=="reset"||e.removeAttribute("value"),t!=null?$m(e,i,oa(t)):a!=null?$m(e,i,oa(a)):n!=null&&e.removeAttribute("value"),r==null&&s!=null&&(e.defaultChecked=!!s),r!=null&&(e.checked=r&&typeof r!="function"&&typeof r!="symbol"),o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.name=""+oa(o):e.removeAttribute("name")}function gy(e,t,a,n,r,s,i,o){if(s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"&&(e.type=s),t!=null||a!=null){if(!(s!=="submit"&&s!=="reset"||t!=null))return;a=a!=null?""+oa(a):"",t=t!=null?""+oa(t):a,o||t===e.value||(e.value=t),e.defaultValue=t}n=n??r,n=typeof n!="function"&&typeof n!="symbol"&&!!n,e.checked=o?e.checked:!!n,e.defaultChecked=!!n,i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.name=i)}function $m(e,t,a){t==="number"&&cu(e.ownerDocument)===e||e.defaultValue===""+a||(e.defaultValue=""+a)}function vs(e,t,a,n){if(e=e.options,t){t={};for(var r=0;r"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Sm=!1;if(un)try{Xr={},Object.defineProperty(Xr,"passive",{get:function(){Sm=!0}}),window.addEventListener("test",Xr,Xr),window.removeEventListener("test",Xr,Xr)}catch{Sm=!1}var Xr,Un=null,hf=null,Gl=null;function wy(){if(Gl)return Gl;var e,t=hf,a=t.length,n,r="value"in Un?Un.value:Un.textContent,s=r.length;for(e=0;e=Bi),Hv=" ",Qv=!1;function Ny(e,t){switch(e){case"keyup":return wC.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function _y(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var os=!1;function NC(e,t){switch(e){case"compositionend":return _y(t);case"keypress":return t.which!==32?null:(Qv=!0,Hv);case"textInput":return e=t.data,e===Hv&&Qv?null:e;default:return null}}function _C(e,t){if(os)return e==="compositionend"||!gf&&Ny(e,t)?(e=wy(),Gl=hf=Un=null,os=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:a,offset:t-e};e=n}e:{for(;a;){if(a.nextSibling){a=a.nextSibling;break e}a=a.parentNode}a=void 0}a=Jv(a)}}function Ey(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ey(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Ty(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=cu(e.document);t instanceof e.HTMLIFrameElement;){try{var a=typeof t.contentWindow.location.href=="string"}catch{a=!1}if(a)e=t.contentWindow;else break;t=cu(e.document)}return t}function yf(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var MC=un&&"documentMode"in document&&11>=document.documentMode,ls=null,Nm=null,Ii=null,_m=!1;function Zv(e,t,a){var n=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;_m||ls==null||ls!==cu(n)||(n=ls,"selectionStart"in n&&yf(n)?n={start:n.selectionStart,end:n.selectionEnd}:(n=(n.ownerDocument&&n.ownerDocument.defaultView||window).getSelection(),n={anchorNode:n.anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset}),Ii&&ro(Ii,n)||(Ii=n,n=Cu(Nm,"onSelect"),0>=i,r-=i,an=1<<32-Vt(t)+r|a<s?s:8;var i=ne.T,o={};ne.T=o,Ff(e,!1,t,a);try{var u=r(),c=ne.S;if(c!==null&&c(o,u),u!==null&&typeof u=="object"&&typeof u.then=="function"){var d=qC(u,n);Yi(e,t,d,Gt(e))}else Yi(e,t,n,Gt(e))}catch(m){Yi(e,t,{then:function(){},status:"rejected",reason:m},Gt())}finally{ve.p=s,ne.T=i}}function VC(){}function jm(e,t,a,n){if(e.tag!==5)throw Error(P(476));var r=hb(e).queue;pb(e,r,t,fr,a===null?VC:function(){return vb(e),a(n)})}function hb(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:fr,baseState:fr,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:cn,lastRenderedState:fr},next:null};var a={};return t.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:cn,lastRenderedState:a},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function vb(e){var t=hb(e).next.queue;Yi(e,t,{},Gt())}function jf(){return xt(mo)}function gb(){return Xe().memoizedState}function yb(){return Xe().memoizedState}function GC(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var a=Gt();e=Bn(a);var n=qn(t,e,a);n!==null&&(Yt(n,t,a),Qi(n,t,a)),t={cache:Nf()},e.payload=t;return}t=t.return}}function YC(e,t,a){var n=Gt();a={lane:n,revertLane:0,action:a,hasEagerState:!1,eagerState:null,next:null},Ku(e)?xb(t,a):(a=xf(e,t,a,n),a!==null&&(Yt(a,e,n),$b(a,t,n)))}function bb(e,t,a){var n=Gt();Yi(e,t,a,n)}function Yi(e,t,a,n){var r={lane:n,revertLane:0,action:a,hasEagerState:!1,eagerState:null,next:null};if(Ku(e))xb(t,r);else{var s=e.alternate;if(e.lanes===0&&(s===null||s.lanes===0)&&(s=t.lastRenderedReducer,s!==null))try{var i=t.lastRenderedState,o=s(i,a);if(r.hasEagerState=!0,r.eagerState=o,Jt(o,i))return zu(e,t,r,0),Ee===null&&Fu(),!1}catch{}finally{}if(a=xf(e,t,r,n),a!==null)return Yt(a,e,n),$b(a,t,n),!0}return!1}function Ff(e,t,a,n){if(n={lane:2,revertLane:Vf(),action:n,hasEagerState:!1,eagerState:null,next:null},Ku(e)){if(t)throw Error(P(479))}else t=xf(e,a,n,2),t!==null&&Yt(t,e,2)}function Ku(e){var t=e.alternate;return e===ie||t!==null&&t===ie}function xb(e,t){bs=vu=!0;var a=e.pending;a===null?t.next=t:(t.next=a.next,a.next=t),e.pending=t}function $b(e,t,a){if((a&4194048)!==0){var n=t.lanes;n&=e.pendingLanes,a|=n,t.lanes=a,dy(e,a)}}var yu={readContext:xt,use:qu,useCallback:Ve,useContext:Ve,useEffect:Ve,useImperativeHandle:Ve,useLayoutEffect:Ve,useInsertionEffect:Ve,useMemo:Ve,useReducer:Ve,useRef:Ve,useState:Ve,useDebugValue:Ve,useDeferredValue:Ve,useTransition:Ve,useSyncExternalStore:Ve,useId:Ve,useHostTransitionStatus:Ve,useFormState:Ve,useActionState:Ve,useOptimistic:Ve,useMemoCache:Ve,useCacheRefresh:Ve},wb={readContext:xt,use:qu,useCallback:function(e,t){return Ot().memoizedState=[e,t===void 0?null:t],e},useContext:xt,useEffect:pg,useImperativeHandle:function(e,t,a){a=a!=null?a.concat([e]):null,Wl(4194308,4,ub.bind(null,t,e),a)},useLayoutEffect:function(e,t){return Wl(4194308,4,e,t)},useInsertionEffect:function(e,t){Wl(4,2,e,t)},useMemo:function(e,t){var a=Ot();t=t===void 0?null:t;var n=e();if(wr){Pn(!0);try{e()}finally{Pn(!1)}}return a.memoizedState=[n,t],n},useReducer:function(e,t,a){var n=Ot();if(a!==void 0){var r=a(t);if(wr){Pn(!0);try{a(t)}finally{Pn(!1)}}}else r=t;return n.memoizedState=n.baseState=r,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:r},n.queue=e,e=e.dispatch=YC.bind(null,ie,e),[n.memoizedState,e]},useRef:function(e){var t=Ot();return e={current:e},t.memoizedState=e},useState:function(e){e=Pm(e);var t=e.queue,a=bb.bind(null,ie,t);return t.dispatch=a,[e.memoizedState,a]},useDebugValue:Pf,useDeferredValue:function(e,t){var a=Ot();return Uf(a,e,t)},useTransition:function(){var e=Pm(!1);return e=pb.bind(null,ie,e.queue,!0,!1),Ot().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,a){var n=ie,r=Ot();if(he){if(a===void 0)throw Error(P(407));a=a()}else{if(a=t(),Ee===null)throw Error(P(349));(de&124)!==0||Yy(n,t,a)}r.memoizedState=a;var s={value:a,getSnapshot:t};return r.queue=s,pg(Xy.bind(null,n,s,e),[e]),n.flags|=2048,Cs(9,Iu(),Jy.bind(null,n,s,a,t),null),a},useId:function(){var e=Ot(),t=Ee.identifierPrefix;if(he){var a=nn,n=an;a=(n&~(1<<32-Vt(n)-1)).toString(32)+a,t="\xAB"+t+"R"+a,a=gu++,0T?(A=_,_=null):A=_.sibling;var O=f(g,_,b[T],$);if(O===null){_===null&&(_=A);break}e&&_&&O.alternate===null&&t(g,_),v=s(O,v,T),R===null?S=O:R.sibling=O,R=O,_=A}if(T===b.length)return a(g,_),he&&dr(g,T),S;if(_===null){for(;TT?(A=_,_=null):A=_.sibling;var U=f(g,_,O.value,$);if(U===null){_===null&&(_=A);break}e&&_&&U.alternate===null&&t(g,_),v=s(U,v,T),R===null?S=U:R.sibling=U,R=U,_=A}if(O.done)return a(g,_),he&&dr(g,T),S;if(_===null){for(;!O.done;T++,O=b.next())O=m(g,O.value,$),O!==null&&(v=s(O,v,T),R===null?S=O:R.sibling=O,R=O);return he&&dr(g,T),S}for(_=n(_);!O.done;T++,O=b.next())O=p(_,g,T,O.value,$),O!==null&&(e&&O.alternate!==null&&_.delete(O.key===null?T:O.key),v=s(O,v,T),R===null?S=O:R.sibling=O,R=O);return e&&_.forEach(function(C){return t(g,C)}),he&&dr(g,T),S}function w(g,v,b,$){if(typeof b=="object"&&b!==null&&b.type===ns&&b.key===null&&(b=b.props.children),typeof b=="object"&&b!==null){switch(b.$$typeof){case El:e:{for(var S=b.key;v!==null;){if(v.key===S){if(S=b.type,S===ns){if(v.tag===7){a(g,v.sibling),$=r(v,b.props.children),$.return=g,g=$;break e}}else if(v.elementType===S||typeof S=="object"&&S!==null&&S.$$typeof===Tn&&hg(S)===v.type){a(g,v.sibling),$=r(v,b.props),Di($,b),$.return=g,g=$;break e}a(g,v);break}else t(g,v);v=v.sibling}b.type===ns?($=pr(b.props.children,g.mode,$,b.key),$.return=g,g=$):($=Jl(b.type,b.key,b.props,null,g.mode,$),Di($,b),$.return=g,g=$)}return i(g);case Ui:e:{for(S=b.key;v!==null;){if(v.key===S)if(v.tag===4&&v.stateNode.containerInfo===b.containerInfo&&v.stateNode.implementation===b.implementation){a(g,v.sibling),$=r(v,b.children||[]),$.return=g,g=$;break e}else{a(g,v);break}else t(g,v);v=v.sibling}$=Qd(b,g.mode,$),$.return=g,g=$}return i(g);case Tn:return S=b._init,b=S(b._payload),w(g,v,b,$)}if(ji(b))return x(g,v,b,$);if(Ei(b)){if(S=Ei(b),typeof S!="function")throw Error(P(150));return b=S.call(b),y(g,v,b,$)}if(typeof b.then=="function")return w(g,v,jl(b),$);if(b.$$typeof===tn)return w(g,v,Pl(g,b),$);Fl(g,b)}return typeof b=="string"&&b!==""||typeof b=="number"||typeof b=="bigint"?(b=""+b,v!==null&&v.tag===6?(a(g,v.sibling),$=r(v,b),$.return=g,g=$):(a(g,v),$=Hd(b,g.mode,$),$.return=g,g=$),i(g)):a(g,v)}return function(g,v,b,$){try{oo=0;var S=w(g,v,b,$);return $s=null,S}catch(_){if(_===_o||_===Bu)throw _;var R=Ht(29,_,null,g.mode);return R.lanes=$,R.return=g,R}finally{}}}var Es=Nb(!0),_b=Nb(!1),fa=ja(null),Ua=null;function Mn(e){var t=e.alternate;Pe(nt,nt.current&1),Pe(fa,e),Ua===null&&(t===null||Rs.current!==null||t.memoizedState!==null)&&(Ua=e)}function kb(e){if(e.tag===22){if(Pe(nt,nt.current),Pe(fa,e),Ua===null){var t=e.alternate;t!==null&&t.memoizedState!==null&&(Ua=e)}}else On(e)}function On(){Pe(nt,nt.current),Pe(fa,fa.current)}function sn(e){dt(fa),Ua===e&&(Ua=null),dt(nt)}var nt=ja(0);function bu(e){for(var t=e;t!==null;){if(t.tag===13){var a=t.memoizedState;if(a!==null&&(a=a.dehydrated,a===null||a.data==="$?"||tf(a)))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&128)!==0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function Yd(e,t,a,n){t=e.memoizedState,a=a(n,t),a=a==null?t:De({},t,a),e.memoizedState=a,e.lanes===0&&(e.updateQueue.baseState=a)}var Fm={enqueueSetState:function(e,t,a){e=e._reactInternals;var n=Gt(),r=Bn(n);r.payload=t,a!=null&&(r.callback=a),t=qn(e,r,n),t!==null&&(Yt(t,e,n),Qi(t,e,n))},enqueueReplaceState:function(e,t,a){e=e._reactInternals;var n=Gt(),r=Bn(n);r.tag=1,r.payload=t,a!=null&&(r.callback=a),t=qn(e,r,n),t!==null&&(Yt(t,e,n),Qi(t,e,n))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var a=Gt(),n=Bn(a);n.tag=2,t!=null&&(n.callback=t),t=qn(e,n,a),t!==null&&(Yt(t,e,a),Qi(t,e,a))}};function vg(e,t,a,n,r,s,i){return e=e.stateNode,typeof e.shouldComponentUpdate=="function"?e.shouldComponentUpdate(n,s,i):t.prototype&&t.prototype.isPureReactComponent?!ro(a,n)||!ro(r,s):!0}function gg(e,t,a,n){e=t.state,typeof t.componentWillReceiveProps=="function"&&t.componentWillReceiveProps(a,n),typeof t.UNSAFE_componentWillReceiveProps=="function"&&t.UNSAFE_componentWillReceiveProps(a,n),t.state!==e&&Fm.enqueueReplaceState(t,t.state,null)}function Sr(e,t){var a=t;if("ref"in t){a={};for(var n in t)n!=="ref"&&(a[n]=t[n])}if(e=e.defaultProps){a===t&&(a=De({},a));for(var r in e)a[r]===void 0&&(a[r]=e[r])}return a}var xu=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Rb(e){xu(e)}function Cb(e){console.error(e)}function Eb(e){xu(e)}function $u(e,t){try{var a=e.onUncaughtError;a(t.value,{componentStack:t.stack})}catch(n){setTimeout(function(){throw n})}}function yg(e,t,a){try{var n=e.onCaughtError;n(a.value,{componentStack:a.stack,errorBoundary:t.tag===1?t.stateNode:null})}catch(r){setTimeout(function(){throw r})}}function zm(e,t,a){return a=Bn(a),a.tag=3,a.payload={element:null},a.callback=function(){$u(e,t)},a}function Tb(e){return e=Bn(e),e.tag=3,e}function Ab(e,t,a,n){var r=a.type.getDerivedStateFromError;if(typeof r=="function"){var s=n.value;e.payload=function(){return r(s)},e.callback=function(){yg(t,a,n)}}var i=a.stateNode;i!==null&&typeof i.componentDidCatch=="function"&&(e.callback=function(){yg(t,a,n),typeof r!="function"&&(In===null?In=new Set([this]):In.add(this));var o=n.stack;this.componentDidCatch(n.value,{componentStack:o!==null?o:""})})}function XC(e,t,a,n,r){if(a.flags|=32768,n!==null&&typeof n=="object"&&typeof n.then=="function"){if(t=a.alternate,t!==null&&So(t,a,r,!0),a=fa.current,a!==null){switch(a.tag){case 13:return Ua===null?Gm():a.alternate===null&&Ke===0&&(Ke=3),a.flags&=-257,a.flags|=65536,a.lanes=r,n===Dm?a.flags|=16384:(t=a.updateQueue,t===null?a.updateQueue=new Set([n]):t.add(n),im(e,n,r)),!1;case 22:return a.flags|=65536,n===Dm?a.flags|=16384:(t=a.updateQueue,t===null?(t={transitions:null,markerInstances:null,retryQueue:new Set([n])},a.updateQueue=t):(a=t.retryQueue,a===null?t.retryQueue=new Set([n]):a.add(n)),im(e,n,r)),!1}throw Error(P(435,a.tag))}return im(e,n,r),Gm(),!1}if(he)return t=fa.current,t!==null?((t.flags&65536)===0&&(t.flags|=256),t.flags|=65536,t.lanes=r,n!==Rm&&(e=Error(P(422),{cause:n}),so(da(e,a)))):(n!==Rm&&(t=Error(P(423),{cause:n}),so(da(t,a))),e=e.current.alternate,e.flags|=65536,r&=-r,e.lanes|=r,n=da(n,a),r=zm(e.stateNode,n,r),Vd(e,r),Ke!==4&&(Ke=2)),!1;var s=Error(P(520),{cause:n});if(s=da(s,a),Zi===null?Zi=[s]:Zi.push(s),Ke!==4&&(Ke=2),t===null)return!0;n=da(n,a),a=t;do{switch(a.tag){case 3:return a.flags|=65536,e=r&-r,a.lanes|=e,e=zm(a.stateNode,n,e),Vd(a,e),!1;case 1:if(t=a.type,s=a.stateNode,(a.flags&128)===0&&(typeof t.getDerivedStateFromError=="function"||s!==null&&typeof s.componentDidCatch=="function"&&(In===null||!In.has(s))))return a.flags|=65536,r&=-r,a.lanes|=r,r=Tb(r),Ab(r,e,a,n),Vd(a,r),!1}a=a.return}while(a!==null);return!1}var Db=Error(P(461)),ct=!1;function pt(e,t,a,n){t.child=e===null?_b(t,null,a,n):Es(t,e.child,a,n)}function bg(e,t,a,n,r){a=a.render;var s=t.ref;if("ref"in n){var i={};for(var o in n)o!=="ref"&&(i[o]=n[o])}else i=n;return $r(t),n=Ef(e,t,a,i,s,r),o=Tf(),e!==null&&!ct?(Af(e,t,r),dn(e,t,r)):(he&&o&&wf(t),t.flags|=1,pt(e,t,n,r),t.child)}function xg(e,t,a,n,r){if(e===null){var s=a.type;return typeof s=="function"&&!$f(s)&&s.defaultProps===void 0&&a.compare===null?(t.tag=15,t.type=s,Mb(e,t,s,n,r)):(e=Jl(a.type,null,n,t,t.mode,r),e.ref=t.ref,e.return=t,t.child=e)}if(s=e.child,!zf(e,r)){var i=s.memoizedProps;if(a=a.compare,a=a!==null?a:ro,a(i,n)&&e.ref===t.ref)return dn(e,t,r)}return t.flags|=1,e=on(s,n),e.ref=t.ref,e.return=t,t.child=e}function Mb(e,t,a,n,r){if(e!==null){var s=e.memoizedProps;if(ro(s,n)&&e.ref===t.ref)if(ct=!1,t.pendingProps=n=s,zf(e,r))(e.flags&131072)!==0&&(ct=!0);else return t.lanes=e.lanes,dn(e,t,r)}return Bm(e,t,a,n,r)}function Ob(e,t,a){var n=t.pendingProps,r=n.children,s=e!==null?e.memoizedState:null;if(n.mode==="hidden"){if((t.flags&128)!==0){if(n=s!==null?s.baseLanes|a:a,e!==null){for(r=t.child=e.child,s=0;r!==null;)s=s|r.lanes|r.childLanes,r=r.sibling;t.childLanes=s&~n}else t.childLanes=0,t.child=null;return $g(e,t,n,a)}if((a&536870912)!==0)t.memoizedState={baseLanes:0,cachePool:null},e!==null&&Xl(t,s!==null?s.cachePool:null),s!==null?lg(t,s):Lm(),kb(t);else return t.lanes=t.childLanes=536870912,$g(e,t,s!==null?s.baseLanes|a:a,a)}else s!==null?(Xl(t,s.cachePool),lg(t,s),On(t),t.memoizedState=null):(e!==null&&Xl(t,null),Lm(),On(t));return pt(e,t,r,a),t.child}function $g(e,t,a,n){var r=_f();return r=r===null?null:{parent:at._currentValue,pool:r},t.memoizedState={baseLanes:a,cachePool:r},e!==null&&Xl(t,null),Lm(),kb(t),e!==null&&So(e,t,n,!0),null}function eu(e,t){var a=t.ref;if(a===null)e!==null&&e.ref!==null&&(t.flags|=4194816);else{if(typeof a!="function"&&typeof a!="object")throw Error(P(284));(e===null||e.ref!==a)&&(t.flags|=4194816)}}function Bm(e,t,a,n,r){return $r(t),a=Ef(e,t,a,n,void 0,r),n=Tf(),e!==null&&!ct?(Af(e,t,r),dn(e,t,r)):(he&&n&&wf(t),t.flags|=1,pt(e,t,a,r),t.child)}function wg(e,t,a,n,r,s){return $r(t),t.updateQueue=null,a=Vy(t,n,a,r),Qy(e),n=Tf(),e!==null&&!ct?(Af(e,t,s),dn(e,t,s)):(he&&n&&wf(t),t.flags|=1,pt(e,t,a,s),t.child)}function Sg(e,t,a,n,r){if($r(t),t.stateNode===null){var s=ds,i=a.contextType;typeof i=="object"&&i!==null&&(s=xt(i)),s=new a(n,s),t.memoizedState=s.state!==null&&s.state!==void 0?s.state:null,s.updater=Fm,t.stateNode=s,s._reactInternals=t,s=t.stateNode,s.props=n,s.state=t.memoizedState,s.refs={},kf(t),i=a.contextType,s.context=typeof i=="object"&&i!==null?xt(i):ds,s.state=t.memoizedState,i=a.getDerivedStateFromProps,typeof i=="function"&&(Yd(t,a,i,n),s.state=t.memoizedState),typeof a.getDerivedStateFromProps=="function"||typeof s.getSnapshotBeforeUpdate=="function"||typeof s.UNSAFE_componentWillMount!="function"&&typeof s.componentWillMount!="function"||(i=s.state,typeof s.componentWillMount=="function"&&s.componentWillMount(),typeof s.UNSAFE_componentWillMount=="function"&&s.UNSAFE_componentWillMount(),i!==s.state&&Fm.enqueueReplaceState(s,s.state,null),Gi(t,n,s,r),Vi(),s.state=t.memoizedState),typeof s.componentDidMount=="function"&&(t.flags|=4194308),n=!0}else if(e===null){s=t.stateNode;var o=t.memoizedProps,u=Sr(a,o);s.props=u;var c=s.context,d=a.contextType;i=ds,typeof d=="object"&&d!==null&&(i=xt(d));var m=a.getDerivedStateFromProps;d=typeof m=="function"||typeof s.getSnapshotBeforeUpdate=="function",o=t.pendingProps!==o,d||typeof s.UNSAFE_componentWillReceiveProps!="function"&&typeof s.componentWillReceiveProps!="function"||(o||c!==i)&&gg(t,s,n,i),An=!1;var f=t.memoizedState;s.state=f,Gi(t,n,s,r),Vi(),c=t.memoizedState,o||f!==c||An?(typeof m=="function"&&(Yd(t,a,m,n),c=t.memoizedState),(u=An||vg(t,a,u,n,f,c,i))?(d||typeof s.UNSAFE_componentWillMount!="function"&&typeof s.componentWillMount!="function"||(typeof s.componentWillMount=="function"&&s.componentWillMount(),typeof s.UNSAFE_componentWillMount=="function"&&s.UNSAFE_componentWillMount()),typeof s.componentDidMount=="function"&&(t.flags|=4194308)):(typeof s.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=n,t.memoizedState=c),s.props=n,s.state=c,s.context=i,n=u):(typeof s.componentDidMount=="function"&&(t.flags|=4194308),n=!1)}else{s=t.stateNode,Mm(e,t),i=t.memoizedProps,d=Sr(a,i),s.props=d,m=t.pendingProps,f=s.context,c=a.contextType,u=ds,typeof c=="object"&&c!==null&&(u=xt(c)),o=a.getDerivedStateFromProps,(c=typeof o=="function"||typeof s.getSnapshotBeforeUpdate=="function")||typeof s.UNSAFE_componentWillReceiveProps!="function"&&typeof s.componentWillReceiveProps!="function"||(i!==m||f!==u)&&gg(t,s,n,u),An=!1,f=t.memoizedState,s.state=f,Gi(t,n,s,r),Vi();var p=t.memoizedState;i!==m||f!==p||An||e!==null&&e.dependencies!==null&&pu(e.dependencies)?(typeof o=="function"&&(Yd(t,a,o,n),p=t.memoizedState),(d=An||vg(t,a,d,n,f,p,u)||e!==null&&e.dependencies!==null&&pu(e.dependencies))?(c||typeof s.UNSAFE_componentWillUpdate!="function"&&typeof s.componentWillUpdate!="function"||(typeof s.componentWillUpdate=="function"&&s.componentWillUpdate(n,p,u),typeof s.UNSAFE_componentWillUpdate=="function"&&s.UNSAFE_componentWillUpdate(n,p,u)),typeof s.componentDidUpdate=="function"&&(t.flags|=4),typeof s.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof s.componentDidUpdate!="function"||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),typeof s.getSnapshotBeforeUpdate!="function"||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),t.memoizedProps=n,t.memoizedState=p),s.props=n,s.state=p,s.context=u,n=d):(typeof s.componentDidUpdate!="function"||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),typeof s.getSnapshotBeforeUpdate!="function"||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),n=!1)}return s=n,eu(e,t),n=(t.flags&128)!==0,s||n?(s=t.stateNode,a=n&&typeof a.getDerivedStateFromError!="function"?null:s.render(),t.flags|=1,e!==null&&n?(t.child=Es(t,e.child,null,r),t.child=Es(t,null,a,r)):pt(e,t,a,r),t.memoizedState=s.state,e=t.child):e=dn(e,t,r),e}function Ng(e,t,a,n){return wo(),t.flags|=256,pt(e,t,a,n),t.child}var Jd={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function Xd(e){return{baseLanes:e,cachePool:By()}}function Zd(e,t,a){return e=e!==null?e.childLanes&~a:0,t&&(e|=ma),e}function Lb(e,t,a){var n=t.pendingProps,r=!1,s=(t.flags&128)!==0,i;if((i=s)||(i=e!==null&&e.memoizedState===null?!1:(nt.current&2)!==0),i&&(r=!0,t.flags&=-129),i=(t.flags&32)!==0,t.flags&=-33,e===null){if(he){if(r?Mn(t):On(t),he){var o=Ie,u;if(u=o){e:{for(u=o,o=Ma;u.nodeType!==8;){if(!o){o=null;break e}if(u=xa(u.nextSibling),u===null){o=null;break e}}o=u}o!==null?(t.memoizedState={dehydrated:o,treeContext:hr!==null?{id:an,overflow:nn}:null,retryLane:536870912,hydrationErrors:null},u=Ht(18,null,null,0),u.stateNode=o,u.return=t,t.child=u,Rt=t,Ie=null,u=!0):u=!1}u||xr(t)}if(o=t.memoizedState,o!==null&&(o=o.dehydrated,o!==null))return tf(o)?t.lanes=32:t.lanes=536870912,null;sn(t)}return o=n.children,n=n.fallback,r?(On(t),r=t.mode,o=wu({mode:"hidden",children:o},r),n=pr(n,r,a,null),o.return=t,n.return=t,o.sibling=n,t.child=o,r=t.child,r.memoizedState=Xd(a),r.childLanes=Zd(e,i,a),t.memoizedState=Jd,n):(Mn(t),qm(t,o))}if(u=e.memoizedState,u!==null&&(o=u.dehydrated,o!==null)){if(s)t.flags&256?(Mn(t),t.flags&=-257,t=Wd(e,t,a)):t.memoizedState!==null?(On(t),t.child=e.child,t.flags|=128,t=null):(On(t),r=n.fallback,o=t.mode,n=wu({mode:"visible",children:n.children},o),r=pr(r,o,a,null),r.flags|=2,n.return=t,r.return=t,n.sibling=r,t.child=n,Es(t,e.child,null,a),n=t.child,n.memoizedState=Xd(a),n.childLanes=Zd(e,i,a),t.memoizedState=Jd,t=r);else if(Mn(t),tf(o)){if(i=o.nextSibling&&o.nextSibling.dataset,i)var c=i.dgst;i=c,n=Error(P(419)),n.stack="",n.digest=i,so({value:n,source:null,stack:null}),t=Wd(e,t,a)}else if(ct||So(e,t,a,!1),i=(a&e.childLanes)!==0,ct||i){if(i=Ee,i!==null&&(n=a&-a,n=(n&42)!==0?1:cf(n),n=(n&(i.suspendedLanes|a))!==0?0:n,n!==0&&n!==u.retryLane))throw u.retryLane=n,Ps(e,n),Yt(i,e,n),Db;o.data==="$?"||Gm(),t=Wd(e,t,a)}else o.data==="$?"?(t.flags|=192,t.child=e.child,t=null):(e=u.treeContext,Ie=xa(o.nextSibling),Rt=t,he=!0,vr=null,Ma=!1,e!==null&&(la[ua++]=an,la[ua++]=nn,la[ua++]=hr,an=e.id,nn=e.overflow,hr=t),t=qm(t,n.children),t.flags|=4096);return t}return r?(On(t),r=n.fallback,o=t.mode,u=e.child,c=u.sibling,n=on(u,{mode:"hidden",children:n.children}),n.subtreeFlags=u.subtreeFlags&65011712,c!==null?r=on(c,r):(r=pr(r,o,a,null),r.flags|=2),r.return=t,n.return=t,n.sibling=r,t.child=n,n=r,r=t.child,o=e.child.memoizedState,o===null?o=Xd(a):(u=o.cachePool,u!==null?(c=at._currentValue,u=u.parent!==c?{parent:c,pool:c}:u):u=By(),o={baseLanes:o.baseLanes|a,cachePool:u}),r.memoizedState=o,r.childLanes=Zd(e,i,a),t.memoizedState=Jd,n):(Mn(t),a=e.child,e=a.sibling,a=on(a,{mode:"visible",children:n.children}),a.return=t,a.sibling=null,e!==null&&(i=t.deletions,i===null?(t.deletions=[e],t.flags|=16):i.push(e)),t.child=a,t.memoizedState=null,a)}function qm(e,t){return t=wu({mode:"visible",children:t},e.mode),t.return=e,e.child=t}function wu(e,t){return e=Ht(22,e,null,t),e.lanes=0,e.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},e}function Wd(e,t,a){return Es(t,e.child,null,a),e=qm(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function _g(e,t,a){e.lanes|=t;var n=e.alternate;n!==null&&(n.lanes|=t),Em(e.return,t,a)}function em(e,t,a,n,r){var s=e.memoizedState;s===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:n,tail:a,tailMode:r}:(s.isBackwards=t,s.rendering=null,s.renderingStartTime=0,s.last=n,s.tail=a,s.tailMode=r)}function Pb(e,t,a){var n=t.pendingProps,r=n.revealOrder,s=n.tail;if(pt(e,t,n.children,a),n=nt.current,(n&2)!==0)n=n&1|2,t.flags|=128;else{if(e!==null&&(e.flags&128)!==0)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&_g(e,a,t);else if(e.tag===19)_g(e,a,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}n&=1}switch(Pe(nt,n),r){case"forwards":for(a=t.child,r=null;a!==null;)e=a.alternate,e!==null&&bu(e)===null&&(r=a),a=a.sibling;a=r,a===null?(r=t.child,t.child=null):(r=a.sibling,a.sibling=null),em(t,!1,r,a,s);break;case"backwards":for(a=null,r=t.child,t.child=null;r!==null;){if(e=r.alternate,e!==null&&bu(e)===null){t.child=r;break}e=r.sibling,r.sibling=a,a=r,r=e}em(t,!0,a,null,s);break;case"together":em(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function dn(e,t,a){if(e!==null&&(t.dependencies=e.dependencies),Jn|=t.lanes,(a&t.childLanes)===0)if(e!==null){if(So(e,t,a,!1),(a&t.childLanes)===0)return null}else return null;if(e!==null&&t.child!==e.child)throw Error(P(153));if(t.child!==null){for(e=t.child,a=on(e,e.pendingProps),t.child=a,a.return=t;e.sibling!==null;)e=e.sibling,a=a.sibling=on(e,e.pendingProps),a.return=t;a.sibling=null}return t.child}function zf(e,t){return(e.lanes&t)!==0?!0:(e=e.dependencies,!!(e!==null&&pu(e)))}function ZC(e,t,a){switch(t.tag){case 3:iu(t,t.stateNode.containerInfo),Dn(t,at,e.memoizedState.cache),wo();break;case 27:case 5:gm(t);break;case 4:iu(t,t.stateNode.containerInfo);break;case 10:Dn(t,t.type,t.memoizedProps.value);break;case 13:var n=t.memoizedState;if(n!==null)return n.dehydrated!==null?(Mn(t),t.flags|=128,null):(a&t.child.childLanes)!==0?Lb(e,t,a):(Mn(t),e=dn(e,t,a),e!==null?e.sibling:null);Mn(t);break;case 19:var r=(e.flags&128)!==0;if(n=(a&t.childLanes)!==0,n||(So(e,t,a,!1),n=(a&t.childLanes)!==0),r){if(n)return Pb(e,t,a);t.flags|=128}if(r=t.memoizedState,r!==null&&(r.rendering=null,r.tail=null,r.lastEffect=null),Pe(nt,nt.current),n)break;return null;case 22:case 23:return t.lanes=0,Ob(e,t,a);case 24:Dn(t,at,e.memoizedState.cache)}return dn(e,t,a)}function Ub(e,t,a){if(e!==null)if(e.memoizedProps!==t.pendingProps)ct=!0;else{if(!zf(e,a)&&(t.flags&128)===0)return ct=!1,ZC(e,t,a);ct=(e.flags&131072)!==0}else ct=!1,he&&(t.flags&1048576)!==0&&Fy(t,fu,t.index);switch(t.lanes=0,t.tag){case 16:e:{e=t.pendingProps;var n=t.elementType,r=n._init;if(n=r(n._payload),t.type=n,typeof n=="function")$f(n)?(e=Sr(n,e),t.tag=1,t=Sg(null,t,n,e,a)):(t.tag=0,t=Bm(null,t,n,e,a));else{if(n!=null){if(r=n.$$typeof,r===of){t.tag=11,t=bg(null,t,n,e,a);break e}else if(r===lf){t.tag=14,t=xg(null,t,n,e,a);break e}}throw t=hm(n)||n,Error(P(306,t,""))}}return t;case 0:return Bm(e,t,t.type,t.pendingProps,a);case 1:return n=t.type,r=Sr(n,t.pendingProps),Sg(e,t,n,r,a);case 3:e:{if(iu(t,t.stateNode.containerInfo),e===null)throw Error(P(387));n=t.pendingProps;var s=t.memoizedState;r=s.element,Mm(e,t),Gi(t,n,null,a);var i=t.memoizedState;if(n=i.cache,Dn(t,at,n),n!==s.cache&&Tm(t,[at],a,!0),Vi(),n=i.element,s.isDehydrated)if(s={element:n,isDehydrated:!1,cache:i.cache},t.updateQueue.baseState=s,t.memoizedState=s,t.flags&256){t=Ng(e,t,n,a);break e}else if(n!==r){r=da(Error(P(424)),t),so(r),t=Ng(e,t,n,a);break e}else{switch(e=t.stateNode.containerInfo,e.nodeType){case 9:e=e.body;break;default:e=e.nodeName==="HTML"?e.ownerDocument.body:e}for(Ie=xa(e.firstChild),Rt=t,he=!0,vr=null,Ma=!0,a=_b(t,null,n,a),t.child=a;a;)a.flags=a.flags&-3|4096,a=a.sibling}else{if(wo(),n===r){t=dn(e,t,a);break e}pt(e,t,n,a)}t=t.child}return t;case 26:return eu(e,t),e===null?(a=Kg(t.type,null,t.pendingProps,null))?t.memoizedState=a:he||(a=t.type,e=t.pendingProps,n=Eu(zn.current).createElement(a),n[bt]=t,n[Ut]=e,vt(n,a,e),ut(n),t.stateNode=n):t.memoizedState=Kg(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return gm(t),e===null&&he&&(n=t.stateNode=S0(t.type,t.pendingProps,zn.current),Rt=t,Ma=!0,r=Ie,Zn(t.type)?(af=r,Ie=xa(n.firstChild)):Ie=r),pt(e,t,t.pendingProps.children,a),eu(e,t),e===null&&(t.flags|=4194304),t.child;case 5:return e===null&&he&&((r=n=Ie)&&(n=NE(n,t.type,t.pendingProps,Ma),n!==null?(t.stateNode=n,Rt=t,Ie=xa(n.firstChild),Ma=!1,r=!0):r=!1),r||xr(t)),gm(t),r=t.type,s=t.pendingProps,i=e!==null?e.memoizedProps:null,n=s.children,Wm(r,s)?n=null:i!==null&&Wm(r,i)&&(t.flags|=32),t.memoizedState!==null&&(r=Ef(e,t,KC,null,null,a),mo._currentValue=r),eu(e,t),pt(e,t,n,a),t.child;case 6:return e===null&&he&&((e=a=Ie)&&(a=_E(a,t.pendingProps,Ma),a!==null?(t.stateNode=a,Rt=t,Ie=null,e=!0):e=!1),e||xr(t)),null;case 13:return Lb(e,t,a);case 4:return iu(t,t.stateNode.containerInfo),n=t.pendingProps,e===null?t.child=Es(t,null,n,a):pt(e,t,n,a),t.child;case 11:return bg(e,t,t.type,t.pendingProps,a);case 7:return pt(e,t,t.pendingProps,a),t.child;case 8:return pt(e,t,t.pendingProps.children,a),t.child;case 12:return pt(e,t,t.pendingProps.children,a),t.child;case 10:return n=t.pendingProps,Dn(t,t.type,n.value),pt(e,t,n.children,a),t.child;case 9:return r=t.type._context,n=t.pendingProps.children,$r(t),r=xt(r),n=n(r),t.flags|=1,pt(e,t,n,a),t.child;case 14:return xg(e,t,t.type,t.pendingProps,a);case 15:return Mb(e,t,t.type,t.pendingProps,a);case 19:return Pb(e,t,a);case 31:return n=t.pendingProps,a=t.mode,n={mode:n.mode,children:n.children},e===null?(a=wu(n,a),a.ref=t.ref,t.child=a,a.return=t,t=a):(a=on(e.child,n),a.ref=t.ref,t.child=a,a.return=t,t=a),t;case 22:return Ob(e,t,a);case 24:return $r(t),n=xt(at),e===null?(r=_f(),r===null&&(r=Ee,s=Nf(),r.pooledCache=s,s.refCount++,s!==null&&(r.pooledCacheLanes|=a),r=s),t.memoizedState={parent:n,cache:r},kf(t),Dn(t,at,r)):((e.lanes&a)!==0&&(Mm(e,t),Gi(t,null,null,a),Vi()),r=e.memoizedState,s=t.memoizedState,r.parent!==n?(r={parent:n,cache:n},t.memoizedState=r,t.lanes===0&&(t.memoizedState=t.updateQueue.baseState=r),Dn(t,at,n)):(n=s.cache,Dn(t,at,n),n!==r.cache&&Tm(t,[at],a,!0))),pt(e,t,t.pendingProps.children,a),t.child;case 29:throw t.pendingProps}throw Error(P(156,t.tag))}function Za(e){e.flags|=4}function kg(e,t){if(t.type!=="stylesheet"||(t.state.loading&4)!==0)e.flags&=-16777217;else if(e.flags|=16777216,!k0(t)){if(t=fa.current,t!==null&&((de&4194048)===de?Ua!==null:(de&62914560)!==de&&(de&536870912)===0||t!==Ua))throw Hi=Dm,qy;e.flags|=8192}}function zl(e,t){t!==null&&(e.flags|=4),e.flags&16384&&(t=e.tag!==22?uy():536870912,e.lanes|=t,Ts|=t)}function Mi(e,t){if(!he)switch(e.tailMode){case"hidden":t=e.tail;for(var a=null;t!==null;)t.alternate!==null&&(a=t),t=t.sibling;a===null?e.tail=null:a.sibling=null;break;case"collapsed":a=e.tail;for(var n=null;a!==null;)a.alternate!==null&&(n=a),a=a.sibling;n===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:n.sibling=null}}function Fe(e){var t=e.alternate!==null&&e.alternate.child===e.child,a=0,n=0;if(t)for(var r=e.child;r!==null;)a|=r.lanes|r.childLanes,n|=r.subtreeFlags&65011712,n|=r.flags&65011712,r.return=e,r=r.sibling;else for(r=e.child;r!==null;)a|=r.lanes|r.childLanes,n|=r.subtreeFlags,n|=r.flags,r.return=e,r=r.sibling;return e.subtreeFlags|=n,e.childLanes=a,t}function WC(e,t,a){var n=t.pendingProps;switch(Sf(t),t.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Fe(t),null;case 1:return Fe(t),null;case 3:return a=t.stateNode,n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),ln(at),Ss(),a.pendingContext&&(a.context=a.pendingContext,a.pendingContext=null),(e===null||e.child===null)&&(Ai(t)?Za(t):e===null||e.memoizedState.isDehydrated&&(t.flags&256)===0||(t.flags|=1024,ag())),Fe(t),null;case 26:return a=t.memoizedState,e===null?(Za(t),a!==null?(Fe(t),kg(t,a)):(Fe(t),t.flags&=-16777217)):a?a!==e.memoizedState?(Za(t),Fe(t),kg(t,a)):(Fe(t),t.flags&=-16777217):(e.memoizedProps!==n&&Za(t),Fe(t),t.flags&=-16777217),null;case 27:ou(t),a=zn.current;var r=t.type;if(e!==null&&t.stateNode!=null)e.memoizedProps!==n&&Za(t);else{if(!n){if(t.stateNode===null)throw Error(P(166));return Fe(t),null}e=La.current,Ai(t)?eg(t,e):(e=S0(r,n,a),t.stateNode=e,Za(t))}return Fe(t),null;case 5:if(ou(t),a=t.type,e!==null&&t.stateNode!=null)e.memoizedProps!==n&&Za(t);else{if(!n){if(t.stateNode===null)throw Error(P(166));return Fe(t),null}if(e=La.current,Ai(t))eg(t,e);else{switch(r=Eu(zn.current),e){case 1:e=r.createElementNS("http://www.w3.org/2000/svg",a);break;case 2:e=r.createElementNS("http://www.w3.org/1998/Math/MathML",a);break;default:switch(a){case"svg":e=r.createElementNS("http://www.w3.org/2000/svg",a);break;case"math":e=r.createElementNS("http://www.w3.org/1998/Math/MathML",a);break;case"script":e=r.createElement("div"),e.innerHTML="