素材管理 (#306) #381

マージ済み
みてるぞ が 23 個のコミットを feature/306 から main へマージ 2026-06-28 06:35:53 +09:00
4個のファイルの変更36行の追加53行の削除
コミット 283c20b9da の変更だけを表示してゐます - すべてのコミットを表示
+1
ファイルの表示
@@ -58,6 +58,7 @@ export const menuOutline = (
{ name: '素材', to: '/materials', visible: true, subMenu: [ { name: '素材', to: '/materials', visible: true, subMenu: [
{ name: '一覧', to: '/materials' }, { name: '一覧', to: '/materials' },
{ name: '追加', to: '/materials/new' }, { name: '追加', to: '/materials/new' },
{ name: '抑止', to: '/materials/suppressions' },
{ name: '全体履歴', to: '/materials/changes' }, { name: '全体履歴', to: '/materials/changes' },
{ name: 'ヘルプ', to: '/wiki/ヘルプ:素材管理' }, { name: 'ヘルプ', to: '/wiki/ヘルプ:素材管理' },
{ component: <Separator/>, visible: materialFlg }, { component: <Separator/>, visible: materialFlg },
+3 -8
ファイルの表示
@@ -127,17 +127,12 @@ const MaterialDetailPage: FC = () => {
<audio src={material.file} controls/>)))} <audio src={material.file} controls/>)))}
<TabGroup> <TabGroup>
{material.tag && (
<Tab name="Wiki"> <Tab name="Wiki">
{material.tag
? (
<WikiBody <WikiBody
title={material.tag.name} title={material.tag.name}
body={material.wikiPageBody ?? undefined}/>) body={material.wikiPageBody ?? undefined}/>
: ( </Tab>)}
<p className="text-stone-700 dark:text-stone-300">
</p>)}
</Tab>
<Tab name="編輯"> <Tab name="編輯">
<div className="max-w-wl space-y-4 pt-2"> <div className="max-w-wl space-y-4 pt-2">
+6 -20
ファイルの表示
@@ -41,16 +41,16 @@ const MEDIA_FILTER_LABELS: Record<MaterialIndexMediaKind, string> = {
video: '動画', video: '動画',
audio: '音声', audio: '音声',
file_other: 'その他ファイル', file_other: 'その他ファイル',
url_only: 'URL のみ'} url_only: '外部リンクのみ'}
const SORT_LABELS: Record<MaterialIndexSort, string> = { const SORT_LABELS: Record<MaterialIndexSort, string> = {
created_at: '作成日時', created_at: '作成日時',
updated_at: '更新日時', updated_at: '更新日時',
tag_name: 'タグ名', tag_name: 'タグ名',
media_kind: '種類', media_kind: '種類',
file_byte_size: 'ファイルサイズ', file_byte_size: '容量',
version_no: 'バージョン', version_no: '',
id: 'ID'} id: 'Id.'}
const setIf = (qs: URLSearchParams, key: string, value: string | null) => { const setIf = (qs: URLSearchParams, key: string, value: string | null) => {
@@ -409,21 +409,7 @@ const MaterialListPage: FC = () => {
<div className="flex flex-wrap items-center justify-between gap-3"> <div className="flex flex-wrap items-center justify-between gap-3">
<PageTitle className="my-auto"></PageTitle> <PageTitle className="my-auto"></PageTitle>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
<PrefetchLink {/* <a
to="/materials/new"
className="rounded-full border border-stone-300 bg-white px-4 py-2 text-sm
text-stone-900 hover:bg-stone-100 dark:border-stone-700
dark:bg-stone-900 dark:text-stone-100 dark:hover:bg-stone-800">
</PrefetchLink>
<PrefetchLink
to="/materials/suppressions"
className="rounded-full border border-stone-300 bg-white px-4 py-2 text-sm
text-stone-900 hover:bg-stone-100 dark:border-stone-700
dark:bg-stone-900 dark:text-stone-100 dark:hover:bg-stone-800">
</PrefetchLink>
<a
href={`${ API_BASE_URL }/materials/download.zip?profile=legacy_drive`} href={`${ API_BASE_URL }/materials/download.zip?profile=legacy_drive`}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -431,7 +417,7 @@ const MaterialListPage: FC = () => {
text-stone-900 hover:bg-stone-100 dark:border-stone-700 text-stone-900 hover:bg-stone-100 dark:border-stone-700
dark:bg-stone-900 dark:text-stone-100 dark:hover:bg-stone-800"> dark:bg-stone-900 dark:text-stone-100 dark:hover:bg-stone-800">
ZIP をダウンロード ZIP をダウンロード
</a> </a> */}
</div> </div>
</div> </div>
+25 -24
ファイルの表示
@@ -9,10 +9,7 @@ import MainArea from '@/components/layout/MainArea'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { toast } from '@/components/ui/use-toast' import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config' import { SITE_TITLE } from '@/config'
import { import { createMaterialSyncSuppression, fetchMaterialSyncSuppressions } from '@/lib/materials'
createMaterialSyncSuppression,
fetchMaterialSyncSuppressions,
} from '@/lib/materials'
import { materialsKeys } from '@/lib/queryKeys' import { materialsKeys } from '@/lib/queryKeys'
import { dateString, inputClass } from '@/lib/utils' import { dateString, inputClass } from '@/lib/utils'
@@ -22,11 +19,11 @@ import type { MaterialSyncSuppressionSourceKind } from '@/types'
const SOURCE_KIND_LABELS: Record<MaterialSyncSuppressionSourceKind, string> = { const SOURCE_KIND_LABELS: Record<MaterialSyncSuppressionSourceKind, string> = {
uri: 'URI', uri: 'URI',
google_drive_path: 'Google Drive path', google_drive_path: 'Google Drive ファイル',
google_drive_path_prefix: 'Google Drive path prefix', google_drive_path_prefix: 'Google Drive フォルダ',
google_drive_file: 'Google Drive file ID', google_drive_file: 'Google Drive ファイル Id.',
legacy_drive_path: 'Legacy Drive path', legacy_drive_path: '汎用ファイル',
legacy_drive_path_prefix: 'Legacy Drive path prefix'} legacy_drive_path_prefix: '汎用フォルダ' }
const REASONS = [ const REASONS = [
'copyright_high_risk', 'copyright_high_risk',
@@ -38,6 +35,16 @@ const REASONS = [
'source_owner_request', 'source_owner_request',
'other'] 'other']
const REASON_NAMES = {
['copyright_high_risk']: '著作権への懸念',
['copyright_takedown']: '著作者からの申出',
['adult_or_sensitive']: '成人向け',
['personal_information']: '個人情報',
['malware_or_dangerous_file']: '危険なソフトウェア',
['duplicate_or_low_quality']: '重複',
['source_owner_request']: '同期元管理者からの申出',
['other']: 'その他' }
const MaterialSyncSuppressionsPage: FC = () => { const MaterialSyncSuppressionsPage: FC = () => {
const qc = useQueryClient () const qc = useQueryClient ()
@@ -82,18 +89,11 @@ const MaterialSyncSuppressionsPage: FC = () => {
return ( return (
<MainArea> <MainArea>
<Helmet> <Helmet>
<title>{`同期抑止 | ${ SITE_TITLE }`}</title> <title>{`素材同期抑止 | ${ SITE_TITLE }`}</title>
</Helmet> </Helmet>
<div className="space-y-5"> <div className="space-y-5">
<div className="flex flex-wrap items-center justify-between gap-3"> <PageTitle></PageTitle>
<PageTitle></PageTitle>
<PrefetchLink
to="/materials"
className="text-sm text-sky-700 underline underline-offset-2 dark:text-sky-300">
</PrefetchLink>
</div>
<form <form
onSubmit={handleSubmit} onSubmit={handleSubmit}
@@ -115,7 +115,7 @@ const MaterialSyncSuppressionsPage: FC = () => {
</select>)} </select>)}
</FormField> </FormField>
<FormField label="Source URI"> <FormField label="同期元 URI">
{({ invalid }) => ( {({ invalid }) => (
<input <input
type="text" type="text"
@@ -124,7 +124,7 @@ const MaterialSyncSuppressionsPage: FC = () => {
className={inputClass (invalid)}/>)} className={inputClass (invalid)}/>)}
</FormField> </FormField>
<FormField label="Drive path"> <FormField label="Google Drive パス">
{({ invalid }) => ( {({ invalid }) => (
<input <input
type="text" type="text"
@@ -133,7 +133,7 @@ const MaterialSyncSuppressionsPage: FC = () => {
className={inputClass (invalid)}/>)} className={inputClass (invalid)}/>)}
</FormField> </FormField>
<FormField label="Drive file ID"> <FormField label="Google Drive ファイル Id.">
{({ invalid }) => ( {({ invalid }) => (
<input <input
type="text" type="text"
@@ -142,7 +142,7 @@ const MaterialSyncSuppressionsPage: FC = () => {
className={inputClass (invalid)}/>)} className={inputClass (invalid)}/>)}
</FormField> </FormField>
<FormField label="由"> <FormField label="由">
{({ invalid }) => ( {({ invalid }) => (
<select <select
value={reason} value={reason}
@@ -150,7 +150,7 @@ const MaterialSyncSuppressionsPage: FC = () => {
className={inputClass (invalid)}> className={inputClass (invalid)}>
{REASONS.map (value => ( {REASONS.map (value => (
<option key={value} value={value}> <option key={value} value={value}>
{value} {REASON_NAMES[value]}
</option>))} </option>))}
</select>)} </select>)}
</FormField> </FormField>
@@ -185,7 +185,8 @@ const MaterialSyncSuppressionsPage: FC = () => {
{suppression.normalizedSourceKey} {suppression.normalizedSourceKey}
</div> </div>
<div className="mt-2 text-sm text-stone-600 dark:text-stone-400"> <div className="mt-2 text-sm text-stone-600 dark:text-stone-400">
: {suppression.reason} / : {dateString (suppression.createdAt)} : {REASON_NAMES[suppression.reason]} /
: {dateString (suppression.createdAt)}
</div> </div>
</article>))} </article>))}
</div> </div>