diff --git a/e2e/redirect_after_login.spec.ts b/e2e/redirect_after_login.spec.ts index 3ab908c75..a355f1048 100644 --- a/e2e/redirect_after_login.spec.ts +++ b/e2e/redirect_after_login.spec.ts @@ -60,9 +60,9 @@ test.describe('redirect with redirectTo parameter', () => { '/account_transfer', '/tasks', '/tasks/1', + '/tasks/grade', '/tags', '/tags/1', - '/vote_management', '/workbooks/order', ]; diff --git a/e2e/votes.spec.ts b/e2e/votes.spec.ts index 8cf06b4c5..f416b2b6b 100644 --- a/e2e/votes.spec.ts +++ b/e2e/votes.spec.ts @@ -4,7 +4,7 @@ import { loginAsAdmin, loginAsUser } from './helpers/auth'; const TIMEOUT = 60 * 1000; const VOTES_LIST_URL = '/votes'; -const VOTE_MANAGEMENT_URL = '/vote_management'; +const TASKS_GRADE_URL = '/tasks/grade'; const KNOWN_TASK_ID = 'abc422_a'; // From prisma/tasks.ts seed data const KNOWN_VOTE_DETAIL_URL = '/votes/abc422_a'; // From prisma/tasks.ts seed data @@ -160,18 +160,18 @@ test.describe('vote detail page (/votes/[slug])', () => { }); // --------------------------------------------------------------------------- -// Vote management page (/vote_management) — admin only +// Grade management page (/tasks/grade) — admin only // --------------------------------------------------------------------------- -test.describe('vote management page (/vote_management)', () => { +test.describe('grade management page (/tasks/grade)', () => { test('unauthenticated user is redirected to /login', async ({ page }) => { - await page.goto(VOTE_MANAGEMENT_URL); + await page.goto(TASKS_GRADE_URL); await expect(page).toHaveURL(/\/login/, { timeout: TIMEOUT }); }); test('non-admin user is redirected to /', async ({ page }) => { await loginAsUser(page); - await page.goto(VOTE_MANAGEMENT_URL); + await page.goto(TASKS_GRADE_URL); await expect(page).toHaveURL('/', { timeout: TIMEOUT }); }); @@ -181,25 +181,25 @@ test.describe('vote management page (/vote_management)', () => { }); test('can access the page', async ({ page }) => { - await page.goto(VOTE_MANAGEMENT_URL); - await expect(page).toHaveURL(VOTE_MANAGEMENT_URL, { timeout: TIMEOUT }); - await expect(page.getByRole('heading', { name: '投票管理' })).toBeVisible({ + await page.goto(TASKS_GRADE_URL); + await expect(page).toHaveURL(TASKS_GRADE_URL, { timeout: TIMEOUT }); + await expect(page.getByRole('heading', { name: 'グレード管理' })).toBeVisible({ timeout: TIMEOUT, }); }); - test('sees the vote management table with expected columns', async ({ page }) => { - await page.goto(VOTE_MANAGEMENT_URL); - await expect(page.getByRole('columnheader', { name: '問題' })).toBeVisible({ + test('shows search input and table with expected columns', async ({ page }) => { + await page.goto(TASKS_GRADE_URL); + await expect(page.getByPlaceholder('問題名・問題ID・出典で検索')).toBeVisible({ timeout: TIMEOUT, }); - await expect(page.getByRole('columnheader', { name: 'DBグレード' })).toBeVisible({ + await expect(page.getByRole('columnheader', { name: '問題名' })).toBeVisible({ timeout: TIMEOUT, }); - await expect(page.getByRole('columnheader', { name: '中央値グレード' })).toBeVisible({ + await expect(page.getByRole('columnheader', { name: 'グレード(admin)' })).toBeVisible({ timeout: TIMEOUT, }); - await expect(page.getByRole('columnheader', { name: '票数' })).toBeVisible({ + await expect(page.getByRole('columnheader', { name: 'グレード(ユーザ投票)' })).toBeVisible({ timeout: TIMEOUT, }); }); diff --git a/src/lib/components/TaskGradeList.svelte b/src/lib/components/TaskGradeList.svelte index f8b0d7a6d..dadfbb9c1 100644 --- a/src/lib/components/TaskGradeList.svelte +++ b/src/lib/components/TaskGradeList.svelte @@ -6,11 +6,10 @@ interface Props { taskResults: TaskResults; - isAdmin: boolean; isLoggedIn: boolean; } - let { taskResults, isAdmin, isLoggedIn }: Props = $props(); + let { taskResults, isLoggedIn }: Props = $props(); // TODO: 共通する内容はutilsに移動させる。 const taskResultsForEachGrade = $derived( @@ -25,28 +24,14 @@ const countTasks = (taskGrade: TaskGrade) => { return taskResultsForEachGrade.get(taskGrade)?.length ?? 0; }; - - const isShowTaskList = (isAdmin: boolean, taskGrade: TaskGrade): boolean => { - if (isAdmin) { - return true; - } - - if (taskGrade !== TaskGrade.PENDING) { - return true; - } - - return false; - }; {#each taskGradeValues as taskGrade (taskGrade)} - - {#if countTasks(taskGrade) && isShowTaskList(isAdmin, taskGrade)} + {#if countTasks(taskGrade) && taskGrade !== TaskGrade.PENDING} {/if} diff --git a/src/lib/components/TaskList.svelte b/src/lib/components/TaskList.svelte index 3cf080f56..f0fd84c4f 100644 --- a/src/lib/components/TaskList.svelte +++ b/src/lib/components/TaskList.svelte @@ -1,6 +1,4 @@ + +
+ + +
+ +
+ + + + 問題名 + 出典 + グレード(admin) + グレード(ユーザ投票) + + + {#if search === ''} + + + 問題名・問題ID・出典を入力してください + + + {:else} + {#each filteredTasks as task (task.task_id)} + + + + + {removeTaskIndexFromTitle(task.title, task.task_table_index)} + + + + + + {addContestNameToTaskIndex(task.contest_id, task.task_table_index)} + + + + {@render adminGradeCell(task)} + + + + {#if task.estimatedGrade} + + {/if} + + + {:else} + + + 該当する問題が見つかりませんでした + + + {/each} + {/if} + +
+
+ +{#snippet adminGradeCell(task: TaskWithVoteInfo)} + +
+
+ + +
+ + {#if task.grade !== TaskGrade.PENDING && task.estimatedGrade} +
+ + +
+ {/if} +
+
+{/snippet} diff --git a/src/routes/(admin)/vote_management/+page.svelte b/src/routes/(admin)/vote_management/+page.svelte deleted file mode 100644 index 0b87519b7..000000000 --- a/src/routes/(admin)/vote_management/+page.svelte +++ /dev/null @@ -1,103 +0,0 @@ - - -
- - -

- 集計済み統計一覧(3票以上で暫定グレードが算出されます) -

- - - - 問題 - コンテスト - DBグレード - 中央値グレード - 票数 - - - {#each data.stats as stat (stat.taskId)} - - - - {stat.title} - - - {stat.contestId} - -
-
- - - - {#if stat.dbGrade !== TaskGrade.PENDING && stat.estimatedGrade} -
- - -
- {/if} -
-
- - - - {stat.voteTotal} -
- {/each} - {#if data.stats.length === 0} - - - 集計データがありません - - - {/if} -
-
-
diff --git a/src/routes/problems/+page.server.ts b/src/routes/problems/+page.server.ts index 901f537dc..7e333f936 100644 --- a/src/routes/problems/+page.server.ts +++ b/src/routes/problems/+page.server.ts @@ -5,7 +5,6 @@ import { zod4 } from 'sveltekit-superforms/adapters'; import * as task_crud from '$lib/services/task_results'; import { getVoteGradeStatistics } from '$features/votes/services/vote_statistics'; import type { TaskResults } from '$lib/types/task'; -import { Roles } from '$lib/types/user'; import { updateTaskResult } from '$lib/actions/update_task_result'; import { voteAbsoluteGrade } from '@/features/votes/actions/vote_actions'; import { voteAbsoluteGradeSchema } from '$features/votes/zod/schema'; @@ -17,7 +16,6 @@ export async function load({ locals, url, setHeaders }) { const params = await url.searchParams; const tagIds: string | null = params.get('tagIds'); - const isAdmin: boolean = session?.user.role === Roles.ADMIN; // TODO: utilに移動させる const isLoggedIn: boolean = session !== null; @@ -41,26 +39,18 @@ export async function load({ locals, url, setHeaders }) { setHeaders({ 'Cache-Control': 'public, max-age=0, s-maxage=300, stale-while-revalidate=600' }); } - if (tagIds != null) { - return { - taskResults: (await task_crud.getTasksWithTagIds( - tagIds, - session?.user.userId, - )) as TaskResults, - voteResults, - isAdmin: isAdmin, - isLoggedIn: isLoggedIn, - isAtCoderVerified: locals.user?.is_validated === true, - }; - } else { - return { - taskResults: (await task_crud.getTaskResults(session?.user.userId)) as TaskResults, - voteResults, - isAdmin: isAdmin, - isLoggedIn: isLoggedIn, - isAtCoderVerified: locals.user?.is_validated === true, - }; - } + const taskResults = ( + tagIds + ? await task_crud.getTasksWithTagIds(tagIds, session?.user.userId) + : await task_crud.getTaskResults(session?.user.userId) + ) as TaskResults; + + return { + taskResults, + voteResults, + isLoggedIn: isLoggedIn, + isAtCoderVerified: locals.user?.is_validated === true, + }; } export const actions = { diff --git a/src/routes/problems/+page.svelte b/src/routes/problems/+page.svelte index ecf9aef2a..504e6f13d 100644 --- a/src/routes/problems/+page.svelte +++ b/src/routes/problems/+page.svelte @@ -22,7 +22,6 @@ let taskResults: TaskResults = $derived(data.taskResults.sort(compareByContestIdAndTaskId)); - const isAdmin = $derived(data.isAdmin); const isLoggedIn = $derived(data.isLoggedIn); const isAtCoderVerified = $derived(data.isAtCoderVerified); const voteResults = $derived(data.voteResults); @@ -65,7 +64,7 @@ {/snippet} {#snippet listByGrade()} - + {/snippet} {#snippet gradeGuidelineTable()}