mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
[PRO-1078] fix problem saving + merge problems and submissions
This commit is contained in:
parent
dc21175300
commit
3a202eeb3d
@ -12,8 +12,9 @@ import { HistoryItem } from './HistoryItem';
|
||||
import { binDates } from './date-binning';
|
||||
import { useSearchFilter } from '~/lib/hooks/useSearchFilter';
|
||||
import { SaveProblem } from './SaveProblem';
|
||||
import { SaveReproductionModal } from './SaveReproduction';
|
||||
import { useAdminStatus } from '~/lib/stores/user';
|
||||
import { authStatusStore } from '../../lib/stores/auth';
|
||||
import { useStore } from '@nanostores/react';
|
||||
|
||||
const menuVariants = {
|
||||
closed: {
|
||||
@ -46,7 +47,7 @@ export const Menu = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [dialogContent, setDialogContent] = useState<DialogContent>(null);
|
||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
||||
const { isAdmin } = useAdminStatus();
|
||||
const isLoggedIn = useStore(authStatusStore.isLoggedIn);
|
||||
|
||||
const { filteredItems: filteredList, handleSearchChange } = useSearchFilter({
|
||||
items: list,
|
||||
@ -140,8 +141,7 @@ export const Menu = () => {
|
||||
>
|
||||
Problems
|
||||
</a>
|
||||
<SaveProblem />
|
||||
{isAdmin && <SaveReproductionModal />}
|
||||
{isLoggedIn && <SaveProblem />}
|
||||
<a
|
||||
href="/about"
|
||||
className="flex gap-2 bg-bolt-elements-sidebar-buttonBackgroundDefault text-bolt-elements-sidebar-buttonText hover:bg-bolt-elements-sidebar-buttonBackgroundHover rounded-md p-2 transition-theme"
|
||||
|
||||
@ -3,14 +3,102 @@ import ReactModal from 'react-modal';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { workbenchStore } from '~/lib/stores/workbench';
|
||||
import { submitProblem, BoltProblemStatus } from '~/lib/replay/Problems';
|
||||
import type { BoltProblemInput } from '~/lib/replay/Problems';
|
||||
import type { BoltProblemInput, BoltProblemSolution } from '~/lib/replay/Problems';
|
||||
import { shouldUseSupabase, getCurrentUser } from '~/lib/supabase/client';
|
||||
import { authModalStore } from '~/lib/stores/authModal';
|
||||
import { authStatusStore } from '~/lib/stores/auth';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import {
|
||||
getLastUserSimulationData,
|
||||
getLastSimulationChatMessages,
|
||||
isSimulatingOrHasFinished,
|
||||
getLastSimulationChatReferences,
|
||||
} from '~/lib/replay/SimulationPrompt';
|
||||
|
||||
ReactModal.setAppElement('#root');
|
||||
|
||||
// External functions for problem storage
|
||||
|
||||
async function saveProblem(
|
||||
title: string,
|
||||
description: string,
|
||||
username: string,
|
||||
reproData: any,
|
||||
): Promise<string | null> {
|
||||
if (!title) {
|
||||
toast.error('Please fill in title field');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!shouldUseSupabase() && !username) {
|
||||
toast.error('Please enter a username');
|
||||
return null;
|
||||
}
|
||||
|
||||
toast.info('Submitting problem...');
|
||||
|
||||
const repositoryId = workbenchStore.repositoryId.get();
|
||||
|
||||
if (!repositoryId) {
|
||||
toast.error('No repository ID found');
|
||||
return null;
|
||||
}
|
||||
|
||||
const solution: BoltProblemSolution = {
|
||||
evaluator: undefined,
|
||||
...reproData,
|
||||
};
|
||||
|
||||
const problem: BoltProblemInput = {
|
||||
version: 2,
|
||||
title,
|
||||
description,
|
||||
username: shouldUseSupabase() ? (undefined as any) : username,
|
||||
user_id: shouldUseSupabase() ? (await getCurrentUser())?.id || '' : undefined,
|
||||
repositoryId,
|
||||
status: BoltProblemStatus.Pending,
|
||||
solution,
|
||||
};
|
||||
|
||||
const problemId = await submitProblem(problem);
|
||||
|
||||
if (problemId) {
|
||||
localStorage.setItem('loadedProblemId', problemId);
|
||||
}
|
||||
|
||||
return problemId;
|
||||
}
|
||||
|
||||
function getReproductionData(): any | null {
|
||||
if (!isSimulatingOrHasFinished()) {
|
||||
toast.error('No simulation data found (neither in progress nor finished)');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const simulationData = getLastUserSimulationData();
|
||||
|
||||
if (!simulationData) {
|
||||
toast.error('No simulation data found');
|
||||
return null;
|
||||
}
|
||||
|
||||
const messages = getLastSimulationChatMessages();
|
||||
const references = getLastSimulationChatReferences();
|
||||
|
||||
if (!messages) {
|
||||
toast.error('No user prompt found');
|
||||
return null;
|
||||
}
|
||||
|
||||
return { simulationData, messages, references };
|
||||
} catch (error: any) {
|
||||
console.error('Error getting reproduction data', error?.stack || error);
|
||||
toast.error(`Error getting reproduction data: ${error?.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Component for saving the current chat as a new problem.
|
||||
|
||||
export function SaveProblem() {
|
||||
@ -21,6 +109,7 @@ export function SaveProblem() {
|
||||
username: '',
|
||||
});
|
||||
const [problemId, setProblemId] = useState<string | null>(null);
|
||||
const [reproData, setReproData] = useState<any>(null);
|
||||
const isLoggedIn = useStore(authStatusStore.isLoggedIn);
|
||||
const username = useStore(authStatusStore.username);
|
||||
|
||||
@ -34,6 +123,13 @@ export function SaveProblem() {
|
||||
const handleSaveProblem = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const currentReproData = getReproductionData();
|
||||
if (!currentReproData) {
|
||||
return;
|
||||
}
|
||||
|
||||
setReproData(currentReproData);
|
||||
setIsModalOpen(true);
|
||||
setProblemId(null);
|
||||
};
|
||||
@ -52,40 +148,13 @@ export function SaveProblem() {
|
||||
};
|
||||
|
||||
const handleSubmitProblem = async () => {
|
||||
if (!formData.title) {
|
||||
toast.error('Please fill in title field');
|
||||
if (!reproData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldUseSupabase() && !formData.username) {
|
||||
toast.error('Please enter a username');
|
||||
return;
|
||||
}
|
||||
|
||||
toast.info('Submitting problem...');
|
||||
|
||||
const repositoryId = workbenchStore.repositoryId.get();
|
||||
|
||||
if (!repositoryId) {
|
||||
toast.error('No repository ID found');
|
||||
return;
|
||||
}
|
||||
|
||||
const problem: BoltProblemInput = {
|
||||
version: 2,
|
||||
title: formData.title,
|
||||
description: formData.description,
|
||||
username: shouldUseSupabase() ? (undefined as any) : formData.username,
|
||||
user_id: shouldUseSupabase() ? (await getCurrentUser())?.id || '' : undefined,
|
||||
repositoryId,
|
||||
status: BoltProblemStatus.Pending,
|
||||
};
|
||||
|
||||
const problemId = await submitProblem(problem);
|
||||
|
||||
if (problemId) {
|
||||
setProblemId(problemId);
|
||||
localStorage.setItem('loadedProblemId', problemId);
|
||||
const newProblemId = await saveProblem(formData.title, formData.description, formData.username, reproData);
|
||||
if (newProblemId) {
|
||||
setProblemId(newProblemId);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,164 +0,0 @@
|
||||
import { toast } from 'react-toastify';
|
||||
import ReactModal from 'react-modal';
|
||||
import { useState } from 'react';
|
||||
import { updateProblem } from '~/lib/replay/Problems';
|
||||
import type { BoltProblem, BoltProblemInput, BoltProblemSolution } from '~/lib/replay/Problems';
|
||||
import { getOrFetchLastLoadedProblem } from '~/components/chat/LoadProblemButton';
|
||||
import {
|
||||
getLastUserSimulationData,
|
||||
getLastSimulationChatMessages,
|
||||
isSimulatingOrHasFinished,
|
||||
getLastSimulationChatReferences,
|
||||
} from '~/lib/replay/SimulationPrompt';
|
||||
|
||||
ReactModal.setAppElement('#root');
|
||||
|
||||
/*
|
||||
* Component for saving input simulation and prompt information for
|
||||
* the problem the current chat was loaded from.
|
||||
*/
|
||||
|
||||
export function SaveReproductionModal() {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [savedReproduction, setSavedReproduction] = useState<boolean>(false);
|
||||
const [problem, setProblem] = useState<BoltProblem | null>(null);
|
||||
|
||||
const handleSaveReproduction = async (e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
const loadId = toast.loading('Loading problem...');
|
||||
|
||||
try {
|
||||
const lastProblem = await getOrFetchLastLoadedProblem();
|
||||
|
||||
if (!lastProblem) {
|
||||
toast.error('No problem loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
setProblem(lastProblem);
|
||||
} finally {
|
||||
toast.dismiss(loadId);
|
||||
}
|
||||
setSavedReproduction(false);
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const handleSubmitReproduction = async () => {
|
||||
if (!problem) {
|
||||
toast.error('No problem loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSimulatingOrHasFinished()) {
|
||||
toast.error('No simulation data found (neither in progress nor finished)');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
toast.info('Submitting reproduction...');
|
||||
console.log('SubmitReproduction');
|
||||
|
||||
const simulationData = getLastUserSimulationData();
|
||||
|
||||
if (!simulationData) {
|
||||
toast.error('No simulation data found');
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = getLastSimulationChatMessages();
|
||||
const references = getLastSimulationChatReferences();
|
||||
|
||||
if (!messages) {
|
||||
toast.error('No user prompt found');
|
||||
return;
|
||||
}
|
||||
|
||||
const reproData = { simulationData, messages, references };
|
||||
|
||||
/**
|
||||
* TODO: Split `solution` into `reproData` and `evaluator`.
|
||||
*/
|
||||
const solution: BoltProblemSolution = {
|
||||
evaluator: problem.solution?.evaluator,
|
||||
...reproData,
|
||||
|
||||
/*
|
||||
* TODO: Also store recordingId for easier debugging.
|
||||
* recordingId,
|
||||
*/
|
||||
};
|
||||
|
||||
const problemUpdatePacket: BoltProblemInput = {
|
||||
...problem,
|
||||
version: 2,
|
||||
solution,
|
||||
};
|
||||
|
||||
await updateProblem(problem.problemId, problemUpdatePacket);
|
||||
|
||||
setSavedReproduction(true);
|
||||
} catch (error: any) {
|
||||
console.error('Error saving reproduction', error?.stack || error);
|
||||
toast.error(`Error saving reproduction: ${error?.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<a
|
||||
href="#"
|
||||
className="flex gap-2 bg-bolt-elements-sidebar-buttonBackgroundDefault text-bolt-elements-sidebar-buttonText hover:bg-bolt-elements-sidebar-buttonBackgroundHover rounded-md p-2 transition-theme"
|
||||
onClick={handleSaveReproduction}
|
||||
>
|
||||
Save Reproduction
|
||||
</a>
|
||||
<ReactModal
|
||||
isOpen={isModalOpen}
|
||||
onRequestClose={() => setIsModalOpen(false)}
|
||||
className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white rounded-lg p-6 max-w-2xl w-full z-50"
|
||||
overlayClassName="fixed inset-0 bg-black bg-opacity-50 z-40"
|
||||
>
|
||||
{savedReproduction && (
|
||||
<>
|
||||
<div className="text-center mb-2">Reproduction Saved</div>
|
||||
<div className="text-center">
|
||||
<div className="flex justify-center gap-2 mt-4">
|
||||
<button
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
className="px-4 py-2 bg-gray-300 rounded hover:bg-gray-400"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!savedReproduction && (
|
||||
<>
|
||||
<div className="text-center">
|
||||
Save reproduction data (prompt, user annotations + simulationData) for the currently loaded problem:{' '}
|
||||
{problem?.problemId}
|
||||
</div>
|
||||
<div style={{ marginTop: '10px' }}>
|
||||
<div className="flex justify-center gap-2 mt-4">
|
||||
<button
|
||||
onClick={handleSubmitReproduction}
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
className="px-4 py-2 bg-gray-300 rounded hover:bg-gray-400"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</ReactModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user