Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Submissions table #87

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/api/mock/front-back-api-mock.json
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@
"responses": [
{
"uuid": "6e32e8f4-b0c6-4ceb-b997-16f63b908234",
"body": "{\n \"total\": {{queryParam 'limit' 20}},\n \"submissions\": [\n {{#repeat (queryParam 'limit' 20)}}\n {\n \"id\": \"{{faker 'string.uuid'}}\",\n \"userId\": \"{{faker 'string.uuid'}}\",\n \"userName\": \"{{faker 'internet.userName'}}\",\n \"problemId\": {{faker 'number.int' min=100 max=1000}},\n \"totalScore\": {{faker 'number.int' min=100 max=1000}},\n \"maxTime\": {{faker 'number.int' min=100 max=1000}},\n \"maxMemory\": {{faker 'number.float' min=100 max=1000}},\n \"codeLength\": {{faker 'number.float' min=100 max=1000}},\n \"languageId\": \"{{body 'languageId'}},\n \"judgeStatus\": \"{{oneOf (array 'AC' 'WA' 'TLE' 'CE')}}\",\n \"submittedAt\": \"{{date '2020-01-01' '2024-11-05' 'yyyy-MM-dd\\'T\\'HH:mm:ss.SSS\\'Z\\''}}\"\n }\n {{/repeat}}\n ]\n}",
"body": "{\n \"total\": {{queryParam 'limit' 20}},\n \"submissions\": [\n {{#repeat (queryParam 'limit' 20)}}\n {\n \"id\": \"{{faker 'string.uuid'}}\",\n \"userId\": \"{{faker 'string.uuid'}}\",\n \"userName\": \"{{faker 'internet.userName'}}\",\n \"problemId\": {{faker 'number.int' min=100 max=1000}},\n \"totalScore\": {{faker 'number.int' min=100 max=1000}},\n \"maxTime\": {{faker 'number.int' min=100 max=1000}},\n \"maxMemory\": {{faker 'number.float' min=100 max=1000}},\n \"codeLength\": {{faker 'number.float' min=100 max=1000}},\n \"languageId\": \"{{body 'languageId'}}\",\n \"judgeStatus\": \"{{oneOf (array 'AC' 'WA' 'TLE' 'CE')}}\",\n \"submittedAt\": \"{{date '2020-01-01' '2024-11-05' 'yyyy-MM-dd\\'T\\'HH:mm:ss.SSS\\'Z\\''}}\"\n }\n {{/repeat}}\n ]\n}",
"latency": 0,
"statusCode": 200,
"label": "",
Expand Down Expand Up @@ -830,7 +830,7 @@
"responses": [
{
"uuid": "1bcfbc5d-6c44-43ec-8b67-c936c3691a23",
"body": "{\n \"id\": \"{{urlParam 'submissionId'}}\",\n \"userId\": \"{{faker 'string.uuid'}}\",\n \"userName\": \"{{faker 'internet.userName'}}\",\n \"problemId\": {{faker 'number.int' min=100 max=1000}},\n \"totalScore\": {{faker 'number.int' min=100 max=1000}},\n \"maxTime\": {{faker 'number.int' min=100 max=1000}},\n \"maxMemory\": {{faker 'number.float' min=100 max=1000}},\n \"codeLength\": {{faker 'number.float' min=100 max=1000}},\n \"languageId\": \"{{body 'languageId'}},\n \"overallJudgeStatus\": \"{{oneOf (array 'AC' 'WA' 'TLE' 'CE')}}\",\n \"submittedAt\": \"{{date '2020-01-01' '2024-11-05' 'yyyy-MM-dd\\'T\\'HH:mm:ss.SSS\\'Z\\''}}\",\n \"judgeResults\": [\n {{#repeat 3}}\n {\n \"testcaseId\": \"{{faker 'string.uuid'}}\",\n \"testcaseName\": \"{{faker 'internet.userName'}}\",\n \"judgeStatus\": \"{{oneOf (array 'AC' 'WA' 'TLE' 'CE')}}\",\n \"score\": {{faker 'number.int' min=100 max=1000}},\n \"time\": {{faker 'number.int' min=100 max=1000}},\n \"memory\": {{faker 'number.float' min=100 max=1000}},\n }\n {{/repeat}}\n ]\n}",
"body": "{\n \"id\": \"{{urlParam 'submissionId'}}\",\n \"userId\": \"{{faker 'string.uuid'}}\",\n \"userName\": \"{{faker 'internet.userName'}}\",\n \"problemId\": {{faker 'number.int' min=100 max=1000}},\n \"totalScore\": {{faker 'number.int' min=100 max=1000}},\n \"maxTime\": {{faker 'number.int' min=100 max=1000}},\n \"maxMemory\": {{faker 'number.float' min=100 max=1000}},\n \"codeLength\": {{faker 'number.float' min=100 max=1000}},\n \"languageId\": \"{{body 'languageId'}}\",\n \"overallJudgeStatus\": \"{{oneOf (array 'AC' 'WA' 'TLE' 'CE')}}\",\n \"submittedAt\": \"{{date '2020-01-01' '2024-11-05' 'yyyy-MM-dd\\'T\\'HH:mm:ss.SSS\\'Z\\''}}\",\n \"judgeResults\": [\n {{#repeat 3}}\n {\n \"testcaseId\": \"{{faker 'string.uuid'}}\",\n \"testcaseName\": \"{{faker 'internet.userName'}}\",\n \"judgeStatus\": \"{{oneOf (array 'AC' 'WA' 'TLE' 'CE')}}\",\n \"score\": {{faker 'number.int' min=100 max=1000}},\n \"time\": {{faker 'number.int' min=100 max=1000}},\n \"memory\": {{faker 'number.float' min=100 max=1000}},\n }\n {{/repeat}}\n ]\n}",
"latency": 0,
"statusCode": 200,
"label": "",
Expand Down
44 changes: 44 additions & 0 deletions src/components/PagedTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script setup lang="ts">
export type Column = { id: string; textAlign?: 'start' | 'end' | 'center' }

// TODO: add pagination, sorting and filtering features
const { cols, rowIds } = defineProps<{
cols: Column[]
rowIds: string[]
}>()
</script>

<template>
<table class="w-full">
<thead class="h-10 bg-background-tertiary">
<tr>
<th
v-for="{ id, textAlign } in cols"
:key="id"
class="px-2 first:pl-4 last:pr-4"
:style="{ textAlign }"
>
<slot name="head" :col-id="id" />
</th>
</tr>
</thead>
<tbody>
<tr
v-for="rowId in rowIds"
:key="rowId"
class="h-9 border-b border-solid border-border-secondary"
>
<th
v-for="col in cols"
:key="col.id"
class="px-2 first:pl-4 last:pr-4"
:style="{ textAlign: col.textAlign }"
>
<slot name="cell" :row-id="rowId" :col-id="col.id" />
</th>
</tr>
</tbody>
</table>
</template>

<style scoped></style>
10 changes: 10 additions & 0 deletions src/utils/date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const dateToString = (date: Date): string => {
return date.toLocaleString('ja-JP', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
}
22 changes: 18 additions & 4 deletions src/views/UserView.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import { useRoute } from 'vue-router'
import SideMenuUserPage from '@/components/Navigations/SideMenu/SideMenuUserPage.vue'

const route = useRoute()

if (typeof route.params.id !== 'string') throw new Error('Invalid route')
const username = route.params.id
// TODO: Fetch user data
</script>

<!-- TODO: Fix the layout on mobile -->
<template>
<div>
<h1>User</h1>
<RouterView />
<div class="flex gap-[max(2rem,calc(25dvw-16rem))] px-[max(2rem,calc(25dvw-16rem))]">
<nav class="sticky top-14 h-[calc(100dvh-3.5rem)]">
<SideMenuUserPage :username="username" />
</nav>
<main class="flex-auto py-10">
<RouterView :username="username" />
</main>
</div>
</template>

Expand Down
87 changes: 84 additions & 3 deletions src/views/user/UserSubmissions.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,89 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import PagedTable, { type Column } from '@/components/PagedTable.vue'
import { type GetSubmissionsRequest, SubmissionsApi, type SubmissionSummary } from '@/api/generated'
import { onMounted, ref } from 'vue'
import { dateToString } from '@/utils/date'

const { username } = defineProps<{ username: string }>()

const submissionIds = ref<string[] | null>(null)
const submissions = ref<Map<string, SubmissionSummary>>(new Map())

/**
* Fetch submissions from the API and store them in the `submissionsIds` and `submissions` refs
* @param filter filter for the submissions
*/
const fetchSubmissions = async (filter: GetSubmissionsRequest) => {
try {
const response = await new SubmissionsApi().getSubmissionsRaw({
orderBy: 'submittedAtDesc',
...filter,
username
})

submissionIds.value = []
submissions.value = new Map()
for (const submission of (await response.value()).submissions!) {

Check failure on line 26 in src/views/user/UserSubmissions.vue

View workflow job for this annotation

GitHub Actions / type and build check

Property 'submissions' does not exist on type 'SubmissionSummaries'.
submissionIds.value.push(submission.id)
submissions.value.set(submission.id, submission)
}
} catch (error) {
submissionIds.value = null

console.error('API Error:', error)
alert(`API Error: ${error}`)
}
}

onMounted(fetchSubmissions)

const cols: (Column & { name: string })[] = [
{ id: 'submittedAt', textAlign: 'start', name: '提出日時' },
{ id: 'userName', textAlign: 'start', name: 'ユーザー名' },
{ id: 'totalScore', textAlign: 'end', name: '得点' },
{ id: 'codeLength', textAlign: 'end', name: 'コード長' },
{ id: 'judgeStatus', textAlign: 'center', name: 'ジャッジ結果' },
{ id: 'maxTime', textAlign: 'end', name: '実行時間' },
{ id: 'maxMemory', textAlign: 'end', name: 'メモリ' }
] as const
</script>

<template>
<div>
<h2>User Submissions</h2>
<div class="rounded-lg border border-solid border-border-secondary pt-28 text-center">
<h2 class="fontstyle-ui-title-large">提出一覧<br />テーブル</h2>
<section class="p-10">
<!-- TODO: add pagination, sorting and filtering features -->
<PagedTable v-if="submissionIds" :cols="cols" :row-ids="submissionIds">
<template #head="{ colId }">
{{ cols.find(({ id }) => id === colId)!.name }}
</template>
<template #cell="{ rowId, colId }">
<template v-if="colId === 'submittedAt'">
{{ dateToString(submissions.get(rowId)!.submittedAt) }}
</template>
<template v-else-if="colId === 'userName'">
{{ submissions.get(rowId)!.userName }}
</template>
<template v-else-if="colId === 'totalScore'">
{{ submissions.get(rowId)!.totalScore }}
</template>
<template v-else-if="colId === 'codeLength'">
{{ Math.ceil(submissions.get(rowId)!.codeLength) }} Byte
</template>
<template v-else-if="colId === 'judgeStatus'">
{{ submissions.get(rowId)!.judgeStatus }}
</template>
<template v-else-if="colId === 'maxTime'">
{{ submissions.get(rowId)!.maxTime }} ms
</template>
<template v-else-if="colId === 'maxMemory'">
{{ submissions.get(rowId)!.maxMemory.toFixed(3) }} MiB
</template>
<template v-else>Unknown column: {{ colId }}</template>
</template>
</PagedTable>
<div v-else>読み込み中...</div>
</section>
</div>
</template>

Expand Down
Loading