diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..405b085 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM node:24-alpine AS builder +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build + +FROM nginx:alpine +COPY --from=builder /app/dist /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/src/pages/components/ui/Buttons.jsx b/src/pages/components/ui/Buttons.jsx index e1cebd6..2309959 100644 --- a/src/pages/components/ui/Buttons.jsx +++ b/src/pages/components/ui/Buttons.jsx @@ -1,9 +1,14 @@ import { Play } from 'lucide-react'; -export function SubmitButton() { +export function SubmitButton({ onClick, disabled }) { return ( - ); } diff --git a/src/pages/components/workspace/LeftWorkspace.jsx b/src/pages/components/workspace/LeftWorkspace.jsx index 1927b49..343cd4f 100644 --- a/src/pages/components/workspace/LeftWorkspace.jsx +++ b/src/pages/components/workspace/LeftWorkspace.jsx @@ -2,7 +2,6 @@ import { useState, useRef } from 'react'; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; import Editor from "@monaco-editor/react"; import { Code, Terminal, Import, RotateCcw, Expand } from 'lucide-react'; - import PanelHeader from '../ui/PanelHeader'; import { RunButton, SubmitButton } from '../ui/Buttons'; import Timer from '../ui/Timer'; @@ -10,16 +9,22 @@ import ConfirmModal from '../ui/ConfirmModal'; const DEFAULT_CODE = "# Напишите ваш код здесь...\n"; -export default function LeftWorkspace({ isDarkMode, position = 'left' }) { +const LANGUAGE_IDS = { + python: 71, + cpp: 54, + javascript: 63, +}; + +export default function LeftWorkspace({ isDarkMode, position = 'left', problemId = 6 }) { const [language, setLanguage] = useState('python'); const [code, setCode] = useState(DEFAULT_CODE); const [showResetModal, setShowResetModal] = useState(false); - + const [testResults, setTestResults] = useState(null); + const [isSubmitting, setIsSubmitting] = useState(false); const [isCollapsed, setIsCollapsed] = useState(false); const panelRef = useRef(null); const fileInputRef = useRef(null); - - const codeContainerRef = useRef(null); + const codeContainerRef = useRef(null); const handleFileImport = (e) => { const file = e.target.files[0]; @@ -43,20 +48,55 @@ export default function LeftWorkspace({ isDarkMode, position = 'left' }) { } }; + const handleSubmit = async () => { + setIsSubmitting(true); + setTestResults('Отправка решения...'); + try { + const blob = new Blob([code], { type: 'text/plain' }); + const file = new File([blob], 'solution.py'); + const formData = new FormData(); + formData.append('problemId', problemId); + formData.append('languageId', LANGUAGE_IDS[language]); + formData.append('file', file); + + const response = await fetch('/submissions/upload', { + method: 'POST', + body: formData, + }); + const submissionId = await response.text(); + setTestResults('Решение в очереди, ожидаем результат...'); + + const wsHost = window.location.hostname; + const ws = new WebSocket(`ws://${wsHost}:8080/ws/results?submissionId=${submissionId}`); + ws.onmessage = (event) => { + setTestResults(event.data); + setIsSubmitting(false); + ws.close(); + }; + ws.onerror = () => { + setTestResults('Ошибка WebSocket соединения'); + setIsSubmitting(false); + }; + } catch (err) { + setTestResults('Ошибка: ' + err.message); + setIsSubmitting(false); + } + }; + return ( - setIsCollapsed(true)} onExpand={() => setIsCollapsed(false)} - defaultSize={50} - minSize={4} + defaultSize={50} + minSize={4} className={`column-container ${position}-column`} > {isCollapsed ? ( -
panelRef.current?.expand()} title="Развернуть" > @@ -67,43 +107,37 @@ export default function LeftWorkspace({ isDarkMode, position = 'left' }) { ) : ( -
-
-
- - - - - - - - - - - - -
+
+ + + + + + + + +
-
- -
+
- - -
-

Здесь будут результаты запуска...

-
+ +
+ {testResults ? ( +
+                  {testResults}
+                
+ ) : ( +

+ Здесь будут результаты запуска... +

+ )} +
)} - - setShowResetModal(false)} onConfirm={confirmReset}