diff --git a/surfsense_web/components/tool-ui/gmail/create-draft.tsx b/surfsense_web/components/tool-ui/gmail/create-draft.tsx
index 2f7b72009..7cd6a6c27 100644
--- a/surfsense_web/components/tool-ui/gmail/create-draft.tsx
+++ b/surfsense_web/components/tool-ui/gmail/create-draft.tsx
@@ -132,6 +132,9 @@ function ApprovalCard({
const wasAlreadyDecided = interruptData.__decided__ != null;
const [isPanelOpen, setIsPanelOpen] = useState(false);
const openHitlEditPanel = useSetAtom(openHitlEditPanelAtom);
+ const [pendingEdits, setPendingEdits] = useState<{
+ subject: string; body: string; to: string; cc: string; bcc: string;
+ } | null>(null);
const accounts = interruptData.context?.accounts ?? [];
const validAccounts = accounts.filter((a) => !a.auth_expired);
@@ -153,18 +156,26 @@ function ApprovalCard({
const handleApprove = useCallback(() => {
if (decided || isPanelOpen || !canApprove) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: {
...args,
+ ...(pendingEdits && {
+ subject: pendingEdits.subject,
+ body: pendingEdits.body,
+ to: pendingEdits.to,
+ cc: pendingEdits.cc,
+ bcc: pendingEdits.bcc,
+ }),
connector_id: selectedAccountId ? Number(selectedAccountId) : null,
},
},
});
- }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedAccountId]);
+ }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedAccountId, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -214,33 +225,24 @@ function ApprovalCard({
onClick={() => {
setIsPanelOpen(true);
const extraFields: ExtraField[] = [
- { key: "to", label: "To", type: "email", value: args.to || "" },
- { key: "cc", label: "CC", type: "email", value: args.cc || "" },
- { key: "bcc", label: "BCC", type: "email", value: args.bcc || "" },
+ { key: "to", label: "To", type: "email", value: pendingEdits?.to ?? args.to ?? "" },
+ { key: "cc", label: "CC", type: "email", value: pendingEdits?.cc ?? args.cc ?? "" },
+ { key: "bcc", label: "BCC", type: "email", value: pendingEdits?.bcc ?? args.bcc ?? "" },
];
openHitlEditPanel({
- title: args.subject ?? "",
- content: args.body ?? "",
+ title: pendingEdits?.subject ?? (args.subject ?? ""),
+ content: pendingEdits?.body ?? (args.body ?? ""),
toolName: "Gmail Draft",
extraFields,
onSave: (newTitle, newContent, extraFieldValues) => {
setIsPanelOpen(false);
- setDecided("edit");
const extras = extraFieldValues ?? {};
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: {
- ...args,
- subject: newTitle,
- body: newContent,
- to: extras.to ?? args.to,
- cc: extras.cc ?? args.cc,
- bcc: extras.bcc ?? args.bcc,
- connector_id: selectedAccountId ? Number(selectedAccountId) : null,
- },
- },
+ setPendingEdits({
+ subject: newTitle,
+ body: newContent,
+ to: extras.to ?? pendingEdits?.to ?? args.to ?? "",
+ cc: extras.cc ?? pendingEdits?.cc ?? args.cc ?? "",
+ bcc: extras.bcc ?? pendingEdits?.bcc ?? args.bcc ?? "",
});
},
});
@@ -297,31 +299,31 @@ function ApprovalCard({
{/* Email headers + body preview */}
- {args.to && (
+ {(pendingEdits?.to ?? args.to) && (
- To: {args.to}
+ To: {pendingEdits?.to ?? args.to}
)}
- {args.cc && args.cc.trim() !== "" && (
+ {(pendingEdits?.cc ?? args.cc) && (pendingEdits?.cc ?? args.cc)?.trim() !== "" && (
- CC: {args.cc}
+ CC: {pendingEdits?.cc ?? args.cc}
)}
- {args.bcc && args.bcc.trim() !== "" && (
+ {(pendingEdits?.bcc ?? args.bcc) && (pendingEdits?.bcc ?? args.bcc)?.trim() !== "" && (
- BCC: {args.bcc}
+ BCC: {pendingEdits?.bcc ?? args.bcc}
)}
- {args.subject != null && (
-
{args.subject}
+ {(pendingEdits?.subject ?? args.subject) != null && (
+
{pendingEdits?.subject ?? args.subject}
)}
- {args.body != null && (
+ {(pendingEdits?.body ?? args.body) != null && (
(null);
const accounts = interruptData.context?.accounts ?? [];
const validAccounts = accounts.filter((a) => !a.auth_expired);
@@ -154,18 +157,26 @@ function ApprovalCard({
const handleApprove = useCallback(() => {
if (decided || isPanelOpen || !canApprove) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: {
...args,
+ ...(pendingEdits && {
+ subject: pendingEdits.subject,
+ body: pendingEdits.body,
+ to: pendingEdits.to,
+ cc: pendingEdits.cc,
+ bcc: pendingEdits.bcc,
+ }),
connector_id: selectedAccountId ? Number(selectedAccountId) : null,
},
},
});
- }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedAccountId]);
+ }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedAccountId, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -216,33 +227,24 @@ function ApprovalCard({
onClick={() => {
setIsPanelOpen(true);
const extraFields: ExtraField[] = [
- { key: "to", label: "To", type: "email", value: args.to || "" },
- { key: "cc", label: "CC", type: "email", value: args.cc || "" },
- { key: "bcc", label: "BCC", type: "email", value: args.bcc || "" },
+ { key: "to", label: "To", type: "email", value: pendingEdits?.to ?? args.to ?? "" },
+ { key: "cc", label: "CC", type: "email", value: pendingEdits?.cc ?? args.cc ?? "" },
+ { key: "bcc", label: "BCC", type: "email", value: pendingEdits?.bcc ?? args.bcc ?? "" },
];
openHitlEditPanel({
- title: args.subject ?? "",
- content: args.body ?? "",
+ title: pendingEdits?.subject ?? (args.subject ?? ""),
+ content: pendingEdits?.body ?? (args.body ?? ""),
toolName: "Send Email",
extraFields,
onSave: (newTitle, newContent, extraFieldValues) => {
setIsPanelOpen(false);
- setDecided("edit");
const extras = extraFieldValues ?? {};
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: {
- ...args,
- subject: newTitle,
- body: newContent,
- to: extras.to ?? args.to,
- cc: extras.cc ?? args.cc,
- bcc: extras.bcc ?? args.bcc,
- connector_id: selectedAccountId ? Number(selectedAccountId) : null,
- },
- },
+ setPendingEdits({
+ subject: newTitle,
+ body: newContent,
+ to: extras.to ?? pendingEdits?.to ?? args.to ?? "",
+ cc: extras.cc ?? pendingEdits?.cc ?? args.cc ?? "",
+ bcc: extras.bcc ?? pendingEdits?.bcc ?? args.bcc ?? "",
});
},
});
@@ -299,31 +301,31 @@ function ApprovalCard({
{/* Email headers + body preview */}
- {args.to && (
+ {(pendingEdits?.to ?? args.to) && (
- To: {args.to}
+ To: {pendingEdits?.to ?? args.to}
)}
- {args.cc && args.cc.trim() !== "" && (
+ {(pendingEdits?.cc ?? args.cc) && (pendingEdits?.cc ?? args.cc)!.trim() !== "" && (
- CC: {args.cc}
+ CC: {pendingEdits?.cc ?? args.cc}
)}
- {args.bcc && args.bcc.trim() !== "" && (
+ {(pendingEdits?.bcc ?? args.bcc) && (pendingEdits?.bcc ?? args.bcc)!.trim() !== "" && (
- BCC: {args.bcc}
+ BCC: {pendingEdits?.bcc ?? args.bcc}
)}
- {args.subject != null && (
-
{args.subject}
+ {(pendingEdits?.subject ?? args.subject) != null && (
+
{pendingEdits?.subject ?? args.subject}
)}
- {args.body != null && (
+ {(pendingEdits?.body ?? args.body) != null && (
(null);
const accounts = interruptData.context?.accounts ?? [];
const validAccounts = accounts.filter((a) => !a.auth_expired);
@@ -189,24 +193,42 @@ function ApprovalCard({
const canApprove =
!!selectedAccountId &&
!!selectedCalendarId &&
- !!args.summary?.trim();
+ !!(pendingEdits?.summary ?? args.summary)?.trim();
const handleApprove = useCallback(() => {
if (decided || isPanelOpen || !canApprove) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
+
+ const finalArgs: Record = {
+ ...args,
+ connector_id: selectedAccountId ? Number(selectedAccountId) : null,
+ calendar_id: selectedCalendarId || null,
+ };
+
+ if (pendingEdits) {
+ finalArgs.summary = pendingEdits.summary;
+ finalArgs.description = pendingEdits.description;
+ if (pendingEdits.start_datetime) finalArgs.start_datetime = pendingEdits.start_datetime;
+ if (pendingEdits.end_datetime) finalArgs.end_datetime = pendingEdits.end_datetime;
+ if (pendingEdits.location !== undefined) finalArgs.location = pendingEdits.location;
+ if (pendingEdits.attendees !== undefined) {
+ finalArgs.attendees = pendingEdits.attendees
+ .split(",")
+ .map((e) => e.trim())
+ .filter(Boolean);
+ }
+ }
+
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
- args: {
- ...args,
- connector_id: selectedAccountId ? Number(selectedAccountId) : null,
- calendar_id: selectedCalendarId || null,
- },
+ args: finalArgs,
},
});
- }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedAccountId, selectedCalendarId]);
+ }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedAccountId, selectedCalendarId, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -219,6 +241,9 @@ function ApprovalCard({
}, [handleApprove]);
const attendeesList = (args.attendees as string[]) ?? [];
+ const displayAttendees = pendingEdits?.attendees
+ ? pendingEdits.attendees.split(",").map((e) => e.trim()).filter(Boolean)
+ : attendeesList;
return (
@@ -259,46 +284,26 @@ function ApprovalCard({
onClick={() => {
setIsPanelOpen(true);
const extraFields: ExtraField[] = [
- { key: "start_datetime", label: "Start", type: "datetime-local", value: args.start_datetime || "" },
- { key: "end_datetime", label: "End", type: "datetime-local", value: args.end_datetime || "" },
- { key: "location", label: "Location", type: "text", value: args.location || "" },
- { key: "attendees", label: "Attendees (comma-separated emails)", type: "text", value: attendeesList.join(", ") },
+ { key: "start_datetime", label: "Start", type: "datetime-local", value: pendingEdits?.start_datetime ?? args.start_datetime ?? "" },
+ { key: "end_datetime", label: "End", type: "datetime-local", value: pendingEdits?.end_datetime ?? args.end_datetime ?? "" },
+ { key: "location", label: "Location", type: "text", value: pendingEdits?.location ?? args.location ?? "" },
+ { key: "attendees", label: "Attendees (comma-separated emails)", type: "text", value: pendingEdits?.attendees ?? attendeesList.join(", ") },
];
openHitlEditPanel({
- title: args.summary ?? "",
- content: args.description ?? "",
+ title: pendingEdits?.summary ?? (args.summary ?? ""),
+ content: pendingEdits?.description ?? (args.description ?? ""),
toolName: "Calendar Event",
extraFields,
onSave: (newTitle, newContent, extraFieldValues) => {
setIsPanelOpen(false);
- setDecided("edit");
-
- const editedArgs: Record
= {
- ...args,
+ const extras = extraFieldValues ?? {};
+ setPendingEdits({
summary: newTitle,
description: newContent,
- connector_id: selectedAccountId ? Number(selectedAccountId) : null,
- calendar_id: selectedCalendarId || null,
- };
-
- if (extraFieldValues) {
- if (extraFieldValues.start_datetime) editedArgs.start_datetime = extraFieldValues.start_datetime;
- if (extraFieldValues.end_datetime) editedArgs.end_datetime = extraFieldValues.end_datetime;
- if (extraFieldValues.location !== undefined) editedArgs.location = extraFieldValues.location;
- if (extraFieldValues.attendees !== undefined) {
- editedArgs.attendees = extraFieldValues.attendees
- .split(",")
- .map((e) => e.trim())
- .filter(Boolean);
- }
- }
-
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: editedArgs,
- },
+ start_datetime: extras.start_datetime ?? pendingEdits?.start_datetime ?? args.start_datetime ?? "",
+ end_datetime: extras.end_datetime ?? pendingEdits?.end_datetime ?? args.end_datetime ?? "",
+ location: extras.location ?? pendingEdits?.location ?? args.location ?? "",
+ attendees: extras.attendees ?? pendingEdits?.attendees ?? attendeesList.join(", "),
});
},
});
@@ -385,36 +390,36 @@ function ApprovalCard({
{/* Content preview */}
- {args.summary && (
-
{args.summary}
+ {(pendingEdits?.summary ?? args.summary) && (
+
{pendingEdits?.summary ?? args.summary}
)}
- {(args.start_datetime || args.end_datetime) && (
+ {((pendingEdits?.start_datetime ?? args.start_datetime) || (pendingEdits?.end_datetime ?? args.end_datetime)) && (
- {args.start_datetime ? formatDateTime(args.start_datetime) : ""}
- {args.start_datetime && args.end_datetime ? " — " : ""}
- {args.end_datetime ? formatDateTime(args.end_datetime) : ""}
+ {(pendingEdits?.start_datetime ?? args.start_datetime) ? formatDateTime(pendingEdits?.start_datetime ?? args.start_datetime) : ""}
+ {(pendingEdits?.start_datetime ?? args.start_datetime) && (pendingEdits?.end_datetime ?? args.end_datetime) ? " — " : ""}
+ {(pendingEdits?.end_datetime ?? args.end_datetime) ? formatDateTime(pendingEdits?.end_datetime ?? args.end_datetime) : ""}
)}
- {args.location && (
+ {(pendingEdits?.location ?? args.location) && (
- {args.location}
+ {pendingEdits?.location ?? args.location}
)}
- {attendeesList.length > 0 && (
+ {displayAttendees.length > 0 && (
- {attendeesList.join(", ")}
+ {displayAttendees.join(", ")}
)}
- {args.description && (
+ {(pendingEdits?.description ?? args.description) && (
(null);
const reviewConfig = interruptData.review_configs[0];
const allowedDecisions = reviewConfig?.allowed_decisions ?? ["approve", "reject"];
@@ -216,6 +220,22 @@ function ApprovalCard({
String(actionArgs.new_description ?? "") !== (event?.description ?? "");
const buildFinalArgs = useCallback(() => {
+ if (pendingEdits) {
+ const attendeesArr = pendingEdits.attendees
+ ? pendingEdits.attendees.split(",").map((e) => e.trim()).filter(Boolean)
+ : null;
+ return {
+ event_id: event?.event_id,
+ document_id: event?.document_id,
+ connector_id: account?.id,
+ new_summary: pendingEdits.summary || null,
+ new_description: pendingEdits.description || null,
+ new_start_datetime: pendingEdits.start_datetime || null,
+ new_end_datetime: pendingEdits.end_datetime || null,
+ new_location: pendingEdits.location || null,
+ new_attendees: attendeesArr,
+ };
+ }
return {
event_id: event?.event_id,
document_id: event?.document_id,
@@ -227,20 +247,21 @@ function ApprovalCard({
new_location: actionArgs.new_location ?? null,
new_attendees: proposedAttendees ?? null,
};
- }, [event, account, actionArgs, proposedAttendees]);
+ }, [event, account, actionArgs, proposedAttendees, pendingEdits]);
const handleApprove = useCallback(() => {
if (decided || isPanelOpen) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: buildFinalArgs(),
},
});
- }, [decided, isPanelOpen, allowedDecisions, onDecision, interruptData, buildFinalArgs]);
+ }, [decided, isPanelOpen, allowedDecisions, onDecision, interruptData, buildFinalArgs, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -290,24 +311,18 @@ function ApprovalCard({
className="rounded-lg text-muted-foreground -mt-1 -mr-2"
onClick={() => {
setIsPanelOpen(true);
- const proposedSummary = actionArgs.new_summary
- ? String(actionArgs.new_summary)
- : (event?.summary ?? "");
- const proposedDescription = actionArgs.new_description
- ? String(actionArgs.new_description)
- : (event?.description ?? "");
- const proposedStart = actionArgs.new_start_datetime
- ? String(actionArgs.new_start_datetime)
- : (event?.start ?? "");
- const proposedEnd = actionArgs.new_end_datetime
- ? String(actionArgs.new_end_datetime)
- : (event?.end ?? "");
- const proposedLocation = actionArgs.new_location !== undefined
- ? String(actionArgs.new_location ?? "")
- : (event?.location ?? "");
- const proposedAttendeesStr = proposedAttendees
- ? proposedAttendees.join(", ")
- : currentAttendees.join(", ");
+ const proposedSummary = pendingEdits?.summary
+ ?? (actionArgs.new_summary ? String(actionArgs.new_summary) : (event?.summary ?? ""));
+ const proposedDescription = pendingEdits?.description
+ ?? (actionArgs.new_description ? String(actionArgs.new_description) : (event?.description ?? ""));
+ const proposedStart = pendingEdits?.start_datetime
+ ?? (actionArgs.new_start_datetime ? String(actionArgs.new_start_datetime) : (event?.start ?? ""));
+ const proposedEnd = pendingEdits?.end_datetime
+ ?? (actionArgs.new_end_datetime ? String(actionArgs.new_end_datetime) : (event?.end ?? ""));
+ const proposedLocation = pendingEdits?.location
+ ?? (actionArgs.new_location !== undefined ? String(actionArgs.new_location ?? "") : (event?.location ?? ""));
+ const proposedAttendeesStr = pendingEdits?.attendees
+ ?? (proposedAttendees ? proposedAttendees.join(", ") : currentAttendees.join(", "));
const extraFields: ExtraField[] = [
{ key: "start_datetime", label: "Start", type: "datetime-local", value: proposedStart },
@@ -322,34 +337,14 @@ function ApprovalCard({
extraFields,
onSave: (newTitle, newContent, extraFieldValues) => {
setIsPanelOpen(false);
- setDecided("edit");
-
- const editedArgs: Record = {
- event_id: event?.event_id,
- document_id: event?.document_id,
- connector_id: account?.id,
- new_summary: newTitle || null,
- new_description: newContent || null,
- };
-
- if (extraFieldValues) {
- editedArgs.new_start_datetime = extraFieldValues.start_datetime || null;
- editedArgs.new_end_datetime = extraFieldValues.end_datetime || null;
- editedArgs.new_location = extraFieldValues.location || null;
- if (extraFieldValues.attendees !== undefined) {
- editedArgs.new_attendees = extraFieldValues.attendees
- .split(",")
- .map((e) => e.trim())
- .filter(Boolean);
- }
- }
-
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: editedArgs,
- },
+ const extras = extraFieldValues ?? {};
+ setPendingEdits({
+ summary: newTitle,
+ description: newContent,
+ start_datetime: extras.start_datetime ?? proposedStart,
+ end_datetime: extras.end_datetime ?? proposedEnd,
+ location: extras.location ?? proposedLocation,
+ attendees: extras.attendees ?? proposedAttendeesStr,
});
},
});
diff --git a/surfsense_web/components/tool-ui/google-drive/create-file.tsx b/surfsense_web/components/tool-ui/google-drive/create-file.tsx
index cca93ce17..e0a92b984 100644
--- a/surfsense_web/components/tool-ui/google-drive/create-file.tsx
+++ b/surfsense_web/components/tool-ui/google-drive/create-file.tsx
@@ -137,6 +137,7 @@ function ApprovalCard({
const wasAlreadyDecided = interruptData.__decided__ != null;
const [isPanelOpen, setIsPanelOpen] = useState(false);
const openHitlEditPanel = useSetAtom(openHitlEditPanelAtom);
+ const [pendingEdits, setPendingEdits] = useState<{ name: string; content: string } | null>(null);
const accounts = interruptData.context?.accounts ?? [];
const validAccounts = accounts.filter(a => !a.auth_expired);
@@ -164,10 +165,10 @@ function ApprovalCard({
const fileTypeLabel = FILE_TYPE_LABELS[selectedFileType] ?? FILE_TYPE_LABELS[args.file_type] ?? "Google Drive File";
- const isNameValid = useMemo(
- () => args.name && typeof args.name === "string" && args.name.trim().length > 0,
- [args.name]
- );
+ const isNameValid = useMemo(() => {
+ const name = pendingEdits?.name ?? args.name;
+ return name && typeof name === "string" && name.trim().length > 0;
+ }, [pendingEdits?.name, args.name]);
const canApprove = !!selectedAccountId && isNameValid;
@@ -178,20 +179,22 @@ function ApprovalCard({
const handleApprove = useCallback(() => {
if (decided || isPanelOpen || !canApprove) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: {
...args,
+ ...(pendingEdits && { name: pendingEdits.name, content: pendingEdits.content }),
file_type: selectedFileType,
connector_id: selectedAccountId ? Number(selectedAccountId) : null,
parent_folder_id: parentFolderId === "__root__" ? null : parentFolderId,
},
},
});
- }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedFileType, selectedAccountId, parentFolderId]);
+ }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, args, selectedFileType, selectedAccountId, parentFolderId, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -239,27 +242,13 @@ function ApprovalCard({
onClick={() => {
setIsPanelOpen(true);
openHitlEditPanel({
- title: args.name ?? "",
- content: args.content ?? "",
+ title: pendingEdits?.name ?? (args.name ?? ""),
+ content: pendingEdits?.content ?? (args.content ?? ""),
toolName: fileTypeLabel,
- onSave: (newName, newContent) => {
- setIsPanelOpen(false);
- setDecided("edit");
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: {
- ...args,
- name: newName,
- content: newContent,
- file_type: selectedFileType,
- connector_id: selectedAccountId ? Number(selectedAccountId) : null,
- parent_folder_id: parentFolderId === "__root__" ? null : parentFolderId,
- },
- },
- });
- },
+ onSave: (newName, newContent) => {
+ setIsPanelOpen(false);
+ setPendingEdits({ name: newName, content: newContent });
+ },
});
}}
>
@@ -355,10 +344,10 @@ function ApprovalCard({
{/* Content preview */}
- {args.name != null && (
-
{args.name}
+ {(pendingEdits?.name ?? args.name) != null && (
+
{String(pendingEdits?.name ?? args.name)}
)}
- {args.content != null && (
+ {(pendingEdits?.content ?? args.content) != null && (
(null);
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState("");
const [selectedTeamId, setSelectedTeamId] = useState("");
@@ -171,7 +172,7 @@ function ApprovalCard({
[selectedWorkspace, selectedTeamId]
);
- const isTitleValid = (args.title ?? "").trim().length > 0;
+ const isTitleValid = (pendingEdits?.title ?? args.title ?? "").trim().length > 0;
const canApprove = !!selectedWorkspaceId && !!selectedTeamId && isTitleValid;
const reviewConfig = interruptData.review_configs[0];
@@ -180,8 +181,8 @@ function ApprovalCard({
const buildFinalArgs = useCallback((overrides?: { title?: string; description?: string }) => {
return {
- title: overrides?.title ?? args.title,
- description: overrides?.description ?? args.description ?? null,
+ title: overrides?.title ?? pendingEdits?.title ?? args.title,
+ description: overrides?.description ?? pendingEdits?.description ?? args.description ?? null,
connector_id: selectedWorkspaceId ? Number(selectedWorkspaceId) : null,
team_id: selectedTeamId || null,
state_id: selectedStateId === "__none__" ? null : selectedStateId,
@@ -189,20 +190,21 @@ function ApprovalCard({
priority: Number(selectedPriority),
label_ids: selectedLabelIds,
};
- }, [args.title, args.description, selectedWorkspaceId, selectedTeamId, selectedStateId, selectedAssigneeId, selectedPriority, selectedLabelIds]);
+ }, [args.title, args.description, selectedWorkspaceId, selectedTeamId, selectedStateId, selectedAssigneeId, selectedPriority, selectedLabelIds, pendingEdits]);
const handleApprove = useCallback(() => {
if (decided || isPanelOpen || !canApprove) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: buildFinalArgs(),
},
});
- }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, buildFinalArgs]);
+ }, [decided, isPanelOpen, canApprove, allowedDecisions, onDecision, interruptData, buildFinalArgs, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -250,19 +252,12 @@ function ApprovalCard({
onClick={() => {
setIsPanelOpen(true);
openHitlEditPanel({
- title: args.title ?? "",
- content: args.description ?? "",
+ title: pendingEdits?.title ?? (args.title ?? ""),
+ content: pendingEdits?.description ?? (args.description ?? ""),
toolName: "Linear Issue",
onSave: (newTitle, newDescription) => {
setIsPanelOpen(false);
- setDecided("edit");
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: buildFinalArgs({ title: newTitle, description: newDescription }),
- },
- });
+ setPendingEdits({ title: newTitle, description: newDescription });
},
});
}}
@@ -461,10 +456,10 @@ function ApprovalCard({
{/* Content preview */}
- {args.title != null && (
-
{args.title}
+ {(pendingEdits?.title ?? args.title) != null && (
+
{pendingEdits?.title ?? args.title}
)}
- {args.description != null && (
+ {(pendingEdits?.description ?? args.description) != null && (
{
if (decided || isPanelOpen) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = hasPanelEdits;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: buildFinalArgs(),
},
});
- }, [decided, isPanelOpen, allowedDecisions, onDecision, interruptData, buildFinalArgs]);
+ }, [decided, isPanelOpen, allowedDecisions, onDecision, interruptData, buildFinalArgs, hasPanelEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -321,18 +323,7 @@ function ApprovalCard({
title: newTitle,
description: newDescription,
}));
- setDecided("edit");
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: {
- ...buildFinalArgs(),
- new_title: newTitle || null,
- new_description: newDescription || null,
- },
- },
- });
+ setHasPanelEdits(true);
},
});
}}
@@ -536,12 +527,12 @@ function ApprovalCard({
{/* Content preview — proposed changes */}
- {hasProposedChanges ? (
+ {(hasProposedChanges || hasPanelEdits) ? (
<>
- {actionArgs.new_title && (
-
{String(actionArgs.new_title)}
+ {(hasPanelEdits ? editedArgs.title : actionArgs.new_title) && (
+
{String(hasPanelEdits ? editedArgs.title : actionArgs.new_title)}
)}
- {actionArgs.new_description && (
+ {(hasPanelEdits ? editedArgs.description : actionArgs.new_description) && (
(null);
const accounts = interruptData.context?.accounts ?? [];
const validAccounts = accounts.filter(a => !a.auth_expired);
@@ -144,8 +145,9 @@ function ApprovalCard({
}, [selectedAccountId, parentPages]);
const isTitleValid = useMemo(() => {
- return args.title && typeof args.title === "string" && (args.title as string).trim().length > 0;
- }, [args.title]);
+ const title = pendingEdits?.title ?? args.title;
+ return title && typeof title === "string" && title.trim().length > 0;
+ }, [pendingEdits?.title, args.title]);
const reviewConfig = interruptData.review_configs[0];
const allowedDecisions = reviewConfig?.allowed_decisions ?? ["approve", "reject"];
@@ -154,20 +156,22 @@ function ApprovalCard({
const handleApprove = useCallback(() => {
if (decided || isPanelOpen || !selectedAccountId || !isTitleValid) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: {
...args,
+ ...(pendingEdits && { title: pendingEdits.title, content: pendingEdits.content }),
connector_id: selectedAccountId ? Number(selectedAccountId) : null,
parent_page_id:
selectedParentPageId === "__none__" ? null : selectedParentPageId,
},
},
});
- }, [decided, isPanelOpen, selectedAccountId, isTitleValid, allowedDecisions, onDecision, interruptData, args, selectedParentPageId]);
+ }, [decided, isPanelOpen, selectedAccountId, isTitleValid, allowedDecisions, onDecision, interruptData, args, selectedParentPageId, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -217,26 +221,12 @@ function ApprovalCard({
onClick={() => {
setIsPanelOpen(true);
openHitlEditPanel({
- title: String(args.title ?? ""),
- content: String(args.content ?? ""),
+ title: pendingEdits?.title ?? String(args.title ?? ""),
+ content: pendingEdits?.content ?? String(args.content ?? ""),
toolName: "Notion Page",
onSave: (newTitle, newContent) => {
setIsPanelOpen(false);
- setDecided("edit");
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: {
- ...args,
- title: newTitle,
- content: newContent,
- connector_id: selectedAccountId ? Number(selectedAccountId) : null,
- parent_page_id:
- selectedParentPageId === "__none__" ? null : selectedParentPageId,
- },
- },
- });
+ setPendingEdits({ title: newTitle, content: newContent });
},
});
}}
@@ -324,10 +314,10 @@ function ApprovalCard({
{/* Content preview */}
- {args.title != null && (
-
{String(args.title)}
+ {(pendingEdits?.title ?? args.title) != null && (
+
{String(pendingEdits?.title ?? args.title)}
)}
- {args.content != null && (
+ {(pendingEdits?.content ?? args.content) != null && (
(null);
const account = interruptData.context?.account;
const currentTitle = interruptData.context?.current_title;
@@ -134,19 +135,20 @@ function ApprovalCard({
const handleApprove = useCallback(() => {
if (decided || isPanelOpen) return;
if (!allowedDecisions.includes("approve")) return;
- setDecided("approve");
+ const isEdited = pendingEdits !== null;
+ setDecided(isEdited ? "edit" : "approve");
onDecision({
- type: "approve",
+ type: isEdited ? "edit" : "approve",
edited_action: {
name: interruptData.action_requests[0].name,
args: {
page_id: args.page_id,
- content: args.content,
+ content: pendingEdits?.content ?? args.content,
connector_id: account?.id,
},
},
});
- }, [decided, isPanelOpen, allowedDecisions, onDecision, interruptData, args, account?.id]);
+ }, [decided, isPanelOpen, allowedDecisions, onDecision, interruptData, args, account?.id, pendingEdits]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
@@ -195,22 +197,11 @@ function ApprovalCard({
setIsPanelOpen(true);
openHitlEditPanel({
title: currentTitle ?? "",
- content: String(args.content ?? ""),
+ content: pendingEdits?.content ?? String(args.content ?? ""),
toolName: "Notion Page",
onSave: (_, newContent) => {
setIsPanelOpen(false);
- setDecided("edit");
- onDecision({
- type: "edit",
- edited_action: {
- name: interruptData.action_requests[0].name,
- args: {
- page_id: args.page_id,
- content: newContent,
- connector_id: account?.id,
- },
- },
- });
+ setPendingEdits({ content: newContent });
},
});
}}
@@ -256,7 +247,7 @@ function ApprovalCard({
{/* Content preview */}
- {args.content != null ? (
+ {(pendingEdits?.content ?? args.content) != null ? (