このコミットが含まれているのは:
2026-10-18 02:45:26 +09:00
コミット 2d1a8b4730
17個のファイルの変更、488行の追加、326行の削除
+36 -42
ファイルの表示
@@ -11,19 +11,20 @@ import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config'
import { createMaterialSyncSuppression, fetchMaterialSyncSuppressions } from '@/lib/materials'
import { materialsKeys } from '@/lib/queryKeys'
import { dateString, inputClass } from '@/lib/utils'
import { localisedDateString, inputClass } from '@/lib/utils'
import { useUITranslation } from '@/lib/useUITranslation'
import type { FC, FormEvent } from 'react'
import type { MaterialSyncSuppressionSourceKind } from '@/types'
const SOURCE_KIND_LABELS: Record<MaterialSyncSuppressionSourceKind, string> = {
uri: 'URI',
google_drive_path: 'Google Drive ファイル',
google_drive_path_prefix: 'Google Drive フォルダ',
google_drive_file: 'Google Drive ファイル Id.',
legacy_drive_path: '汎用ファイル',
legacy_drive_path_prefix: '汎用フォルダ' }
uri: 'suppressions.sources.uri',
google_drive_path: 'suppressions.sources.google_drive_path',
google_drive_path_prefix: 'suppressions.sources.google_drive_path_prefix',
google_drive_file: 'suppressions.sources.google_drive_file',
legacy_drive_path: 'suppressions.sources.legacy_drive_path',
legacy_drive_path_prefix: 'suppressions.sources.legacy_drive_path_prefix' }
const REASONS = [
'copyright_high_risk',
@@ -37,23 +38,9 @@ const REASONS = [
type MaterialSyncSuppressionReason = typeof REASONS[number]
const REASON_NAMES: Record<MaterialSyncSuppressionReason, string> = {
['copyright_high_risk']: '著作権への懸念',
['copyright_takedown']: '著作者からの申出',
['adult_or_sensitive']: '成人向け',
['personal_information']: '個人情報',
['malware_or_dangerous_file']: '危険なソフトウェア',
['duplicate_or_low_quality']: '重複',
['source_owner_request']: '同期元管理者からの申出',
['other']: 'その他' } as const
const reasonName = (reason: string): string =>
REASON_NAMES[reason as MaterialSyncSuppressionReason] ?? reason
const MaterialSyncSuppressionsPage: FC = () => {
const locale = useLocale ()
const { message, label } = useUITranslation ('materials')
const qc = useQueryClient ()
const [sourceKind, setSourceKind] =
useState<MaterialSyncSuppressionSourceKind> ('uri')
@@ -80,10 +67,10 @@ const MaterialSyncSuppressionsPage: FC = () => {
setSourceUri ('')
setDrivePath ('')
setDriveFileId ('')
toast ({ title: '同期元抑止を登録しました' })
toast ({ title: label ('suppressions.registered') })
},
onError: () => {
toast ({ title: '同期元抑止の登録に失敗しました' })
toast ({ title: label ('suppressions.registerFailed') })
}})
const handleSubmit = (event: FormEvent) => {
@@ -96,11 +83,11 @@ const MaterialSyncSuppressionsPage: FC = () => {
return (
<MainArea>
<Helmet>
<title>{`素材同期抑止 | ${ SITE_TITLE }`}</title>
<title>{message ('suppressions.title').text} | {SITE_TITLE}</title>
</Helmet>
<div className="space-y-5">
<PageTitle>同期抑止</PageTitle>
<PageTitle>{label ('suppressions.heading')}</PageTitle>
<form
onSubmit={handleSubmit}
@@ -108,21 +95,21 @@ const MaterialSyncSuppressionsPage: FC = () => {
text-stone-900 dark:border-stone-700 dark:bg-stone-900
dark:text-stone-100">
<div className="space-y-3">
<FormField label="同期元種別">
<FormField label={label ('suppressions.sourceKind')}>
{({ invalid }) => (
<select
value={sourceKind}
onChange={e => setSourceKind (
e.target.value as MaterialSyncSuppressionSourceKind)}
className={inputClass (invalid)}>
{Object.entries (SOURCE_KIND_LABELS).map (([value, label]) => (
<option key={value} value={value}>
{label}
{Object.entries (SOURCE_KIND_LABELS).map (([value, key]) => (
<option key={value} value={value} lang={message (key).language}>
{message (key).text}
</option>))}
</select>)}
</FormField>
<FormField label="同期元 URI">
<FormField label={label ('suppressions.sourceUri')}>
{({ invalid }) => (
<input
type="text"
@@ -131,7 +118,7 @@ const MaterialSyncSuppressionsPage: FC = () => {
className={inputClass (invalid)}/>)}
</FormField>
<FormField label="Google Drive パス">
<FormField label={label ('suppressions.drivePath')}>
{({ invalid }) => (
<input
type="text"
@@ -140,7 +127,7 @@ const MaterialSyncSuppressionsPage: FC = () => {
className={inputClass (invalid)}/>)}
</FormField>
<FormField label="Google Drive ファイル Id.">
<FormField label={label ('suppressions.driveFileId')}>
{({ invalid }) => (
<input
type="text"
@@ -149,15 +136,16 @@ const MaterialSyncSuppressionsPage: FC = () => {
className={inputClass (invalid)}/>)}
</FormField>
<FormField label="事由">
<FormField label={label ('suppressions.reason')}>
{({ invalid }) => (
<select
value={reason}
onChange={e => setReason (e.target.value as MaterialSyncSuppressionReason)}
className={inputClass (invalid)}>
{REASONS.map (value => (
<option key={value} value={value}>
{REASON_NAMES[value]}
<option key={value} value={value}
lang={message (`suppressions.reasons.${value}`).language}>
{message (`suppressions.reasons.${value}`).text}
</option>))}
</select>)}
</FormField>
@@ -168,14 +156,14 @@ const MaterialSyncSuppressionsPage: FC = () => {
className="mt-4 rounded bg-blue-600 px-4 py-2 text-white
disabled:bg-gray-400"
disabled={createMutation.isPending}>
登録
{label ('suppressions.register')}
</Button>
</form>
{isLoading && <p>Loading...</p>}
{isLoading && <p>{label ('common:loading')}</p>}
{isError && (
<p className="text-red-600 dark:text-red-300">
同期元抑止一覧の取得に失敗しました.
{label ('suppressions.error')}
</p>)}
<div className="space-y-3">
@@ -186,14 +174,20 @@ const MaterialSyncSuppressionsPage: FC = () => {
text-stone-900 shadow-sm dark:border-stone-700
dark:bg-stone-900 dark:text-stone-100">
<div className="font-medium">
{SOURCE_KIND_LABELS[suppression.sourceKind]}
{label (SOURCE_KIND_LABELS[suppression.sourceKind])}
</div>
<div className="break-all text-sm text-stone-700 dark:text-stone-300">
{suppression.normalizedSourceKey}
</div>
<div className="mt-2 text-sm text-stone-600 dark:text-stone-400">
事由: {reasonName (suppression.reason)} /
登録: {dateString (suppression.createdAt)}
{label ('suppressions.reasonPrefix')}
{REASONS.includes (suppression.reason as MaterialSyncSuppressionReason)
? label (`suppressions.reasons.${suppression.reason}`)
: suppression.reason} /{' '}
{label ('suppressions.registeredPrefix')}
<time dateTime={suppression.createdAt} lang={locale}>
{localisedDateString (suppression.createdAt, locale)}
</time>
</div>
</article>))}
</div>