diff --git a/.changes/submission.md b/.changes/submission.md new file mode 100644 index 0000000..d0954ad --- /dev/null +++ b/.changes/submission.md @@ -0,0 +1,5 @@ +--- +"algohub": patch:feat +--- + +Support auto load submissions in AlgoHub. diff --git a/src/main.ts b/src/main.ts index 344d5fe..96986cc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,7 +7,8 @@ import App from "@/App.vue"; import PrimeVue from "primevue/config"; import Aura from "@primevue/themes/aura"; import ToastService from "primevue/toastservice"; -import ConfirmationService from 'primevue/confirmationservice'; +import ConfirmationService from "primevue/confirmationservice"; +import Tooltip from "primevue/tooltip"; import router from "./router"; import { createPinia } from "pinia"; @@ -32,5 +33,6 @@ app.use(PrimeVue, { }); app.use(ToastService); app.use(ConfirmationService); +app.directive("tooltip", Tooltip); app.mount("#app"); diff --git a/src/scripts/api.ts b/src/scripts/api.ts index 393d6cb..f7fba4d 100644 --- a/src/scripts/api.ts +++ b/src/scripts/api.ts @@ -8,8 +8,8 @@ import type { Profile, UserContent, CreateProblem, - Language, - RecordId, + Submission, + Contest, } from "./types"; export interface Response { @@ -175,17 +175,6 @@ export const submitCode = async (problem_id: string, form: SubmitCodeForm) => { } }; -interface Submission { - id: string; - lang: Language; - problem: RecordId; - code: string; - status: "in_queue" | "judging" | "ready"; - judge_details: { status: any; timeUsed: number; memoryUsed: number }[]; - judge_result: { status: any; timeUsed: number; memoryUsed: number }; - // contest -} - export const fetchSubmission = async (id: string, form?: Credentials) => { try { const response = await axios.post(`/code/get/${id}`, form); @@ -194,3 +183,28 @@ export const fetchSubmission = async (id: string, form?: Credentials) => { return handleAxiosError(AxiosError.from(error)); } }; + +export const listSubmissionsByProblemForAccount = async ( + id: string, + account_id: string, + auth: Credentials +) => { + try { + const response = await axios.post( + `/code/list/${id}/account/${account_id}`, + auth + ); + return response.data as Response; + } catch (error) { + return handleAxiosError(AxiosError.from(error)); + } +}; + +export const listAllContests = async (auth: Credentials) => { + try { + const response = await axios.post("/contest/list/all", auth); + return response.data as Response; + } catch (error) { + return handleAxiosError(AxiosError.from(error)); + } +}; diff --git a/src/scripts/time.ts b/src/scripts/time.ts index e1f7f94..837cc89 100644 --- a/src/scripts/time.ts +++ b/src/scripts/time.ts @@ -5,46 +5,46 @@ export function timeAgo(timestamp: string): string { const diffInSeconds = Math.floor(diffInMs / 1000); if (diffInSeconds < 60) { - return `Updated just now`; + return `just now`; } const diffInMinutes = Math.floor(diffInSeconds / 60); if (diffInMinutes < 60) { - return `Updated ${diffInMinutes} minute${diffInMinutes > 1 ? 's' : ''} ago`; + return `${diffInMinutes} minute${diffInMinutes > 1 ? 's' : ''} ago`; } const diffInHours = Math.floor(diffInMinutes / 60); if (diffInHours < 24) { - return `Updated ${diffInHours} hour${diffInHours > 1 ? 's' : ''} ago`; + return `${diffInHours} hour${diffInHours > 1 ? 's' : ''} ago`; } const diffInDays = Math.floor(diffInHours / 24); if (diffInDays === 1) { - return `Updated yesterday`; + return `yesterday`; } if (diffInDays < 7) { - return `Updated ${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`; + return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`; } const diffInWeeks = Math.floor(diffInDays / 7); if (diffInWeeks === 1) { - return `Updated last week`; + return `last week`; } if (diffInWeeks < 4) { - return `Updated ${diffInWeeks} week${diffInWeeks > 1 ? 's' : ''} ago`; + return `${diffInWeeks} week${diffInWeeks > 1 ? 's' : ''} ago`; } const diffInMonths = Math.floor(diffInDays / 30); if (diffInMonths === 1) { - return `Updated last month`; + return `last month`; } if (diffInMonths < 12) { - return `Updated ${diffInMonths} month${diffInMonths > 1 ? 's' : ''} ago`; + return `${diffInMonths} month${diffInMonths > 1 ? 's' : ''} ago`; } const diffInYears = Math.floor(diffInDays / 365); if (diffInYears === 1) { - return `Updated last year`; + return `last year`; } - return `Updated ${diffInYears} year${diffInYears > 1 ? 's' : ''} ago`; + return `${diffInYears} year${diffInYears > 1 ? 's' : ''} ago`; } diff --git a/src/scripts/types.ts b/src/scripts/types.ts index 7480b90..70ec937 100644 --- a/src/scripts/types.ts +++ b/src/scripts/types.ts @@ -106,3 +106,37 @@ export enum Language { Nodejs = "nodejs", Java = "java", } + +export interface Submission { + id: string; + lang: Language; + problem: RecordId; + code: string; + status: "in_queue" | "judging" | "ready"; + judge_details: { status: any; timeUsed: number; memoryUsed: number }[]; + judge_result: { status: any; timeUsed: number; memoryUsed: number }; + // contest +} + +export enum Visibility { + Public = "public", + Private = "private", + Internal = "internal", +} + +export interface Contest { + id: string; + name: string; + mode: Mode; + visibility: Visibility; + description: string; + announcement?: string; + start_time: string; + end_time: string; + owner: RecordId; + creator: string; + updaters: string[]; + participants: RecordId[]; + created_at: string; + updated_at: string; +} diff --git a/src/views/account/[id].vue b/src/views/account/[id].vue index 028f10a..de22d90 100644 --- a/src/views/account/[id].vue +++ b/src/views/account/[id].vue @@ -181,7 +181,7 @@ onMounted(async () => { 'Public' }} - {{ timeAgo(problem.updated_at) }} + Updated {{ timeAgo(problem.updated_at) }} diff --git a/src/views/problem/[id].vue b/src/views/problem/[id].vue index 77204d1..c0e9a62 100644 --- a/src/views/problem/[id].vue +++ b/src/views/problem/[id].vue @@ -4,9 +4,10 @@ import { useRoute, useRouter } from 'vue-router'; import * as api from '@/scripts/api'; import { useAccountStore, useThemeStore } from '@/scripts/store'; import { useToast } from 'primevue'; -import { Language, UserProblem } from '@/scripts/types'; +import { Language, Submission, UserProblem } from '@/scripts/types'; import { MdPreview } from 'md-editor-v3'; import 'md-editor-v3/lib/style.css'; +import { timeAgo } from '@/scripts/time'; const route = useRoute(); const router = useRouter(); @@ -54,12 +55,9 @@ const onSubmit = async (code: string, lang: Language, finish: (text: string, sev if (!res.success) { return finish(res.message, 'error'); } - await new Promise(resolve => setTimeout(resolve, 2000)); - const submission = await api.fetchSubmission(res.data!.id, accountStore.auth!); - if (!submission.success) { - return finish(submission.message, 'error'); - } - finish(submission.data!.judge_result.status, 'success'); + await new Promise(resolve => setTimeout(resolve, 1000)); + await togglePanel('records'); + finish('', 'info') } const path = ref<{ label?: string, link?: string }[]>([]); @@ -89,12 +87,42 @@ window.onresize = () => { onUnmounted(() => { window.onresize = null; }) + +const selectedPanel = ref('problem'); + +const togglePanel = async (panel: string) => { + selectedPanel.value = panel; + switch (panel) { + case 'problem': + break; + case 'records': + await fetchSubmissions(); + break; + } +} + +const records = ref(); +const loadingRecords = ref(false); +const fetchSubmissions = async () => { + loadingRecords.value = true; + const res = await api.listSubmissionsByProblemForAccount( + problem.value!.id, + accountStore.account!.id!, + accountStore.auth! + ); + if (!res.success) { + return toast.add({ severity: 'error', summary: 'Error', detail: res.message }); + } + records.value = res.data!; + loadingRecords.value = false; +}