-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(frontend): 管理画面に提出状況詳細画面を実装 (#156)
- Loading branch information
1 parent
06a2898
commit dd05631
Showing
10 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
frontend/src/routes/admin/submissions/$submissionId/-components/submission-info/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { SubmissionInfo } from "./submission-info" |
54 changes: 54 additions & 0 deletions
54
...rc/routes/admin/submissions/$submissionId/-components/submission-info/submission-info.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" | ||
import { CheckCircle, XCircle } from "lucide-react" | ||
import { components } from "openapi/schema" | ||
|
||
type Submission = components["schemas"]["Submission"] | ||
|
||
export const SubmissionInfo = ({ submission }: { submission: Submission }) => ( | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>基本情報</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<dl className="grid grid-cols-1 gap-4 sm:grid-cols-2"> | ||
{/* 問題ID */} | ||
<div> | ||
<dt className="font-semibold">問題ID</dt> | ||
<dd>{submission.problem_id}</dd> | ||
</div> | ||
{/* 提出ID */} | ||
<div> | ||
<dt className="font-semibold">提出ID</dt> | ||
<dd>{submission.id}</dd> | ||
</div> | ||
{/* 提出日時 */} | ||
<div> | ||
<dt className="font-semibold">提出日時</dt> | ||
<dd>{submission.submitted_at}</dd> | ||
</div> | ||
{/* 学生ID */} | ||
<div> | ||
<dt className="font-semibold">学生ID</dt> | ||
<dd>{submission.student_id}</dd> | ||
</div> | ||
{/* プログラミング言語 */} | ||
<div> | ||
<dt className="font-semibold">プログラミング言語</dt> | ||
<dd>{`${submission.language.name} (${submission.language.version})`}</dd> | ||
</div> | ||
{/* 結果 */} | ||
<div> | ||
<dt className="font-semibold">全体の結果</dt> | ||
<dd className="flex items-center"> | ||
{submission.result.status === "Accepted" ? ( | ||
<CheckCircle className="mr-2 h-5 w-5 text-green-500" /> | ||
) : ( | ||
<XCircle className="mr-2 h-5 w-5 text-red-500" /> | ||
)} | ||
{submission.result.status} | ||
</dd> | ||
</div> | ||
</dl> | ||
</CardContent> | ||
</Card> | ||
) |
1 change: 1 addition & 0 deletions
1
frontend/src/routes/admin/submissions/$submissionId/-components/submitted-code/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { SubmittedCode } from "./submitted-code" |
22 changes: 22 additions & 0 deletions
22
...outes/admin/submissions/$submissionId/-components/submitted-code/read-only-code-block.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import MonacoEditor from "@monaco-editor/react" | ||
|
||
export const ReadOnlyCodeBlock = ({ | ||
code, | ||
language, | ||
}: { | ||
code: string | ||
language: string | ||
}) => ( | ||
<MonacoEditor | ||
height="100%" | ||
language={language} | ||
options={{ | ||
fixedOverflowWidgets: true, | ||
lineNumbers: "on", | ||
minimap: { enabled: false }, | ||
readOnly: true, | ||
scrollBeyondLastLine: false, | ||
}} | ||
value={code} | ||
/> | ||
) |
49 changes: 49 additions & 0 deletions
49
.../src/routes/admin/submissions/$submissionId/-components/submitted-code/submitted-code.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" | ||
import { Check, Copy } from "lucide-react" | ||
import { components } from "openapi/schema" | ||
import { useState } from "react" | ||
|
||
import { ReadOnlyCodeBlock } from "./read-only-code-block" | ||
|
||
type Submission = components["schemas"]["Submission"] | ||
|
||
export const SubmittedCode = ({ submission }: { submission: Submission }) => { | ||
const [isCopied, setIsCopied] = useState(false) | ||
|
||
const copyToClipboard = async () => { | ||
try { | ||
await navigator.clipboard.writeText(submission.code) | ||
setIsCopied(true) | ||
setTimeout(() => setIsCopied(false), 2000) | ||
} catch (error) { | ||
console.error("Failed to copy text:", error) | ||
} | ||
} | ||
|
||
return ( | ||
<Card className="flex flex-1 flex-col"> | ||
<CardHeader> | ||
<CardTitle>提出されたコード</CardTitle> | ||
</CardHeader> | ||
<CardContent className="flex-1 overflow-auto"> | ||
<div className="relative h-full overflow-x-auto rounded-md bg-gray-100 p-4"> | ||
<ReadOnlyCodeBlock | ||
code={submission.code} | ||
language={submission.language.name.toLowerCase()} | ||
/> | ||
<button | ||
aria-label="コードをコピー" | ||
className="absolute right-5 top-5 rounded-md bg-white p-2 shadow-sm hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2" | ||
onClick={copyToClipboard} | ||
> | ||
{isCopied ? ( | ||
<Check className="h-4 w-4 text-green-500" /> | ||
) : ( | ||
<Copy className="h-4 w-4" /> | ||
)} | ||
</button> | ||
</div> | ||
</CardContent> | ||
</Card> | ||
) | ||
} |
1 change: 1 addition & 0 deletions
1
frontend/src/routes/admin/submissions/$submissionId/-components/test-results/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { TestResults } from "./test-results" |
104 changes: 104 additions & 0 deletions
104
...tend/src/routes/admin/submissions/$submissionId/-components/test-results/test-results.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" | ||
import { | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableHead, | ||
TableHeader, | ||
TableRow, | ||
} from "@/components/ui/table" | ||
import { ChevronDown, ChevronUp } from "lucide-react" | ||
import { components } from "openapi/schema" | ||
import { useState } from "react" | ||
|
||
type Submission = components["schemas"]["Submission"] | ||
type TestCase = components["schemas"]["TestCase"] | ||
|
||
export const TestResults = ({ | ||
submission, | ||
testCases, | ||
}: { | ||
submission: Submission | ||
testCases: TestCase[] | ||
}) => { | ||
const [openIndexes, setOpenIndexes] = useState<boolean[]>( | ||
submission.test_results.map(() => false), | ||
) | ||
|
||
const toggleOpen = (index: number) => { | ||
setOpenIndexes((prev) => { | ||
const newState = [...prev] | ||
newState[index] = !newState[index] | ||
return newState | ||
}) | ||
} | ||
|
||
return ( | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>テスト結果</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<Table> | ||
<TableHeader> | ||
<TableRow> | ||
<TableHead>テストケースID</TableHead> | ||
<TableHead>結果</TableHead> | ||
<TableHead>メッセージ</TableHead> | ||
</TableRow> | ||
</TableHeader> | ||
<TableBody> | ||
{submission.test_results.map((TestResults, index) => ( | ||
<> | ||
<TableRow | ||
className="cursor-pointer hover:bg-gray-100" | ||
key={TestResults.test_case_id} | ||
onClick={() => toggleOpen(index)} | ||
> | ||
<TableCell>{TestResults.test_case_id}</TableCell> | ||
<TableCell | ||
className={ | ||
TestResults.status === "Passed" | ||
? "text-green-500" | ||
: "text-red-500" | ||
} | ||
> | ||
{TestResults.status} | ||
</TableCell> | ||
<TableCell>{TestResults.message || "-"}</TableCell> | ||
<TableCell> | ||
{openIndexes[index] ? ( | ||
<ChevronUp className="h-4 w-4" /> | ||
) : ( | ||
<ChevronDown className="h-4 w-4" /> | ||
)} | ||
</TableCell> | ||
</TableRow> | ||
{openIndexes[index] && ( | ||
<TableRow> | ||
<TableCell colSpan={4}> | ||
<div className="rounded-md bg-gray-50 p-4"> | ||
<h4 className="mb-2 font-semibold">入力:</h4> | ||
<pre className="mb-4 overflow-x-auto rounded-md bg-white p-2"> | ||
<code> | ||
{testCases[index]?.input || "データがありません"} | ||
</code> | ||
</pre> | ||
<h4 className="mb-2 font-semibold">正解出力:</h4> | ||
<pre className="overflow-x-auto rounded-md bg-white p-2"> | ||
<code> | ||
{testCases[index]?.output || "データがありません"} | ||
</code> | ||
</pre> | ||
</div> | ||
</TableCell> | ||
</TableRow> | ||
)} | ||
</> | ||
))} | ||
</TableBody> | ||
</Table> | ||
</CardContent> | ||
</Card> | ||
) | ||
} |
Oops, something went wrong.