From 0cf35658a5ec704a29834c7188198fa9bad66f2a Mon Sep 17 00:00:00 2001 From: Kato Hiroki Date: Tue, 17 Mar 2026 22:30:15 +0000 Subject: [PATCH 1/6] feat: Change Round label background to AC color when all tasks accepted (#3270) Also fix optimistic update bug where ac_with_editorial set is_ac to false, causing the label to not update live until page reload. Co-Authored-By: Claude Sonnet 4.6 --- .../ac-background-for-round-label/plan.md | 99 +++++++++++++++++++ .../components/contest-table/TaskTable.svelte | 16 ++- .../SubmissionStatus/UpdatingDropdown.svelte | 4 +- 3 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md diff --git a/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md b/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md new file mode 100644 index 000000000..63dd8e2f1 --- /dev/null +++ b/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md @@ -0,0 +1,99 @@ +# Round ラベルの全問AC時の背景色変更 + +## 概要 + +Issue: https://github.com/AtCoder-NoviSteps/AtCoderNoviSteps/issues/3270 + +コンテストテーブルの Round ラベルセルについて、そのコンテスト行の全問が AC(または解説AC)の場合に +背景色を AC 背景色(`bg-atcoder-ac-background dark:bg-atcoder-ac-background_dark`)に変更する。 + +## 前提 + +- 対象はログインユーザーのみ(未ログイン時は従来の `bg-gray-50 dark:bg-gray-800` を維持) +- `ac` / `ac_with_editorial` はどちらも `is_ac === true` のため、両方とも AC 背景色(緑)でよい +- `areAllTasksAccepted` の既存テストが通っているので、ユーティリティ側の追加テストは不要 + +## 設計メモ + +### データの取り出し方 + +`contestTable.innerTaskTable[contestId]` は `Record` 。 +`generateTable` は実際に存在するタスク結果のみを挿入するため、 +`Object.values(...)` で取得した配列に `undefined` は含まれない。 + +```typescript +const rowTasks: TaskResult[] = Object.values(contestTable.innerTaskTable[contestId]); +areAllTasksAccepted(rowTasks, rowTasks); +// 第1引数(acceptedTasks)を内部で is_ac フィルタ、第2引数(allTasks)をカウント +// 既存テストでも同一配列を両引数に渡すパターンが使われている +``` + +### ヘルパー関数 + +既存の `getBodyCellClasses` と同パターンで関数を抽出する。 +`isLoggedIn` はコンポーネント prop のクロージャ参照。 + +```typescript +function getRoundLabelClasses(contestTable: ProviderData, contestId: string): string { + const tasks = Object.values(contestTable.innerTaskTable[contestId]); + const bgColor = + isLoggedIn && areAllTasksAccepted(tasks, tasks) + ? getBackgroundColorFrom('ac') + : 'bg-gray-50 dark:bg-gray-800'; + + return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center ${bgColor}`; +} +``` + +## バグ報告と調査(2026-03-18) + +### 症状 + +ステータスを「挑戦中(WA)→ 解説AC」に変更しても、Round ラベルの背景がリアクティブに緑にならない。 +リロードすると緑になる(= DB には正しく保存されている)。 +「挑戦中(WA)→ AC」は即時反映される。 + +### 原因 + +`src/lib/components/SubmissionStatus/UpdatingDropdown.svelte` の楽観的更新関数 `updateTaskResult` に誤りがある。 + +```typescript +// 誤り(line 161) +is_ac: submissionStatus.innerName === 'ac', +``` + +`ac_with_editorial` を選択すると `'ac_with_editorial' === 'ac'` が `false` になるため、 +楽観的更新後の `TaskResult` は `is_ac: false` のまま。 + +`getRoundLabelClasses` 内の `areAllTasksAccepted` は `is_ac` を参照するため、 +全問 ac_with_editorial でも `false` を返し → ラベルが灰色のまま。 + +リロードすれば DB から `is_ac: true`(`submission_statuses` の `is_AC: true`)が読まれるため正しく緑になる。 + +### 対処 + +`submission_statuses`(同ファイルで既に import 済み)から `is_AC` を参照する。 + +```typescript +// 修正後 +is_ac: + submission_statuses.find((status) => status.status_name === submissionStatus.innerName)?.is_AC ?? + false, +``` + +### 修正ファイル + +- `src/lib/components/SubmissionStatus/UpdatingDropdown.svelte`(line 161) + +--- + +## TODO + +- [x] `src/features/tasks/components/contest-table/TaskTable.svelte` + - [x] `areAllTasksAccepted` を `$lib/utils/task` から import に追加 + - [x] `getRoundLabelClasses(contestTable, contestId)` ヘルパー関数を追加(`getBodyCellClasses` の隣) + - [x] `TableBodyCell`(Round ラベル)の `class` を `getRoundLabelClasses(contestTable, contestId)` に差し替え +- [ ] 動作確認 + - [ ] ログインユーザーで全問AC済みのコンテスト行のラベルが緑背景になること + - [ ] 未AC・未ログインでは従来色(グレー)のままであること +- [x] `pnpm format` を実行してコミット diff --git a/src/features/tasks/components/contest-table/TaskTable.svelte b/src/features/tasks/components/contest-table/TaskTable.svelte index 3c26f5bb6..ed61b4d31 100644 --- a/src/features/tasks/components/contest-table/TaskTable.svelte +++ b/src/features/tasks/components/contest-table/TaskTable.svelte @@ -26,6 +26,7 @@ } from '$features/tasks/utils/contest-table/contest_table_provider'; import { getBackgroundColorFrom } from '$lib/services/submission_status'; + import { areAllTasksAccepted } from '$lib/utils/task'; import { createContestTaskPairKey } from '$lib/utils/contest_task_pair'; interface Props { @@ -105,6 +106,16 @@ return totalColumns > 8 ? 'flex flex-wrap' : 'flex flex-wrap xl:table-row'; } + function getRoundLabelClasses(contestTable: ProviderData, contestId: string): string { + const tasks = Object.values(contestTable.innerTaskTable[contestId]); + const bgColor = + isLoggedIn && areAllTasksAccepted(tasks, tasks) + ? getBackgroundColorFrom('ac') + : 'bg-gray-50 dark:bg-gray-800'; + + return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center ${bgColor}`; + } + function getBodyCellClasses(taskResult: TaskResult, tableBodyCellWidth: string): string { const backgroundColor = getBackgroundColor(taskResult); @@ -240,10 +251,7 @@ {#each contestTable.contestIds as contestId (contestId)} {#if contestTable.displayConfig.isShownRoundLabel} - + {getContestRoundLabel(provider, contestId)} {/if} diff --git a/src/lib/components/SubmissionStatus/UpdatingDropdown.svelte b/src/lib/components/SubmissionStatus/UpdatingDropdown.svelte index 00e1cf4e0..6993d6e92 100644 --- a/src/lib/components/SubmissionStatus/UpdatingDropdown.svelte +++ b/src/lib/components/SubmissionStatus/UpdatingDropdown.svelte @@ -158,7 +158,9 @@ status_name: submissionStatus.innerName, status_id: submissionStatus.innerId, submission_status_label_name: submissionStatus.labelName, - is_ac: submissionStatus.innerName === 'ac', + is_ac: + submission_statuses.find((status) => status.status_name === submissionStatus.innerName) + ?.is_AC ?? false, updated_at: new Date(), }; } From 1650e41a945202b0e39557e17cc313304668c805 Mon Sep 17 00:00:00 2001 From: Kato Hiroki Date: Tue, 17 Mar 2026 22:31:57 +0000 Subject: [PATCH 2/6] docs: Add Optimistic Updates rule to coding-style Co-Authored-By: Claude Sonnet 4.6 --- .claude/rules/coding-style.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.claude/rules/coding-style.md b/.claude/rules/coding-style.md index 454db270b..591e9be71 100644 --- a/.claude/rules/coding-style.md +++ b/.claude/rules/coding-style.md @@ -34,6 +34,15 @@ When the same constraint is enforced in two layers (e.g. Zod validation + SQL `C .refine(...) ``` +## Optimistic Updates + +Derive computed fields (flags, labels, etc.) from the canonical data source — don't +re-implement the derivation inline. Divergence causes a "works after reload" bug where +the server state is correct but the client-side update is wrong. + +**Diagnostic**: "Not reflected live, but fixed after reload" → suspect the optimistic +update payload, not the reactivity system. + ## Async Rollback: Capture State Before `await` Capture `$state` values before the first `await` for safe rollback. A concurrent update can overwrite the variable while awaiting: From e6ee788d3c2459021c55a37b63dd9ec4b2cb33ef Mon Sep 17 00:00:00 2001 From: Kato Hiroki Date: Tue, 17 Mar 2026 22:51:17 +0000 Subject: [PATCH 3/6] docs: Update plan (#3270) --- .../ac-background-for-round-label/plan.md | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md b/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md index 63dd8e2f1..bbba7e425 100644 --- a/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md +++ b/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md @@ -4,13 +4,19 @@ Issue: https://github.com/AtCoder-NoviSteps/AtCoderNoviSteps/issues/3270 -コンテストテーブルの Round ラベルセルについて、そのコンテスト行の全問が AC(または解説AC)の場合に -背景色を AC 背景色(`bg-atcoder-ac-background dark:bg-atcoder-ac-background_dark`)に変更する。 +コンテストテーブルの Round ラベルセルについて、そのコンテスト行の全問が AC 系(`is_ac === true`)の場合に +ステータスの内訳に応じて背景色を変更する。 + +| 条件 | 背景色 | +|------|--------| +| 全問 `is_ac === true` かつ 1問以上 `ac_with_editorial` | 解説AC背景色 (`bg-atcoder-ac-with_editorial-background dark:bg-atcoder-ac-with_editorial-background_dark`) | +| 全問 `is_ac === true` かつ 全問 `ac` | AC背景色(緑)(`bg-atcoder-ac-background dark:bg-atcoder-ac-background_dark`) | +| それ以外(未AC あり、または未ログイン) | グレー (`bg-gray-50 dark:bg-gray-800`) | ## 前提 - 対象はログインユーザーのみ(未ログイン時は従来の `bg-gray-50 dark:bg-gray-800` を維持) -- `ac` / `ac_with_editorial` はどちらも `is_ac === true` のため、両方とも AC 背景色(緑)でよい +- 解説AC(`ac_with_editorial`)は `is_ac === true` だが、全問 AC であっても 1 問でも解説AC が混じれば解説AC背景色を優先する - `areAllTasksAccepted` の既存テストが通っているので、ユーティリティ側の追加テストは不要 ## 設計メモ @@ -30,21 +36,30 @@ areAllTasksAccepted(rowTasks, rowTasks); ### ヘルパー関数 -既存の `getBodyCellClasses` と同パターンで関数を抽出する。 `isLoggedIn` はコンポーネント prop のクロージャ参照。 +全問 AC 判定後、`tasks.some()` で解説AC の有無を確認して背景色を分岐する。 ```typescript function getRoundLabelClasses(contestTable: ProviderData, contestId: string): string { const tasks = Object.values(contestTable.innerTaskTable[contestId]); - const bgColor = - isLoggedIn && areAllTasksAccepted(tasks, tasks) - ? getBackgroundColorFrom('ac') - : 'bg-gray-50 dark:bg-gray-800'; + const bgColor = getRoundLabelBgColor(tasks); return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center ${bgColor}`; } + +function getRoundLabelBgColor(tasks: TaskResult[]): string { + if (!isLoggedIn || !areAllTasksAccepted(tasks, tasks)) { + return 'bg-gray-50 dark:bg-gray-800'; + } + + const hasEditorial = tasks.some((task) => task.status_name === 'ac_with_editorial'); + return getBackgroundColorFrom(hasEditorial ? 'ac_with_editorial' : 'ac'); +} ``` +`getRoundLabelBgColor` を独立した関数に切り出すことでテストが書きやすくなる +(ただし `isLoggedIn` をクロージャで参照しているため、引数として渡す設計でも可)。 + ## バグ報告と調査(2026-03-18) ### 症状 @@ -93,7 +108,12 @@ is_ac: - [x] `areAllTasksAccepted` を `$lib/utils/task` から import に追加 - [x] `getRoundLabelClasses(contestTable, contestId)` ヘルパー関数を追加(`getBodyCellClasses` の隣) - [x] `TableBodyCell`(Round ラベル)の `class` を `getRoundLabelClasses(contestTable, contestId)` に差し替え +- [ ] 仕様変更: 解説AC混在時の背景色分岐 + - [ ] `getRoundLabelClasses` 内の分岐を `getRoundLabelBgColor` ヘルパーに切り出す + - [ ] 全問 AC かつ解説ACあり → `getBackgroundColorFrom('ac_with_editorial')` に変更 + - [ ] 全問 AC かつ解説ACなし → `getBackgroundColorFrom('ac')` を維持 - [ ] 動作確認 - - [ ] ログインユーザーで全問AC済みのコンテスト行のラベルが緑背景になること + - [ ] ログインユーザーで全問AC済み(AC のみ)のコンテスト行のラベルが緑背景になること + - [ ] ログインユーザーで全問AC済み(解説ACあり)のコンテスト行のラベルが解説AC背景色になること - [ ] 未AC・未ログインでは従来色(グレー)のままであること -- [x] `pnpm format` を実行してコミット +- [ ] `pnpm format` を実行してコミット From 7bba06bbfa49bf8d3ede8ed5f1fdeb09017c99fd Mon Sep 17 00:00:00 2001 From: Kato Hiroki Date: Tue, 17 Mar 2026 23:02:24 +0000 Subject: [PATCH 4/6] feat: Add ac_with_editorial background to Round label when all tasks have editorial AC (#3270) Co-Authored-By: Claude Sonnet 4.6 --- .../ac-background-for-round-label/plan.md | 29 ++++++++++--------- .../components/contest-table/TaskTable.svelte | 15 +++++++--- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md b/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md index bbba7e425..2f3a67027 100644 --- a/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md +++ b/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md @@ -7,11 +7,11 @@ Issue: https://github.com/AtCoder-NoviSteps/AtCoderNoviSteps/issues/3270 コンテストテーブルの Round ラベルセルについて、そのコンテスト行の全問が AC 系(`is_ac === true`)の場合に ステータスの内訳に応じて背景色を変更する。 -| 条件 | 背景色 | -|------|--------| +| 条件 | 背景色 | +| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | 全問 `is_ac === true` かつ 1問以上 `ac_with_editorial` | 解説AC背景色 (`bg-atcoder-ac-with_editorial-background dark:bg-atcoder-ac-with_editorial-background_dark`) | -| 全問 `is_ac === true` かつ 全問 `ac` | AC背景色(緑)(`bg-atcoder-ac-background dark:bg-atcoder-ac-background_dark`) | -| それ以外(未AC あり、または未ログイン) | グレー (`bg-gray-50 dark:bg-gray-800`) | +| 全問 `is_ac === true` かつ 全問 `ac` | AC背景色(緑)(`bg-atcoder-ac-background dark:bg-atcoder-ac-background_dark`) | +| それ以外(未AC あり、または未ログイン) | グレー (`bg-gray-50 dark:bg-gray-800`) | ## 前提 @@ -98,7 +98,7 @@ is_ac: ### 修正ファイル -- `src/lib/components/SubmissionStatus/UpdatingDropdown.svelte`(line 161) +- `src/lib/components/SubmissionStatus/UpdatingDropdown.svelte`(line 161)✅ 修正済み --- @@ -108,12 +108,13 @@ is_ac: - [x] `areAllTasksAccepted` を `$lib/utils/task` から import に追加 - [x] `getRoundLabelClasses(contestTable, contestId)` ヘルパー関数を追加(`getBodyCellClasses` の隣) - [x] `TableBodyCell`(Round ラベル)の `class` を `getRoundLabelClasses(contestTable, contestId)` に差し替え -- [ ] 仕様変更: 解説AC混在時の背景色分岐 - - [ ] `getRoundLabelClasses` 内の分岐を `getRoundLabelBgColor` ヘルパーに切り出す - - [ ] 全問 AC かつ解説ACあり → `getBackgroundColorFrom('ac_with_editorial')` に変更 - - [ ] 全問 AC かつ解説ACなし → `getBackgroundColorFrom('ac')` を維持 -- [ ] 動作確認 - - [ ] ログインユーザーで全問AC済み(AC のみ)のコンテスト行のラベルが緑背景になること - - [ ] ログインユーザーで全問AC済み(解説ACあり)のコンテスト行のラベルが解説AC背景色になること - - [ ] 未AC・未ログインでは従来色(グレー)のままであること -- [ ] `pnpm format` を実行してコミット +- [x] 仕様変更: 解説AC混在時の背景色分岐 + - [x] `getRoundLabelClasses` 内の分岐を `getRoundLabelBgColor` ヘルパーに切り出す + - [x] 全問 AC かつ解説ACあり → `getBackgroundColorFrom('ac_with_editorial')` に変更 + - [x] 全問 AC かつ解説ACなし → `getBackgroundColorFrom('ac')` を維持 +- [x] 動作確認 + - [x] ログインユーザーで全問AC済み(AC のみ)のコンテスト行のラベルが緑背景になること + - [x] ログインユーザーで全問AC済み(解説ACあり)のコンテスト行のラベルが解説AC背景色になること + - [x] 未AC・未ログインでは従来色(グレー)のままであること +- [x] `pnpm format` を実行(変更なし) +- [x] `pnpm test:unit` — 1908/1909 passed(失敗1件は既存フレイキーテスト: `expects to handle large arrays efficiently`、今回の変更と無関係) diff --git a/src/features/tasks/components/contest-table/TaskTable.svelte b/src/features/tasks/components/contest-table/TaskTable.svelte index ed61b4d31..4dc234c50 100644 --- a/src/features/tasks/components/contest-table/TaskTable.svelte +++ b/src/features/tasks/components/contest-table/TaskTable.svelte @@ -108,14 +108,21 @@ function getRoundLabelClasses(contestTable: ProviderData, contestId: string): string { const tasks = Object.values(contestTable.innerTaskTable[contestId]); - const bgColor = - isLoggedIn && areAllTasksAccepted(tasks, tasks) - ? getBackgroundColorFrom('ac') - : 'bg-gray-50 dark:bg-gray-800'; + const bgColor = getRoundLabelBgColor(tasks); return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center ${bgColor}`; } + function getRoundLabelBgColor(tasks: TaskResults): string { + if (!isLoggedIn || !areAllTasksAccepted(tasks, tasks)) { + return 'bg-gray-50 dark:bg-gray-800'; + } + + const hasEditorial = tasks.some((task) => task.status_name === 'ac_with_editorial'); + + return getBackgroundColorFrom(hasEditorial ? 'ac_with_editorial' : 'ac'); + } + function getBodyCellClasses(taskResult: TaskResult, tableBodyCellWidth: string): string { const backgroundColor = getBackgroundColor(taskResult); From bb9887df994d6b92d7b1f074818cb343489b203f Mon Sep 17 00:00:00 2001 From: Kato Hiroki Date: Tue, 17 Mar 2026 23:06:38 +0000 Subject: [PATCH 5/6] docs: Discard completed plan and add clarifying comment to getRoundLabelBgColor (#3270) Co-Authored-By: Claude Sonnet 4.6 --- .../ac-background-for-round-label/plan.md | 120 ------------------ .../components/contest-table/TaskTable.svelte | 1 + 2 files changed, 1 insertion(+), 120 deletions(-) delete mode 100644 docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md diff --git a/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md b/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md deleted file mode 100644 index 2f3a67027..000000000 --- a/docs/dev-notes/2026-03-17/ac-background-for-round-label/plan.md +++ /dev/null @@ -1,120 +0,0 @@ -# Round ラベルの全問AC時の背景色変更 - -## 概要 - -Issue: https://github.com/AtCoder-NoviSteps/AtCoderNoviSteps/issues/3270 - -コンテストテーブルの Round ラベルセルについて、そのコンテスト行の全問が AC 系(`is_ac === true`)の場合に -ステータスの内訳に応じて背景色を変更する。 - -| 条件 | 背景色 | -| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | -| 全問 `is_ac === true` かつ 1問以上 `ac_with_editorial` | 解説AC背景色 (`bg-atcoder-ac-with_editorial-background dark:bg-atcoder-ac-with_editorial-background_dark`) | -| 全問 `is_ac === true` かつ 全問 `ac` | AC背景色(緑)(`bg-atcoder-ac-background dark:bg-atcoder-ac-background_dark`) | -| それ以外(未AC あり、または未ログイン) | グレー (`bg-gray-50 dark:bg-gray-800`) | - -## 前提 - -- 対象はログインユーザーのみ(未ログイン時は従来の `bg-gray-50 dark:bg-gray-800` を維持) -- 解説AC(`ac_with_editorial`)は `is_ac === true` だが、全問 AC であっても 1 問でも解説AC が混じれば解説AC背景色を優先する -- `areAllTasksAccepted` の既存テストが通っているので、ユーティリティ側の追加テストは不要 - -## 設計メモ - -### データの取り出し方 - -`contestTable.innerTaskTable[contestId]` は `Record` 。 -`generateTable` は実際に存在するタスク結果のみを挿入するため、 -`Object.values(...)` で取得した配列に `undefined` は含まれない。 - -```typescript -const rowTasks: TaskResult[] = Object.values(contestTable.innerTaskTable[contestId]); -areAllTasksAccepted(rowTasks, rowTasks); -// 第1引数(acceptedTasks)を内部で is_ac フィルタ、第2引数(allTasks)をカウント -// 既存テストでも同一配列を両引数に渡すパターンが使われている -``` - -### ヘルパー関数 - -`isLoggedIn` はコンポーネント prop のクロージャ参照。 -全問 AC 判定後、`tasks.some()` で解説AC の有無を確認して背景色を分岐する。 - -```typescript -function getRoundLabelClasses(contestTable: ProviderData, contestId: string): string { - const tasks = Object.values(contestTable.innerTaskTable[contestId]); - const bgColor = getRoundLabelBgColor(tasks); - - return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center ${bgColor}`; -} - -function getRoundLabelBgColor(tasks: TaskResult[]): string { - if (!isLoggedIn || !areAllTasksAccepted(tasks, tasks)) { - return 'bg-gray-50 dark:bg-gray-800'; - } - - const hasEditorial = tasks.some((task) => task.status_name === 'ac_with_editorial'); - return getBackgroundColorFrom(hasEditorial ? 'ac_with_editorial' : 'ac'); -} -``` - -`getRoundLabelBgColor` を独立した関数に切り出すことでテストが書きやすくなる -(ただし `isLoggedIn` をクロージャで参照しているため、引数として渡す設計でも可)。 - -## バグ報告と調査(2026-03-18) - -### 症状 - -ステータスを「挑戦中(WA)→ 解説AC」に変更しても、Round ラベルの背景がリアクティブに緑にならない。 -リロードすると緑になる(= DB には正しく保存されている)。 -「挑戦中(WA)→ AC」は即時反映される。 - -### 原因 - -`src/lib/components/SubmissionStatus/UpdatingDropdown.svelte` の楽観的更新関数 `updateTaskResult` に誤りがある。 - -```typescript -// 誤り(line 161) -is_ac: submissionStatus.innerName === 'ac', -``` - -`ac_with_editorial` を選択すると `'ac_with_editorial' === 'ac'` が `false` になるため、 -楽観的更新後の `TaskResult` は `is_ac: false` のまま。 - -`getRoundLabelClasses` 内の `areAllTasksAccepted` は `is_ac` を参照するため、 -全問 ac_with_editorial でも `false` を返し → ラベルが灰色のまま。 - -リロードすれば DB から `is_ac: true`(`submission_statuses` の `is_AC: true`)が読まれるため正しく緑になる。 - -### 対処 - -`submission_statuses`(同ファイルで既に import 済み)から `is_AC` を参照する。 - -```typescript -// 修正後 -is_ac: - submission_statuses.find((status) => status.status_name === submissionStatus.innerName)?.is_AC ?? - false, -``` - -### 修正ファイル - -- `src/lib/components/SubmissionStatus/UpdatingDropdown.svelte`(line 161)✅ 修正済み - ---- - -## TODO - -- [x] `src/features/tasks/components/contest-table/TaskTable.svelte` - - [x] `areAllTasksAccepted` を `$lib/utils/task` から import に追加 - - [x] `getRoundLabelClasses(contestTable, contestId)` ヘルパー関数を追加(`getBodyCellClasses` の隣) - - [x] `TableBodyCell`(Round ラベル)の `class` を `getRoundLabelClasses(contestTable, contestId)` に差し替え -- [x] 仕様変更: 解説AC混在時の背景色分岐 - - [x] `getRoundLabelClasses` 内の分岐を `getRoundLabelBgColor` ヘルパーに切り出す - - [x] 全問 AC かつ解説ACあり → `getBackgroundColorFrom('ac_with_editorial')` に変更 - - [x] 全問 AC かつ解説ACなし → `getBackgroundColorFrom('ac')` を維持 -- [x] 動作確認 - - [x] ログインユーザーで全問AC済み(AC のみ)のコンテスト行のラベルが緑背景になること - - [x] ログインユーザーで全問AC済み(解説ACあり)のコンテスト行のラベルが解説AC背景色になること - - [x] 未AC・未ログインでは従来色(グレー)のままであること -- [x] `pnpm format` を実行(変更なし) -- [x] `pnpm test:unit` — 1908/1909 passed(失敗1件は既存フレイキーテスト: `expects to handle large arrays efficiently`、今回の変更と無関係) diff --git a/src/features/tasks/components/contest-table/TaskTable.svelte b/src/features/tasks/components/contest-table/TaskTable.svelte index 4dc234c50..07fb34dc3 100644 --- a/src/features/tasks/components/contest-table/TaskTable.svelte +++ b/src/features/tasks/components/contest-table/TaskTable.svelte @@ -113,6 +113,7 @@ return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center ${bgColor}`; } + // Note: If any task is ac_with_editorial, that color takes priority over AC (Accepted). function getRoundLabelBgColor(tasks: TaskResults): string { if (!isLoggedIn || !areAllTasksAccepted(tasks, tasks)) { return 'bg-gray-50 dark:bg-gray-800'; From d19871736a53c07671e4f83c5a9180dc83303472 Mon Sep 17 00:00:00 2001 From: Kato Hiroki Date: Tue, 17 Mar 2026 23:10:37 +0000 Subject: [PATCH 6/6] fix: Add dark:text-gray-300 to Round label for dark mode text color (#3270) Co-Authored-By: Claude Sonnet 4.6 --- src/features/tasks/components/contest-table/TaskTable.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/tasks/components/contest-table/TaskTable.svelte b/src/features/tasks/components/contest-table/TaskTable.svelte index 07fb34dc3..f88932772 100644 --- a/src/features/tasks/components/contest-table/TaskTable.svelte +++ b/src/features/tasks/components/contest-table/TaskTable.svelte @@ -110,7 +110,7 @@ const tasks = Object.values(contestTable.innerTaskTable[contestId]); const bgColor = getRoundLabelBgColor(tasks); - return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center ${bgColor}`; + return `w-full ${contestTable.displayConfig.roundLabelWidth} truncate px-2 py-2 text-center dark:text-gray-300 ${bgColor}`; } // Note: If any task is ac_with_editorial, that color takes priority over AC (Accepted).