diff --git a/app/components/sidebar/Menu.client.tsx b/app/components/sidebar/Menu.client.tsx index d2eff5d6..67262264 100644 --- a/app/components/sidebar/Menu.client.tsx +++ b/app/components/sidebar/Menu.client.tsx @@ -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(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 - - {isAdmin && } + {isLoggedIn && } { + 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(null); + const [reproData, setReproData] = useState(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); } }; diff --git a/app/components/sidebar/SaveReproduction.tsx b/app/components/sidebar/SaveReproduction.tsx deleted file mode 100644 index c8053657..00000000 --- a/app/components/sidebar/SaveReproduction.tsx +++ /dev/null @@ -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(false); - const [problem, setProblem] = useState(null); - - const handleSaveReproduction = async (e: React.MouseEvent) => { - 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 ( - <> - - Save Reproduction - - 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 && ( - <> -
Reproduction Saved
-
-
- -
-
- - )} - {!savedReproduction && ( - <> -
- Save reproduction data (prompt, user annotations + simulationData) for the currently loaded problem:{' '} - {problem?.problemId} -
-
-
- - -
-
- - )} -
- - ); -}