From 4a2c6fb05dc25262d1a5dfdd9d9ba30c45303ab9 Mon Sep 17 00:00:00 2001 From: max747 Date: Fri, 20 Feb 2026 11:13:38 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20reporter=20=E5=90=8D=E8=A7=A3?= =?UTF-8?q?=E6=B1=BA=E3=82=92=20getReporterName=20=E3=81=AB=E7=B5=B1?= =?UTF-8?q?=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reporterSummaryUtils.ts と ReportTable.tsx で重複していた `r.reporterName || r.reporter || "匿名"` を reportTableUtils.ts の getReporterName 関数に統一した。 Co-Authored-By: Claude Sonnet 4.6 --- viewer/src/components/ReportTable.tsx | 6 +++--- viewer/src/reporterSummaryUtils.ts | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/viewer/src/components/ReportTable.tsx b/viewer/src/components/ReportTable.tsx index 2f2e559..9ff799e 100644 --- a/viewer/src/components/ReportTable.tsx +++ b/viewer/src/components/ReportTable.tsx @@ -3,7 +3,7 @@ import { createExcludedIdSet, isOutlier } from "../aggregate"; import { formatItemHeader, formatNote, formatTimestamp } from "../formatters"; import { useSortState } from "../hooks/useSortState"; import type { SortKey } from "../reportTableUtils"; -import { sortReports } from "../reportTableUtils"; +import { getReporterName, sortReports } from "../reportTableUtils"; import type { Exclusion, ItemOutlierStats, ItemStats, Report } from "../types"; import { sortIndicator, @@ -80,13 +80,13 @@ export function ReportTable({ reports, exclusions, itemNames, outlierStats, stat return ( {excluded ? "除外" : "有効"} - + - {r.reporterName || r.reporter || "匿名"} + {getReporterName(r)} {r.runcount} diff --git a/viewer/src/reporterSummaryUtils.ts b/viewer/src/reporterSummaryUtils.ts index 0dac7c6..0493372 100644 --- a/viewer/src/reporterSummaryUtils.ts +++ b/viewer/src/reporterSummaryUtils.ts @@ -1,3 +1,4 @@ +import { getReporterName } from "./reportTableUtils"; import type { ExclusionsMap, QuestData, SortDir } from "./types"; export interface ReportDetail { @@ -33,7 +34,7 @@ export function aggregateReporters( for (const r of qd.reports) { if (excludedIds.has(r.id)) continue; - const name = r.reporterName || r.reporter || "匿名"; + const name = getReporterName(r); const entry = map.get(name) ?? { reporter: name, xId: r.reporter || "", From 5e47c7b757de4966f5446afac1965b601db2c880 Mon Sep 17 00:00:00 2001 From: max747 Date: Fri, 20 Feb 2026 11:13:43 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20VITE=5FDATA=5FURL=20=E6=9C=AA?= =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E6=99=82=E3=81=AB=E6=98=8E=E7=A2=BA=E3=81=AA?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=92=E5=87=BA=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit as string キャストを外し、未設定時に Error をスローする 即時実行関数で検証するよう変更した。 Co-Authored-By: Claude Sonnet 4.6 --- viewer/src/api.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/viewer/src/api.ts b/viewer/src/api.ts index 72dc618..a63c019 100644 --- a/viewer/src/api.ts +++ b/viewer/src/api.ts @@ -1,6 +1,10 @@ import type { EventsResponse, ExclusionsMap, QuestData } from "./types"; -const DATA_URL = import.meta.env.VITE_DATA_URL as string; +const DATA_URL: string = (() => { + const url = import.meta.env.VITE_DATA_URL; + if (!url) throw new Error("VITE_DATA_URL is not set"); + return url; +})(); export async function fetchEvents(signal?: AbortSignal): Promise { const res = await fetch(`${DATA_URL}/events.json`, { signal }); From 44439c69191fc756710c4b5bdceafd48cfd3c3be Mon Sep 17 00:00:00 2001 From: max747 Date: Fri, 20 Feb 2026 11:40:59 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20VITE=5FDATA=5FURL=20=E3=81=AE?= =?UTF-8?q?=E6=A4=9C=E8=A8=BC=E3=82=92=E5=90=84=20fetch=20=E9=96=A2?= =?UTF-8?q?=E6=95=B0=E3=81=AE=E5=91=BC=E3=81=B3=E5=87=BA=E3=81=97=E6=99=82?= =?UTF-8?q?=E3=81=AB=E9=81=85=E5=BB=B6=E5=AE=9F=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IIFE によるモジュール初期化時の同期クラッシュを廃止し、 getDataUrl() 関数に切り出した。async 関数内で呼ぶことで 未設定時のエラーが rejected Promise として伝播し、 AppLayout の error 表示で捕捉できるようになる。 Co-Authored-By: Claude Sonnet 4.6 --- viewer/src/api.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/viewer/src/api.ts b/viewer/src/api.ts index a63c019..ee049ed 100644 --- a/viewer/src/api.ts +++ b/viewer/src/api.ts @@ -1,19 +1,19 @@ import type { EventsResponse, ExclusionsMap, QuestData } from "./types"; -const DATA_URL: string = (() => { +function getDataUrl(): string { const url = import.meta.env.VITE_DATA_URL; if (!url) throw new Error("VITE_DATA_URL is not set"); return url; -})(); +} export async function fetchEvents(signal?: AbortSignal): Promise { - const res = await fetch(`${DATA_URL}/events.json`, { signal }); + const res = await fetch(`${getDataUrl()}/events.json`, { signal }); if (!res.ok) throw new Error(`Failed to fetch events: ${res.status}`); return res.json(); } export async function fetchExclusions(signal?: AbortSignal): Promise { - const res = await fetch(`${DATA_URL}/exclusions.json`, { signal }); + const res = await fetch(`${getDataUrl()}/exclusions.json`, { signal }); if (!res.ok) return {}; return res.json(); } @@ -23,7 +23,7 @@ export async function fetchQuestData( questId: string, signal?: AbortSignal, ): Promise { - const res = await fetch(`${DATA_URL}/${eventId}/${questId}.json`, { signal }); + const res = await fetch(`${getDataUrl()}/${eventId}/${questId}.json`, { signal }); // S3 + CloudFront では未作成のオブジェクトに対して 403 が返るため、 // 404 と同様に「データ未登録」として扱い、エラーではなく null を返す if (res.status === 403 || res.status === 404) return null;