このコミットが含まれているのは:
2026-10-26 21:53:09 +09:00
コミット 1154babe45
22個のファイルの変更、537行の追加、145行の削除
+35 -7
ファイルの表示
@@ -1,7 +1,7 @@
import { countsFieldLabel } from '@/lib/countsDefinitions'
import { countsFieldLabel, readCountsJSON } from '@/lib/countsDefinitions'
import { apiDownload, apiGet } from '@/lib/api'
import type { CountsDefinition } from '@/lib/countsDefinitions'
import type { CountsAxis, CountsDefinition } from '@/lib/countsDefinitions'
import type { LocaleCode } from '@/lib/locales'
import type { TagNameSnapshot } from '@/types'
@@ -55,7 +55,13 @@ export type CountsStateTotals = {
assignments: number | null
deprecatedTags: number | null
externalAssignments: number | null }
export type CountsPivotHeader = { values: (string | number | null)[]
kind: 'data' | 'subtotal' | 'grand_total' }
export type CountsResult = {
rowHeaders?: CountsPivotHeader[]
columnHeaders?: CountsPivotHeader[]
pivotTotals?: { row: (string | number | null)[]; column: (string | number | null)[]
count: number }[]
executionAt?: string
columnValues?: (string | number | null)[][]
cells?: { values: (string | number | null)[]; count: number }[]
@@ -83,11 +89,10 @@ export type CountRecord = Record<string, unknown>
export const countColumns: Record<string, string> = {
event_type: 'counts:eventType',
thumbnail: 'counts:columns.thumbnailDisplay', resource_id: 'counts:columns.resourceId',
version_no: 'history:version', is_latest: 'counts:columns.latest',
version_no: 'counts:columns.version', is_latest: 'counts:columns.latest',
title: 'counts:columns.postTitle', url: 'counts:columns.postURL',
thumbnail_base: 'counts:columns.thumbnailURL', tags: 'counts:columns.tags',
parents: 'shared:labels.parentPosts', video_ms: 'shared:labels.duration',
original_created_at: 'shared:labels.originalCreatedAt',
original_created_from: 'counts:columns.originalFrom',
original_created_before: 'counts:columns.originalBefore',
name: 'history:tagName', names: 'counts:columns.names',
@@ -144,7 +149,7 @@ export const columnsForCounts = (
'resource_id', 'version_no', 'is_latest',
...(resource === 'posts'
? ['title', 'url', 'thumbnail_base', 'tags', 'parents', 'video_ms',
'original_created_at', 'original_created_from', 'original_created_before']
'original_created_from', 'original_created_before']
: (resource === 'tags'
? ['name', 'names', 'category', 'aliases', 'parents', 'deprecated']
: (definition?.fields.filter (field => ![
@@ -206,6 +211,7 @@ export const selectedCountColumns = (
params: URLSearchParams,
definition?: CountsDefinition,
): CountColumn[] => {
const resolved = normaliseCountsParams (resource, params, definition)
const common = ['resource_id', 'version_no', 'event_type', 'user', 'created_at']
const defaults: Record<CountsResource, string[]> = {
posts: ['title', 'url', 'tags', 'parents', 'video_ms'],
@@ -214,9 +220,9 @@ export const selectedCountColumns = (
tag_descriptions: ['language_code', 'body', 'source_language_code'],
tag_groups: ['name', 'description', 'members'],
materials: ['url', 'source_kind', 'tag_id'] }
const selected = params.has ('columns') ? params.get ('columns')!.split (',')
const selected = resolved.has ('columns') ? resolved.get ('columns')!.split (',')
: [...common, ...defaults[resource]]
return orderedCountFields (fieldsForCounts (resource, definition), params)
return orderedCountFields (fieldsForCounts (resource, definition), resolved)
.map (field => field.key as CountColumn).filter (key => selected.includes (key))
}
@@ -281,6 +287,7 @@ export const defaultCountsMode = (definition: string | null): 'summary' | 'detai
export const normaliseCountsParams = (
resource: CountsResource,
source: URLSearchParams,
definition?: CountsDefinition,
): URLSearchParams => {
const params = new URLSearchParams (source)
if (!params.has ('definition'))
@@ -306,6 +313,27 @@ export const normaliseCountsParams = (
params.set ('columns', columnsForCounts (resource).filter (key => selected.has (key))
.join (','))
}
if (params.has ('sort'))
params.set ('sort', params.get ('sort')!.split (',')
.filter (entry => entry.split (':')[0] !== 'original_created_at').join (','))
if (params.has ('order'))
params.set ('order', params.get ('order')!.split (',')
.filter (key => key !== 'original_created_at').join (','))
const defaults = definition?.defaults?.find (entry =>
entry.definition === params.get ('definition') && entry.mode === params.get ('mode'))
for (const { key, value } of defaults?.params ?? [])
{
if (params.has (key)) continue
if (key === 'sort')
{
const expected = defaults?.params.find (entry => entry.key === 'rows')?.value
const axes = readCountsJSON<CountsAxis[]> (params, 'rows', [])
const first = expected == null ? null : (JSON.parse (expected) as CountsAxis[])[0]
if (!Array.isArray (axes) || axes[0]?.field !== first?.field
|| (axes[0]?.grain ?? 'month') !== (first?.grain ?? 'month')) continue
}
params.set (key, value)
}
return params
}