fix(backend): use prefixItems in admin/queue/*-delayed endpoint schema (#14468)
				
					
				
			* fix(backend): represent tuples with `prefixItems` * refactor(frontend): fix type errors * fix(backend): add `prefixItems` in `SchemaType` * fix(backend): add `unevaluatedItems: false` to disallow extra items * refactor(frontend): consolidate `'deliver' | 'queue'` type def into `queue.vue` * fix(backend): add `unevaluatedItems` in `SchemaType`
This commit is contained in:
		| @@ -144,7 +144,9 @@ export interface Schema extends OfSchema { | ||||
| 	readonly type?: TypeStringef; | ||||
| 	readonly nullable?: boolean; | ||||
| 	readonly optional?: boolean; | ||||
| 	readonly prefixItems?: ReadonlyArray<Schema>; | ||||
| 	readonly items?: Schema; | ||||
| 	readonly unevaluatedItems?: Schema | boolean; | ||||
| 	readonly properties?: Obj; | ||||
| 	readonly required?: ReadonlyArray<Extract<keyof NonNullable<this['properties']>, string>>; | ||||
| 	readonly description?: string; | ||||
| @@ -198,6 +200,7 @@ type UnionSchemaType<a extends readonly any[], X extends Schema = a[number]> = X | ||||
| //type UnionObjectSchemaType<a extends readonly any[], X extends Schema = a[number]> = X extends any ? ObjectSchemaType<X> : never; | ||||
| type UnionObjType<s extends Obj, a extends readonly any[], X extends ReadonlyArray<keyof s> = a[number]> = X extends any ? ObjType<s, X> : never; | ||||
| type ArrayUnion<T> = T extends any ? Array<T> : never; | ||||
| type ArrayToTuple<X extends ReadonlyArray<Schema>> = { [K in keyof X]: SchemaType<X[K]> }; | ||||
|  | ||||
| type ObjectSchemaTypeDef<p extends Schema> = | ||||
| 	p['ref'] extends keyof typeof refs ? Packed<p['ref']> : | ||||
| @@ -232,6 +235,12 @@ export type SchemaTypeDef<p extends Schema> = | ||||
| 			p['items']['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] : | ||||
| 			never | ||||
| 		) : | ||||
| 		p['prefixItems'] extends ReadonlyArray<Schema> ? ( | ||||
| 			p['items'] extends NonNullable<Schema> ? [...ArrayToTuple<p['prefixItems']>, ...SchemaType<p['items']>[]] : | ||||
| 			p['items'] extends false ? ArrayToTuple<p['prefixItems']> : | ||||
| 			p['unevaluatedItems'] extends false ? ArrayToTuple<p['prefixItems']> : | ||||
| 			[...ArrayToTuple<p['prefixItems']>, ...unknown[]] | ||||
| 		) : | ||||
| 		p['items'] extends NonNullable<Schema> ? SchemaType<p['items']>[] : | ||||
| 		any[] | ||||
| 	) : | ||||
|   | ||||
| @@ -21,16 +21,15 @@ export const meta = { | ||||
| 		items: { | ||||
| 			type: 'array', | ||||
| 			optional: false, nullable: false, | ||||
| 			items: { | ||||
| 				anyOf: [ | ||||
| 					{ | ||||
| 						type: 'string', | ||||
| 					}, | ||||
| 					{ | ||||
| 						type: 'number', | ||||
| 					}, | ||||
| 				], | ||||
| 			}, | ||||
| 			prefixItems: [ | ||||
| 				{ | ||||
| 					type: 'string', | ||||
| 				}, | ||||
| 				{ | ||||
| 					type: 'number', | ||||
| 				}, | ||||
| 			], | ||||
| 			unevaluatedItems: false, | ||||
| 		}, | ||||
| 		example: [[ | ||||
| 			'example.com', | ||||
|   | ||||
| @@ -21,16 +21,15 @@ export const meta = { | ||||
| 		items: { | ||||
| 			type: 'array', | ||||
| 			optional: false, nullable: false, | ||||
| 			items: { | ||||
| 				anyOf: [ | ||||
| 					{ | ||||
| 						type: 'string', | ||||
| 					}, | ||||
| 					{ | ||||
| 						type: 'number', | ||||
| 					}, | ||||
| 				], | ||||
| 			}, | ||||
| 			prefixItems: [ | ||||
| 				{ | ||||
| 					type: 'string', | ||||
| 				}, | ||||
| 				{ | ||||
| 					type: 'number', | ||||
| 				}, | ||||
| 			], | ||||
| 			unevaluatedItems: false, | ||||
| 		}, | ||||
| 		example: [[ | ||||
| 			'example.com', | ||||
|   | ||||
| @@ -36,7 +36,9 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import XChart from './overview.queue.chart.vue'; | ||||
| import type { ApQueueDomain } from '@/pages/admin/queue.vue'; | ||||
| import number from '@/filters/number.js'; | ||||
| import { useStream } from '@/stream.js'; | ||||
|  | ||||
| @@ -52,10 +54,10 @@ const chartDelayed = shallowRef<InstanceType<typeof XChart>>(); | ||||
| const chartWaiting = shallowRef<InstanceType<typeof XChart>>(); | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	domain: string; | ||||
| 	domain: ApQueueDomain; | ||||
| }>(); | ||||
|  | ||||
| const onStats = (stats) => { | ||||
| function onStats(stats: Misskey.entities.QueueStats) { | ||||
| 	activeSincePrevTick.value = stats[props.domain].activeSincePrevTick; | ||||
| 	active.value = stats[props.domain].active; | ||||
| 	delayed.value = stats[props.domain].delayed; | ||||
| @@ -65,13 +67,13 @@ const onStats = (stats) => { | ||||
| 	chartActive.value.pushData(stats[props.domain].active); | ||||
| 	chartDelayed.value.pushData(stats[props.domain].delayed); | ||||
| 	chartWaiting.value.pushData(stats[props.domain].waiting); | ||||
| }; | ||||
| } | ||||
|  | ||||
| const onStatsLog = (statsLog) => { | ||||
| 	const dataProcess = []; | ||||
| 	const dataActive = []; | ||||
| 	const dataDelayed = []; | ||||
| 	const dataWaiting = []; | ||||
| function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) { | ||||
| 	const dataProcess: Misskey.entities.QueueStats[ApQueueDomain]['activeSincePrevTick'][] = []; | ||||
| 	const dataActive: Misskey.entities.QueueStats[ApQueueDomain]['active'][] = []; | ||||
| 	const dataDelayed: Misskey.entities.QueueStats[ApQueueDomain]['delayed'][] = []; | ||||
| 	const dataWaiting: Misskey.entities.QueueStats[ApQueueDomain]['waiting'][] = []; | ||||
|  | ||||
| 	for (const stats of [...statsLog].reverse()) { | ||||
| 		dataProcess.push(stats[props.domain].activeSincePrevTick); | ||||
| @@ -84,7 +86,7 @@ const onStatsLog = (statsLog) => { | ||||
| 	chartActive.value.setData(dataActive); | ||||
| 	chartDelayed.value.setData(dataDelayed); | ||||
| 	chartWaiting.value.setData(dataWaiting); | ||||
| }; | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
| 	connection.on('stats', onStats); | ||||
|   | ||||
| @@ -49,7 +49,9 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import XChart from './queue.chart.chart.vue'; | ||||
| import type { ApQueueDomain } from '@/pages/admin/queue.vue'; | ||||
| import number from '@/filters/number.js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { useStream } from '@/stream.js'; | ||||
| @@ -62,17 +64,17 @@ const activeSincePrevTick = ref(0); | ||||
| const active = ref(0); | ||||
| const delayed = ref(0); | ||||
| const waiting = ref(0); | ||||
| const jobs = ref<(string | number)[][]>([]); | ||||
| const jobs = ref<Misskey.Endpoints[`admin/queue/${ApQueueDomain}-delayed`]['res']>([]); | ||||
| const chartProcess = shallowRef<InstanceType<typeof XChart>>(); | ||||
| const chartActive = shallowRef<InstanceType<typeof XChart>>(); | ||||
| const chartDelayed = shallowRef<InstanceType<typeof XChart>>(); | ||||
| const chartWaiting = shallowRef<InstanceType<typeof XChart>>(); | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	domain: string; | ||||
| 	domain: ApQueueDomain; | ||||
| }>(); | ||||
|  | ||||
| const onStats = (stats) => { | ||||
| function onStats(stats: Misskey.entities.QueueStats) { | ||||
| 	activeSincePrevTick.value = stats[props.domain].activeSincePrevTick; | ||||
| 	active.value = stats[props.domain].active; | ||||
| 	delayed.value = stats[props.domain].delayed; | ||||
| @@ -82,13 +84,13 @@ const onStats = (stats) => { | ||||
| 	chartActive.value.pushData(stats[props.domain].active); | ||||
| 	chartDelayed.value.pushData(stats[props.domain].delayed); | ||||
| 	chartWaiting.value.pushData(stats[props.domain].waiting); | ||||
| }; | ||||
| } | ||||
|  | ||||
| const onStatsLog = (statsLog) => { | ||||
| 	const dataProcess = []; | ||||
| 	const dataActive = []; | ||||
| 	const dataDelayed = []; | ||||
| 	const dataWaiting = []; | ||||
| function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) { | ||||
| 	const dataProcess: Misskey.entities.QueueStats[ApQueueDomain]['activeSincePrevTick'][] = []; | ||||
| 	const dataActive: Misskey.entities.QueueStats[ApQueueDomain]['active'][] = []; | ||||
| 	const dataDelayed: Misskey.entities.QueueStats[ApQueueDomain]['delayed'][] = []; | ||||
| 	const dataWaiting: Misskey.entities.QueueStats[ApQueueDomain]['waiting'][] = []; | ||||
|  | ||||
| 	for (const stats of [...statsLog].reverse()) { | ||||
| 		dataProcess.push(stats[props.domain].activeSincePrevTick); | ||||
| @@ -101,14 +103,12 @@ const onStatsLog = (statsLog) => { | ||||
| 	chartActive.value.setData(dataActive); | ||||
| 	chartDelayed.value.setData(dataDelayed); | ||||
| 	chartWaiting.value.setData(dataWaiting); | ||||
| }; | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
| 	if (props.domain === 'inbox' || props.domain === 'deliver') { | ||||
| 		misskeyApi(`admin/queue/${props.domain}-delayed`).then(result => { | ||||
| 			jobs.value = result; | ||||
| 		}); | ||||
| 	} | ||||
| 	misskeyApi(`admin/queue/${props.domain}-delayed`).then(result => { | ||||
| 		jobs.value = result; | ||||
| 	}); | ||||
|  | ||||
| 	connection.on('stats', onStats); | ||||
| 	connection.on('statsLog', onStatsLog); | ||||
|   | ||||
| @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { ref, computed } from 'vue'; | ||||
| import { ref, computed, type Ref } from 'vue'; | ||||
| import XQueue from './queue.chart.vue'; | ||||
| import XHeader from './_header_.vue'; | ||||
| import * as os from '@/os.js'; | ||||
| @@ -25,7 +25,9 @@ import { i18n } from '@/i18n.js'; | ||||
| import { definePageMetadata } from '@/scripts/page-metadata.js'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
|  | ||||
| const tab = ref('deliver'); | ||||
| export type ApQueueDomain = 'deliver' | 'inbox'; | ||||
|  | ||||
| const tab: Ref<ApQueueDomain> = ref('deliver'); | ||||
|  | ||||
| function clear() { | ||||
| 	os.confirm({ | ||||
|   | ||||
| @@ -8218,7 +8218,7 @@ export type operations = { | ||||
|       /** @description OK (with results) */ | ||||
|       200: { | ||||
|         content: { | ||||
|           'application/json': ((string | number)[])[]; | ||||
|           'application/json': [string, number][]; | ||||
|         }; | ||||
|       }; | ||||
|       /** @description Client error */ | ||||
| @@ -8264,7 +8264,7 @@ export type operations = { | ||||
|       /** @description OK (with results) */ | ||||
|       200: { | ||||
|         content: { | ||||
|           'application/json': ((string | number)[])[]; | ||||
|           'application/json': [string, number][]; | ||||
|         }; | ||||
|       }; | ||||
|       /** @description Client error */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 zyoshoka
					zyoshoka