このコミットが含まれているのは:
@@ -1,42 +1,41 @@
|
||||
import { createContext, useContext } from 'react'
|
||||
|
||||
import { apiGet } from '@/lib/api'
|
||||
|
||||
import type { CountField, CountsResource } from '@/lib/counts'
|
||||
|
||||
export type CountsAxis = { field: string; grain?: string }
|
||||
export type CountsCondition = {
|
||||
field: string; operator: string; value?: string; end?: string; blank?: boolean }
|
||||
export type CountsFieldType = 'string' | 'integer' | 'datetime' | 'enum' | 'json'
|
||||
export type CountsFieldType = 'string' | 'integer' | 'datetime' | 'enum' | 'json' | 'boolean'
|
||||
|
||||
export const countsResources: CountsResource[] = [
|
||||
'posts', 'tags', 'nico_tags', 'tag_descriptions', 'tag_groups', 'materials']
|
||||
export const countsGrains = ['year', 'quarter', 'month', 'week', 'day', 'hour']
|
||||
export const countsOperators: Record<CountsFieldType, string[]> = {
|
||||
string: ['eq', 'ne', 'like'], enum: ['eq', 'ne'], json: [],
|
||||
integer: ['eq', 'ne', 'gt', 'lt', 'ge', 'le', 'range'],
|
||||
datetime: ['eq', 'ne', 'gt', 'lt', 'ge', 'le', 'range'] }
|
||||
export type CountsFieldMetadata = {
|
||||
key: string; type: CountsFieldType; nullable: boolean; operators: string[] }
|
||||
export type CountsDefinition = {
|
||||
fields: CountsFieldMetadata[]
|
||||
axes: { latest: string[]; history: string[] }
|
||||
grains: string[] }
|
||||
|
||||
export const countsAttributes: Record<CountsResource, Record<string, CountsFieldType>> = {
|
||||
posts: { title: 'string', url: 'string', thumbnail_base: 'string', tags_json: 'json',
|
||||
parent_post_ids: 'string', video_ms: 'integer', original_created_from: 'datetime',
|
||||
original_created_before: 'datetime' },
|
||||
tags: { name: 'string', names: 'json', category: 'enum', aliases: 'string',
|
||||
parent_tag_ids: 'string', deprecated_at: 'datetime' },
|
||||
nico_tags: { name: 'string', linked_tags: 'string' },
|
||||
tag_descriptions: { language_code: 'enum', body: 'string', source_language_code: 'enum',
|
||||
source_version_no: 'integer' },
|
||||
tag_groups: { name: 'string', description: 'string', members: 'json', placements: 'json' },
|
||||
materials: { url: 'string', parent_id: 'integer', tag_id: 'integer', tag_name: 'string',
|
||||
tag_category: 'enum', discarded_at: 'datetime', updated_at: 'datetime',
|
||||
updated_by_user_id: 'integer', export_paths_json: 'json', file_blob_id: 'integer',
|
||||
file_filename: 'string', file_content_type: 'string', file_byte_size: 'integer',
|
||||
file_checksum: 'string', file_sha256: 'string', source_kind: 'enum', source_uri: 'string',
|
||||
source_path: 'string', source_file_id: 'string', normalized_source_key: 'string' } }
|
||||
export const CountsDefinitionContext = createContext<CountsDefinition | null> (null)
|
||||
|
||||
|
||||
export const useCountsDefinition = (): CountsDefinition => {
|
||||
const definition = useContext (CountsDefinitionContext)
|
||||
if (definition == null) throw new Error ('Missing Counts definition')
|
||||
return definition
|
||||
}
|
||||
|
||||
|
||||
export const fetchCountsDefinition = (resource: CountsResource): Promise<CountsDefinition> =>
|
||||
apiGet (`/counts/definitions/${encodeURIComponent (resource)}`)
|
||||
|
||||
|
||||
export const countsFilterFields = (
|
||||
resource: CountsResource,
|
||||
): Record<string, CountsFieldType> => ({
|
||||
resource_id: 'integer' as const, version_no: 'integer' as const,
|
||||
event_type: 'enum' as const, user: 'integer' as const, created_at: 'datetime' as const,
|
||||
...countsAttributes[resource] })
|
||||
definition: CountsDefinition,
|
||||
): Record<string, CountsFieldType> => Object.fromEntries (
|
||||
definition.fields.map (field => [field.key, field.type]))
|
||||
|
||||
|
||||
export const countsFieldLabel = (key: string): string => {
|
||||
@@ -52,12 +51,11 @@ export const countsFieldLabel = (key: string): string => {
|
||||
}
|
||||
|
||||
|
||||
export const countsAxisFields = (resource: CountsResource, history: boolean): CountField[] => [
|
||||
...Object.entries (countsFilterFields (resource))
|
||||
.filter (([, type]) => type !== 'json')
|
||||
.map (([key]) => ({ key, label: countsFieldLabel (key) })),
|
||||
...(resource === 'posts' ? [{ key: 'tags', label: 'columns.tags' }] : []),
|
||||
...(history ? [{ key: 'changed_field', label: 'changedField' }] : [])]
|
||||
export const countsAxisFields = (
|
||||
definition: CountsDefinition,
|
||||
history: boolean,
|
||||
): CountField[] => definition.axes[history ? 'history' : 'latest']
|
||||
.map (key => ({ key, label: countsFieldLabel (key) }))
|
||||
|
||||
|
||||
export const readCountsJSON = <T,> (params: URLSearchParams, key: string, fallback: T): T => {
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする