Refresh proposal & loaders for proposal action
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
|||||||
AlertOctagon,
|
AlertOctagon,
|
||||||
FileText,
|
FileText,
|
||||||
Check,
|
Check,
|
||||||
|
Loader2,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
@@ -31,6 +32,8 @@ interface ChatInputActionsProps {
|
|||||||
onApprove: () => void;
|
onApprove: () => void;
|
||||||
onReject: () => void;
|
onReject: () => void;
|
||||||
isApprovable: boolean; // Can be used to enable/disable buttons
|
isApprovable: boolean; // Can be used to enable/disable buttons
|
||||||
|
isApproving: boolean; // State for approving
|
||||||
|
isRejecting: boolean; // State for rejecting
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChatInputProps {
|
interface ChatInputProps {
|
||||||
@@ -46,12 +49,16 @@ export function ChatInput({ chatId, onSubmit }: ChatInputProps) {
|
|||||||
useStreamChat();
|
useStreamChat();
|
||||||
const [selectedAppId] = useAtom(selectedAppIdAtom);
|
const [selectedAppId] = useAtom(selectedAppIdAtom);
|
||||||
const [showError, setShowError] = useState(true);
|
const [showError, setShowError] = useState(true);
|
||||||
|
const [isApproving, setIsApproving] = useState(false); // State for approving
|
||||||
|
const [isRejecting, setIsRejecting] = useState(false); // State for rejecting
|
||||||
|
|
||||||
// Use the hook to fetch the proposal
|
// Use the hook to fetch the proposal
|
||||||
const {
|
const {
|
||||||
proposal,
|
proposal,
|
||||||
|
messageId,
|
||||||
isLoading: isProposalLoading,
|
isLoading: isProposalLoading,
|
||||||
error: proposalError,
|
error: proposalError,
|
||||||
|
refreshProposal,
|
||||||
} = useProposal(chatId);
|
} = useProposal(chatId);
|
||||||
|
|
||||||
const adjustHeight = () => {
|
const adjustHeight = () => {
|
||||||
@@ -102,14 +109,60 @@ export function ChatInput({ chatId, onSubmit }: ChatInputProps) {
|
|||||||
setShowError(false);
|
setShowError(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleApprove = () => {
|
const handleApprove = async () => {
|
||||||
console.log("Approve clicked");
|
if (!chatId || !messageId || isApproving || isRejecting || isStreaming)
|
||||||
// Add approve logic here
|
return;
|
||||||
|
console.log(
|
||||||
|
`Approving proposal for chatId: ${chatId}, messageId: ${messageId}`
|
||||||
|
);
|
||||||
|
setIsApproving(true);
|
||||||
|
try {
|
||||||
|
const result = await IpcClient.getInstance().approveProposal({
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
});
|
||||||
|
if (result.success) {
|
||||||
|
console.log("Proposal approved successfully");
|
||||||
|
// TODO: Maybe refresh proposal state or show confirmation?
|
||||||
|
} else {
|
||||||
|
console.error("Failed to approve proposal:", result.error);
|
||||||
|
setError(result.error || "Failed to approve proposal");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error approving proposal:", err);
|
||||||
|
setError((err as Error)?.message || "An error occurred while approving");
|
||||||
|
} finally {
|
||||||
|
setIsApproving(false);
|
||||||
|
refreshProposal();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReject = () => {
|
const handleReject = async () => {
|
||||||
console.log("Reject clicked");
|
if (!chatId || !messageId || isApproving || isRejecting || isStreaming)
|
||||||
// Add reject logic here
|
return;
|
||||||
|
console.log(
|
||||||
|
`Rejecting proposal for chatId: ${chatId}, messageId: ${messageId}`
|
||||||
|
);
|
||||||
|
setIsRejecting(true);
|
||||||
|
try {
|
||||||
|
const result = await IpcClient.getInstance().rejectProposal({
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
});
|
||||||
|
if (result.success) {
|
||||||
|
console.log("Proposal rejected successfully");
|
||||||
|
// TODO: Maybe refresh proposal state or show confirmation?
|
||||||
|
} else {
|
||||||
|
console.error("Failed to reject proposal:", result.error);
|
||||||
|
setError(result.error || "Failed to reject proposal");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error rejecting proposal:", err);
|
||||||
|
setError((err as Error)?.message || "An error occurred while rejecting");
|
||||||
|
} finally {
|
||||||
|
setIsRejecting(false);
|
||||||
|
refreshProposal();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!settings) {
|
if (!settings) {
|
||||||
@@ -150,7 +203,16 @@ export function ChatInput({ chatId, onSubmit }: ChatInputProps) {
|
|||||||
proposal={proposal}
|
proposal={proposal}
|
||||||
onApprove={handleApprove}
|
onApprove={handleApprove}
|
||||||
onReject={handleReject}
|
onReject={handleReject}
|
||||||
isApprovable={!isProposalLoading && !!proposal}
|
isApprovable={
|
||||||
|
!isProposalLoading &&
|
||||||
|
!!proposal &&
|
||||||
|
!!messageId &&
|
||||||
|
!isApproving &&
|
||||||
|
!isRejecting &&
|
||||||
|
!isStreaming
|
||||||
|
}
|
||||||
|
isApproving={isApproving}
|
||||||
|
isRejecting={isRejecting}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-start space-x-2 ">
|
<div className="flex items-start space-x-2 ">
|
||||||
@@ -202,6 +264,8 @@ function ChatInputActions({
|
|||||||
onApprove,
|
onApprove,
|
||||||
onReject,
|
onReject,
|
||||||
isApprovable,
|
isApprovable,
|
||||||
|
isApproving,
|
||||||
|
isRejecting,
|
||||||
}: ChatInputActionsProps) {
|
}: ChatInputActionsProps) {
|
||||||
const [autoApprove, setAutoApprove] = useState(false);
|
const [autoApprove, setAutoApprove] = useState(false);
|
||||||
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
||||||
@@ -236,9 +300,13 @@ function ChatInputActions({
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={onApprove}
|
onClick={onApprove}
|
||||||
disabled={!isApprovable}
|
disabled={!isApprovable || isApproving || isRejecting}
|
||||||
>
|
>
|
||||||
<Check size={16} className="mr-1" />
|
{isApproving ? (
|
||||||
|
<Loader2 size={16} className="mr-1 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Check size={16} className="mr-1" />
|
||||||
|
)}
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -246,9 +314,13 @@ function ChatInputActions({
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={onReject}
|
onClick={onReject}
|
||||||
disabled={!isApprovable}
|
disabled={!isApprovable || isApproving || isRejecting}
|
||||||
>
|
>
|
||||||
<X size={16} className="mr-1" />
|
{isRejecting ? (
|
||||||
|
<Loader2 size={16} className="mr-1 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<X size={16} className="mr-1" />
|
||||||
|
)}
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
<div className="flex items-center space-x-1 ml-auto">
|
<div className="flex items-center space-x-1 ml-auto">
|
||||||
|
|||||||
@@ -1,44 +1,73 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import type { Proposal } from "@/lib/schemas"; // Import Proposal type
|
import type { Proposal } from "@/lib/schemas"; // Import Proposal type
|
||||||
|
|
||||||
export function useProposal(chatId: number | undefined) {
|
// Define the structure returned by the IPC call
|
||||||
const [proposal, setProposal] = useState<Proposal | null>(null);
|
interface ProposalResult {
|
||||||
|
proposal: Proposal;
|
||||||
|
messageId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useProposal(chatId?: number | undefined) {
|
||||||
|
const [proposalData, setProposalData] = useState<ProposalResult | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
const fetchProposal = useCallback(
|
||||||
if (chatId === undefined) {
|
async (innerChatId?: number) => {
|
||||||
setProposal(null);
|
chatId = chatId ?? innerChatId;
|
||||||
setIsLoading(false);
|
if (chatId === undefined) {
|
||||||
setError(null);
|
setProposalData(null);
|
||||||
return;
|
setIsLoading(false);
|
||||||
}
|
setError(null);
|
||||||
|
return;
|
||||||
const fetchProposal = async () => {
|
}
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
setProposalData(null); // Reset on new fetch
|
||||||
try {
|
try {
|
||||||
const fetchedProposal = await IpcClient.getInstance().getProposal(
|
// Type assertion might be needed depending on how IpcClient is typed
|
||||||
|
const result = (await IpcClient.getInstance().getProposal(
|
||||||
chatId
|
chatId
|
||||||
);
|
)) as ProposalResult | null;
|
||||||
setProposal(fetchedProposal);
|
|
||||||
|
if (result) {
|
||||||
|
setProposalData(result);
|
||||||
|
} else {
|
||||||
|
setProposalData(null); // Explicitly set to null if IPC returns null
|
||||||
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("Error fetching proposal:", err);
|
console.error("Error fetching proposal:", err);
|
||||||
setError(err.message || "Failed to fetch proposal");
|
setError(err.message || "Failed to fetch proposal");
|
||||||
setProposal(null); // Clear proposal on error
|
setProposalData(null); // Clear proposal data on error
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
[chatId]
|
||||||
|
); // Depend on chatId
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
fetchProposal();
|
fetchProposal();
|
||||||
|
|
||||||
// Cleanup function if needed (e.g., for aborting requests)
|
// Cleanup function if needed (e.g., for aborting requests)
|
||||||
// return () => {
|
// return () => {
|
||||||
// // Abort logic here
|
// // Abort logic here
|
||||||
// };
|
// };
|
||||||
}, [chatId]); // Re-run effect if chatId changes
|
}, [fetchProposal]); // Re-run effect if fetchProposal changes (due to chatId change)
|
||||||
|
|
||||||
return { proposal, isLoading, error };
|
const refreshProposal = useCallback(
|
||||||
|
(chatId?: number) => {
|
||||||
|
fetchProposal(chatId);
|
||||||
|
},
|
||||||
|
[fetchProposal]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
proposal: proposalData?.proposal ?? null,
|
||||||
|
messageId: proposalData?.messageId,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
refreshProposal, // Expose the refresh function
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { useLoadApp } from "./useLoadApp";
|
|||||||
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
||||||
import { useLoadVersions } from "./useLoadVersions";
|
import { useLoadVersions } from "./useLoadVersions";
|
||||||
import { showError } from "@/lib/toast";
|
import { showError } from "@/lib/toast";
|
||||||
|
import { useProposal } from "./useProposal";
|
||||||
|
|
||||||
export function getRandomString() {
|
export function getRandomString() {
|
||||||
return Math.random().toString(36).substring(2, 15);
|
return Math.random().toString(36).substring(2, 15);
|
||||||
@@ -30,7 +31,7 @@ export function useStreamChat() {
|
|||||||
const { refreshApp } = useLoadApp(selectedAppId);
|
const { refreshApp } = useLoadApp(selectedAppId);
|
||||||
const setStreamCount = useSetAtom(chatStreamCountAtom);
|
const setStreamCount = useSetAtom(chatStreamCountAtom);
|
||||||
const { refreshVersions } = useLoadVersions(selectedAppId);
|
const { refreshVersions } = useLoadVersions(selectedAppId);
|
||||||
|
const { refreshProposal } = useProposal();
|
||||||
const streamMessage = useCallback(
|
const streamMessage = useCallback(
|
||||||
async ({
|
async ({
|
||||||
prompt,
|
prompt,
|
||||||
@@ -94,6 +95,7 @@ export function useStreamChat() {
|
|||||||
|
|
||||||
// Keep the same as below
|
// Keep the same as below
|
||||||
setIsStreaming(false);
|
setIsStreaming(false);
|
||||||
|
refreshProposal(chatId);
|
||||||
refreshChats();
|
refreshChats();
|
||||||
refreshApp();
|
refreshApp();
|
||||||
refreshVersions();
|
refreshVersions();
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import { ipcMain, type IpcMainInvokeEvent } from "electron";
|
|||||||
import type { Proposal } from "@/lib/schemas";
|
import type { Proposal } from "@/lib/schemas";
|
||||||
import { db } from "../../db";
|
import { db } from "../../db";
|
||||||
import { messages } from "../../db/schema";
|
import { messages } from "../../db/schema";
|
||||||
import { desc, eq, and } from "drizzle-orm";
|
import { desc, eq, and, Update } from "drizzle-orm";
|
||||||
import path from "node:path"; // Import path for basename
|
import path from "node:path"; // Import path for basename
|
||||||
// Import tag parsers
|
// Import tag parsers
|
||||||
import {
|
import {
|
||||||
getDyadChatSummaryTag,
|
getDyadChatSummaryTag,
|
||||||
getDyadWriteTags,
|
getDyadWriteTags,
|
||||||
|
processFullResponseActions,
|
||||||
} from "../processors/response_processor";
|
} from "../processors/response_processor";
|
||||||
|
|
||||||
// Placeholder Proposal data (can be removed or kept for reference)
|
// Placeholder Proposal data (can be removed or kept for reference)
|
||||||
@@ -19,6 +20,12 @@ interface ParsedProposal {
|
|||||||
files: string[];
|
files: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define return type for getProposalHandler
|
||||||
|
interface ProposalResult {
|
||||||
|
proposal: Proposal;
|
||||||
|
messageId: number;
|
||||||
|
}
|
||||||
|
|
||||||
function isParsedProposal(obj: any): obj is ParsedProposal {
|
function isParsedProposal(obj: any): obj is ParsedProposal {
|
||||||
return (
|
return (
|
||||||
obj &&
|
obj &&
|
||||||
@@ -32,7 +39,7 @@ function isParsedProposal(obj: any): obj is ParsedProposal {
|
|||||||
const getProposalHandler = async (
|
const getProposalHandler = async (
|
||||||
_event: IpcMainInvokeEvent,
|
_event: IpcMainInvokeEvent,
|
||||||
{ chatId }: { chatId: number }
|
{ chatId }: { chatId: number }
|
||||||
): Promise<Proposal | null> => {
|
): Promise<ProposalResult | null> => {
|
||||||
console.log(`IPC: get-proposal called for chatId: ${chatId}`);
|
console.log(`IPC: get-proposal called for chatId: ${chatId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -41,12 +48,16 @@ const getProposalHandler = async (
|
|||||||
where: and(eq(messages.chatId, chatId), eq(messages.role, "assistant")),
|
where: and(eq(messages.chatId, chatId), eq(messages.role, "assistant")),
|
||||||
orderBy: [desc(messages.createdAt)],
|
orderBy: [desc(messages.createdAt)],
|
||||||
columns: {
|
columns: {
|
||||||
|
id: true, // Fetch the ID
|
||||||
content: true, // Fetch the content to parse
|
content: true, // Fetch the content to parse
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (latestAssistantMessage?.content) {
|
if (latestAssistantMessage?.content && latestAssistantMessage.id) {
|
||||||
console.log("Found latest assistant message, parsing content...");
|
const messageId = latestAssistantMessage.id; // Get the message ID
|
||||||
|
console.log(
|
||||||
|
`Found latest assistant message (ID: ${messageId}), parsing content...`
|
||||||
|
);
|
||||||
const messageContent = latestAssistantMessage.content;
|
const messageContent = latestAssistantMessage.content;
|
||||||
|
|
||||||
// Parse tags directly from message content
|
// Parse tags directly from message content
|
||||||
@@ -66,7 +77,7 @@ const getProposalHandler = async (
|
|||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
console.log("Generated proposal on the fly:", proposal);
|
console.log("Generated proposal on the fly:", proposal);
|
||||||
return proposal;
|
return { proposal, messageId }; // Return proposal and messageId
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
"No relevant tags found in the latest assistant message content."
|
"No relevant tags found in the latest assistant message content."
|
||||||
@@ -83,8 +94,127 @@ const getProposalHandler = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handler to approve a proposal (process actions and update message)
|
||||||
|
const approveProposalHandler = async (
|
||||||
|
_event: IpcMainInvokeEvent,
|
||||||
|
{ chatId, messageId }: { chatId: number; messageId: number }
|
||||||
|
): Promise<{ success: boolean; error?: string }> => {
|
||||||
|
console.log(
|
||||||
|
`IPC: approve-proposal called for chatId: ${chatId}, messageId: ${messageId}`
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Fetch the specific assistant message
|
||||||
|
const messageToApprove = await db.query.messages.findFirst({
|
||||||
|
where: and(
|
||||||
|
eq(messages.id, messageId),
|
||||||
|
eq(messages.chatId, chatId),
|
||||||
|
eq(messages.role, "assistant")
|
||||||
|
),
|
||||||
|
columns: {
|
||||||
|
content: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!messageToApprove?.content) {
|
||||||
|
console.error(
|
||||||
|
`Assistant message not found for chatId: ${chatId}, messageId: ${messageId}`
|
||||||
|
);
|
||||||
|
return { success: false, error: "Assistant message not found." };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Process the actions defined in the message content
|
||||||
|
const chatSummary = getDyadChatSummaryTag(messageToApprove.content);
|
||||||
|
const processResult = await processFullResponseActions(
|
||||||
|
messageToApprove.content,
|
||||||
|
chatId,
|
||||||
|
{ chatSummary: chatSummary ?? undefined } // Pass summary if found
|
||||||
|
);
|
||||||
|
|
||||||
|
if (processResult.error) {
|
||||||
|
console.error(
|
||||||
|
`Error processing actions for message ${messageId}:`,
|
||||||
|
processResult.error
|
||||||
|
);
|
||||||
|
// Optionally: Update message state to 'error' or similar?
|
||||||
|
// For now, just return error to frontend
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `Action processing failed: ${processResult.error}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Update the message's approval state to 'approved'
|
||||||
|
await db
|
||||||
|
.update(messages)
|
||||||
|
.set({ approvalState: "approved" })
|
||||||
|
.where(eq(messages.id, messageId));
|
||||||
|
|
||||||
|
console.log(`Message ${messageId} marked as approved.`);
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Error approving proposal for messageId ${messageId}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: (error as Error)?.message || "Unknown error",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler to reject a proposal (just update message state)
|
||||||
|
const rejectProposalHandler = async (
|
||||||
|
_event: IpcMainInvokeEvent,
|
||||||
|
{ chatId, messageId }: { chatId: number; messageId: number }
|
||||||
|
): Promise<{ success: boolean; error?: string }> => {
|
||||||
|
console.log(
|
||||||
|
`IPC: reject-proposal called for chatId: ${chatId}, messageId: ${messageId}`
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Verify the message exists and is an assistant message
|
||||||
|
const messageToReject = await db.query.messages.findFirst({
|
||||||
|
where: and(
|
||||||
|
eq(messages.id, messageId),
|
||||||
|
eq(messages.chatId, chatId),
|
||||||
|
eq(messages.role, "assistant")
|
||||||
|
),
|
||||||
|
columns: { id: true }, // Only need to confirm existence
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!messageToReject) {
|
||||||
|
console.error(
|
||||||
|
`Assistant message not found for chatId: ${chatId}, messageId: ${messageId}`
|
||||||
|
);
|
||||||
|
return { success: false, error: "Assistant message not found." };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Update the message's approval state to 'rejected'
|
||||||
|
await db
|
||||||
|
.update(messages)
|
||||||
|
.set({ approvalState: "rejected" })
|
||||||
|
.where(eq(messages.id, messageId));
|
||||||
|
|
||||||
|
console.log(`Message ${messageId} marked as rejected.`);
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Error rejecting proposal for messageId ${messageId}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: (error as Error)?.message || "Unknown error",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Function to register proposal-related handlers
|
// Function to register proposal-related handlers
|
||||||
export function registerProposalHandlers() {
|
export function registerProposalHandlers() {
|
||||||
ipcMain.handle("get-proposal", getProposalHandler);
|
ipcMain.handle("get-proposal", getProposalHandler);
|
||||||
console.log("Registered proposal IPC handlers");
|
ipcMain.handle("approve-proposal", approveProposalHandler);
|
||||||
|
ipcMain.handle("reject-proposal", rejectProposalHandler);
|
||||||
|
console.log("Registered proposal IPC handlers (get, approve, reject)");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ import type {
|
|||||||
import type { Proposal } from "@/lib/schemas";
|
import type { Proposal } from "@/lib/schemas";
|
||||||
import { showError } from "@/lib/toast";
|
import { showError } from "@/lib/toast";
|
||||||
|
|
||||||
|
// Define the structure returned by getProposal
|
||||||
|
interface ProposalResult {
|
||||||
|
proposal: Proposal;
|
||||||
|
messageId: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ChatStreamCallbacks {
|
export interface ChatStreamCallbacks {
|
||||||
onUpdate: (messages: Message[]) => void;
|
onUpdate: (messages: Message[]) => void;
|
||||||
onEnd: (response: ChatResponseEnd) => void;
|
onEnd: (response: ChatResponseEnd) => void;
|
||||||
@@ -616,11 +622,12 @@ export class IpcClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get proposal details
|
// Get proposal details
|
||||||
public async getProposal(chatId: number): Promise<Proposal> {
|
public async getProposal(chatId: number): Promise<ProposalResult | null> {
|
||||||
try {
|
try {
|
||||||
const data = await this.ipcRenderer.invoke("get-proposal", { chatId });
|
const data = await this.ipcRenderer.invoke("get-proposal", { chatId });
|
||||||
// Assuming the main process returns data matching the Proposal interface
|
// Assuming the main process returns data matching the ProposalResult interface
|
||||||
return data as Proposal;
|
// Add a type check/guard if necessary for robustness
|
||||||
|
return data as ProposalResult | null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error);
|
showError(error);
|
||||||
throw error;
|
throw error;
|
||||||
@@ -629,4 +636,44 @@ export class IpcClient {
|
|||||||
|
|
||||||
// Example methods for listening to events (if needed)
|
// Example methods for listening to events (if needed)
|
||||||
// public on(channel: string, func: (...args: any[]) => void): void {
|
// public on(channel: string, func: (...args: any[]) => void): void {
|
||||||
|
|
||||||
|
// --- Proposal Management ---
|
||||||
|
public async approveProposal({
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
}: {
|
||||||
|
chatId: number;
|
||||||
|
messageId: number;
|
||||||
|
}): Promise<{ success: boolean; error?: string }> {
|
||||||
|
try {
|
||||||
|
const result = await this.ipcRenderer.invoke("approve-proposal", {
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
});
|
||||||
|
return result as { success: boolean; error?: string };
|
||||||
|
} catch (error) {
|
||||||
|
showError(error);
|
||||||
|
return { success: false, error: (error as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async rejectProposal({
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
}: {
|
||||||
|
chatId: number;
|
||||||
|
messageId: number;
|
||||||
|
}): Promise<{ success: boolean; error?: string }> {
|
||||||
|
try {
|
||||||
|
const result = await this.ipcRenderer.invoke("reject-proposal", {
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
});
|
||||||
|
return result as { success: boolean; error?: string };
|
||||||
|
} catch (error) {
|
||||||
|
showError(error);
|
||||||
|
return { success: false, error: (error as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --- End Proposal Management ---
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ const validInvokeChannels = [
|
|||||||
"get-app-version",
|
"get-app-version",
|
||||||
"reload-env-path",
|
"reload-env-path",
|
||||||
"get-proposal",
|
"get-proposal",
|
||||||
|
"approve-proposal",
|
||||||
|
"reject-proposal",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// Add valid receive channels
|
// Add valid receive channels
|
||||||
|
|||||||
Reference in New Issue
Block a user