このコミットが含まれているのは:
@@ -98,6 +98,7 @@ export type CountsResult = {
|
||||
export type CountSort = { key: string; direction: 'asc' | 'desc' }
|
||||
export type CountField = { key: string; label: string; children?: CountField[]
|
||||
labelValues?: Record<string, string>
|
||||
multipleValues?: boolean
|
||||
nameLocale?: { code: string; languageCode: string; scriptCode: string } }
|
||||
export type CountRecord = Record<string, unknown>
|
||||
|
||||
@@ -335,12 +336,17 @@ export const normaliseCountsParams = (
|
||||
const params = new URLSearchParams (source)
|
||||
if (definition?.nameColumns != null)
|
||||
{
|
||||
const names = definition.nameColumns.map (field => field.key)
|
||||
const names = definition.nameColumns.filter (field => !field.multipleValues)
|
||||
.map (field => field.key)
|
||||
const current = definition.nameColumns.find (field =>
|
||||
field.nameLocale?.code === currentViewingLocale ())?.key
|
||||
!field.multipleValues && field.nameLocale?.code === currentViewingLocale ())?.key
|
||||
const aliases = definition.nameColumns.find (field =>
|
||||
field.multipleValues && field.nameLocale?.code === currentViewingLocale ())?.key
|
||||
const rootKey = (key: string) => (key === 'name' && current != null) ? current
|
||||
: ((key === 'aliases' && aliases != null) ? aliases : key)
|
||||
if (resource === 'tags' && params.has ('columns'))
|
||||
params.set ('columns', params.get ('columns')!.split (' ').flatMap (key =>
|
||||
key === 'names' ? names : [key === 'name' && current != null ? current : key])
|
||||
key === 'names' ? names : [rootKey (key)])
|
||||
.join (' '))
|
||||
if (params.has ('children'))
|
||||
{
|
||||
@@ -348,12 +354,15 @@ export const normaliseCountsParams = (
|
||||
params.set ('children', selected.flatMap (key => {
|
||||
if (['tags.names', 'parents.names'].includes (key))
|
||||
return names.map (name => `${key.slice (0, -6)}.${name}`)
|
||||
if (['tags.aliases', 'parents.aliases'].includes (key) && aliases != null)
|
||||
return [`${key.slice (0, -8)}.${aliases}`]
|
||||
if (key.startsWith ('tags.aliases.') || key.startsWith ('parents.aliases.')) return []
|
||||
return key.startsWith ('tags.names.') || key.startsWith ('parents.names.') ? [] : [key]
|
||||
}).join (' '))
|
||||
}
|
||||
if (resource === 'tags' && params.has ('order'))
|
||||
params.set ('order', params.get ('order')!.split (' ').flatMap (key =>
|
||||
key === 'names' ? names : [key === 'name' && current != null ? current : key])
|
||||
key === 'names' ? names : [rootKey (key)])
|
||||
.join (' '))
|
||||
}
|
||||
for (const [key, value] of params)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createContext, useContext } from 'react'
|
||||
|
||||
import { translateUIMessage } from '@/lib/i18n'
|
||||
import { i18n, translateUIMessage } from '@/lib/i18n'
|
||||
import { apiGet } from '@/lib/api'
|
||||
|
||||
import type { LocaleCode } from '@/lib/locales'
|
||||
@@ -26,6 +26,7 @@ export type CountsFieldMetadata = {
|
||||
labels?: string[]; multiple?: boolean; candidateSource?: 'categories' | 'tags'
|
||||
setType?: 'tag_reference'; inputTypes?: string[]
|
||||
labelValues?: Record<string, string>
|
||||
nameLocale?: CountField['nameLocale']
|
||||
choices?: { value: string; label: string }[] }
|
||||
export type CountsDefinition = {
|
||||
fields: CountsFieldMetadata[]
|
||||
@@ -46,10 +47,48 @@ export const useCountsDefinition = (): CountsDefinition => {
|
||||
}
|
||||
|
||||
|
||||
const localiseCountsDefinition = (
|
||||
definition: CountsDefinition, locale: LocaleCode,
|
||||
): CountsDefinition => {
|
||||
const heading = (name: CountField['nameLocale'], aliasesFlg: boolean) => {
|
||||
if (name == null) return null
|
||||
const key = `languageNames.${name.languageCode}`
|
||||
const language = i18n.exists (key, { ns: 'counts', lng: locale })
|
||||
? translateUIMessage (key, 'counts', locale).text : name.languageCode
|
||||
const scripts = new Set ((definition.nameColumns ?? [])
|
||||
.filter (field => field.nameLocale?.languageCode === name.languageCode)
|
||||
.map (field => field.nameLocale!.scriptCode.toLowerCase ()))
|
||||
const label = aliasesFlg ? 'counts:localeAliases' : 'counts:localeName'
|
||||
return { label: scripts.size > 1 ? `${label}WithScript` : label,
|
||||
labelValues: { language, script: name.scriptCode } }
|
||||
}
|
||||
const columns = (fields: CountField[]): CountField[] => fields.map (field => ({
|
||||
...field, ...heading (field.nameLocale, field.multipleValues === true),
|
||||
...(field.children == null ? { } : { children: columns (field.children) }) }))
|
||||
const metadata = (fields: CountsFieldMetadata[]): CountsFieldMetadata[] =>
|
||||
fields.map (field => {
|
||||
const aliasesFlg = field.key.split ('.').pop()?.startsWith ('aliases_') === true
|
||||
const name = heading (field.nameLocale, aliasesFlg)
|
||||
return name == null ? field : { ...field, labelValues: name.labelValues,
|
||||
labels: field.labels?.map (label =>
|
||||
['counts:localeName', 'counts:localeAliases'].includes (label) ? name.label : label) }
|
||||
})
|
||||
return { ...definition,
|
||||
fields: metadata (definition.fields),
|
||||
...(definition.outputFields == null ? { }
|
||||
: { outputFields: columns (definition.outputFields) }),
|
||||
...(definition.nameColumns == null ? { }
|
||||
: { nameColumns: columns (definition.nameColumns) }),
|
||||
...(definition.filterFields == null ? { }
|
||||
: { filterFields: metadata (definition.filterFields) }) }
|
||||
}
|
||||
|
||||
|
||||
export const fetchCountsDefinition = (
|
||||
resource: CountsResource, locale: LocaleCode = 'ja',
|
||||
): Promise<CountsDefinition> => apiGet (
|
||||
): Promise<CountsDefinition> => apiGet<CountsDefinition> (
|
||||
`/counts/definitions/${encodeURIComponent (resource)}`, { locale })
|
||||
.then (definition => localiseCountsDefinition (definition, locale))
|
||||
|
||||
export type CountsCandidate = {
|
||||
value: string; id?: number; name: string | null; category?: string | null
|
||||
|
||||
@@ -58,6 +58,7 @@ export const countsCellText = (
|
||||
case 'created_at': return date (row.createdAt)
|
||||
default:
|
||||
{
|
||||
if (column.startsWith ('aliases_')) return countsLogicalName (row, column, locale).text
|
||||
const key = column.replace (/_([a-z])/g, (_, letter: string) => letter.toUpperCase ())
|
||||
const value = row[key]
|
||||
if (['discarded_at', 'updated_at'].includes (column) && typeof value === 'string')
|
||||
@@ -123,6 +124,9 @@ export const countsLogicalName = (
|
||||
): { text: string; language?: string } => {
|
||||
const value = countsFieldValue (row, field)
|
||||
if (value == null) return { text: '' }
|
||||
if (field.startsWith ('aliases_') && Array.isArray (value))
|
||||
return { text: value.map (entry => typeof entry === 'string' ? entry
|
||||
: String (entry?.name ?? '')).join ('\n') }
|
||||
if (field === 'sections')
|
||||
return { text: (countsSectionRanges (value, locale) ?? []).join (
|
||||
translateUIMessage ('sections.separator', 'counts', locale).text) }
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする