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:
parent
06855f769f
commit
7fe3035059
|
@ -144,7 +144,9 @@ export interface Schema extends OfSchema {
|
||||||
readonly type?: TypeStringef;
|
readonly type?: TypeStringef;
|
||||||
readonly nullable?: boolean;
|
readonly nullable?: boolean;
|
||||||
readonly optional?: boolean;
|
readonly optional?: boolean;
|
||||||
|
readonly prefixItems?: ReadonlyArray<Schema>;
|
||||||
readonly items?: Schema;
|
readonly items?: Schema;
|
||||||
|
readonly unevaluatedItems?: Schema | boolean;
|
||||||
readonly properties?: Obj;
|
readonly properties?: Obj;
|
||||||
readonly required?: ReadonlyArray<Extract<keyof NonNullable<this['properties']>, string>>;
|
readonly required?: ReadonlyArray<Extract<keyof NonNullable<this['properties']>, string>>;
|
||||||
readonly description?: 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 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 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 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> =
|
type ObjectSchemaTypeDef<p extends Schema> =
|
||||||
p['ref'] extends keyof typeof refs ? Packed<p['ref']> :
|
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']>>>[] :
|
p['items']['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] :
|
||||||
never
|
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']>[] :
|
p['items'] extends NonNullable<Schema> ? SchemaType<p['items']>[] :
|
||||||
any[]
|
any[]
|
||||||
) :
|
) :
|
||||||
|
|
|
@ -21,8 +21,7 @@ export const meta = {
|
||||||
items: {
|
items: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
items: {
|
prefixItems: [
|
||||||
anyOf: [
|
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
|
@ -30,7 +29,7 @@ export const meta = {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
unevaluatedItems: false,
|
||||||
},
|
},
|
||||||
example: [[
|
example: [[
|
||||||
'example.com',
|
'example.com',
|
||||||
|
|
|
@ -21,8 +21,7 @@ export const meta = {
|
||||||
items: {
|
items: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
items: {
|
prefixItems: [
|
||||||
anyOf: [
|
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
|
@ -30,7 +29,7 @@ export const meta = {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
unevaluatedItems: false,
|
||||||
},
|
},
|
||||||
example: [[
|
example: [[
|
||||||
'example.com',
|
'example.com',
|
||||||
|
|
|
@ -36,7 +36,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
import XChart from './overview.queue.chart.vue';
|
import XChart from './overview.queue.chart.vue';
|
||||||
|
import type { ApQueueDomain } from '@/pages/admin/queue.vue';
|
||||||
import number from '@/filters/number.js';
|
import number from '@/filters/number.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
|
|
||||||
|
@ -52,10 +54,10 @@ const chartDelayed = shallowRef<InstanceType<typeof XChart>>();
|
||||||
const chartWaiting = shallowRef<InstanceType<typeof XChart>>();
|
const chartWaiting = shallowRef<InstanceType<typeof XChart>>();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
domain: string;
|
domain: ApQueueDomain;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const onStats = (stats) => {
|
function onStats(stats: Misskey.entities.QueueStats) {
|
||||||
activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
|
activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
|
||||||
active.value = stats[props.domain].active;
|
active.value = stats[props.domain].active;
|
||||||
delayed.value = stats[props.domain].delayed;
|
delayed.value = stats[props.domain].delayed;
|
||||||
|
@ -65,13 +67,13 @@ const onStats = (stats) => {
|
||||||
chartActive.value.pushData(stats[props.domain].active);
|
chartActive.value.pushData(stats[props.domain].active);
|
||||||
chartDelayed.value.pushData(stats[props.domain].delayed);
|
chartDelayed.value.pushData(stats[props.domain].delayed);
|
||||||
chartWaiting.value.pushData(stats[props.domain].waiting);
|
chartWaiting.value.pushData(stats[props.domain].waiting);
|
||||||
};
|
}
|
||||||
|
|
||||||
const onStatsLog = (statsLog) => {
|
function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) {
|
||||||
const dataProcess = [];
|
const dataProcess: Misskey.entities.QueueStats[ApQueueDomain]['activeSincePrevTick'][] = [];
|
||||||
const dataActive = [];
|
const dataActive: Misskey.entities.QueueStats[ApQueueDomain]['active'][] = [];
|
||||||
const dataDelayed = [];
|
const dataDelayed: Misskey.entities.QueueStats[ApQueueDomain]['delayed'][] = [];
|
||||||
const dataWaiting = [];
|
const dataWaiting: Misskey.entities.QueueStats[ApQueueDomain]['waiting'][] = [];
|
||||||
|
|
||||||
for (const stats of [...statsLog].reverse()) {
|
for (const stats of [...statsLog].reverse()) {
|
||||||
dataProcess.push(stats[props.domain].activeSincePrevTick);
|
dataProcess.push(stats[props.domain].activeSincePrevTick);
|
||||||
|
@ -84,7 +86,7 @@ const onStatsLog = (statsLog) => {
|
||||||
chartActive.value.setData(dataActive);
|
chartActive.value.setData(dataActive);
|
||||||
chartDelayed.value.setData(dataDelayed);
|
chartDelayed.value.setData(dataDelayed);
|
||||||
chartWaiting.value.setData(dataWaiting);
|
chartWaiting.value.setData(dataWaiting);
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
connection.on('stats', onStats);
|
connection.on('stats', onStats);
|
||||||
|
|
|
@ -49,7 +49,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
import XChart from './queue.chart.chart.vue';
|
import XChart from './queue.chart.chart.vue';
|
||||||
|
import type { ApQueueDomain } from '@/pages/admin/queue.vue';
|
||||||
import number from '@/filters/number.js';
|
import number from '@/filters/number.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
|
@ -62,17 +64,17 @@ const activeSincePrevTick = ref(0);
|
||||||
const active = ref(0);
|
const active = ref(0);
|
||||||
const delayed = ref(0);
|
const delayed = ref(0);
|
||||||
const waiting = 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 chartProcess = shallowRef<InstanceType<typeof XChart>>();
|
||||||
const chartActive = shallowRef<InstanceType<typeof XChart>>();
|
const chartActive = shallowRef<InstanceType<typeof XChart>>();
|
||||||
const chartDelayed = shallowRef<InstanceType<typeof XChart>>();
|
const chartDelayed = shallowRef<InstanceType<typeof XChart>>();
|
||||||
const chartWaiting = shallowRef<InstanceType<typeof XChart>>();
|
const chartWaiting = shallowRef<InstanceType<typeof XChart>>();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
domain: string;
|
domain: ApQueueDomain;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const onStats = (stats) => {
|
function onStats(stats: Misskey.entities.QueueStats) {
|
||||||
activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
|
activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
|
||||||
active.value = stats[props.domain].active;
|
active.value = stats[props.domain].active;
|
||||||
delayed.value = stats[props.domain].delayed;
|
delayed.value = stats[props.domain].delayed;
|
||||||
|
@ -82,13 +84,13 @@ const onStats = (stats) => {
|
||||||
chartActive.value.pushData(stats[props.domain].active);
|
chartActive.value.pushData(stats[props.domain].active);
|
||||||
chartDelayed.value.pushData(stats[props.domain].delayed);
|
chartDelayed.value.pushData(stats[props.domain].delayed);
|
||||||
chartWaiting.value.pushData(stats[props.domain].waiting);
|
chartWaiting.value.pushData(stats[props.domain].waiting);
|
||||||
};
|
}
|
||||||
|
|
||||||
const onStatsLog = (statsLog) => {
|
function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) {
|
||||||
const dataProcess = [];
|
const dataProcess: Misskey.entities.QueueStats[ApQueueDomain]['activeSincePrevTick'][] = [];
|
||||||
const dataActive = [];
|
const dataActive: Misskey.entities.QueueStats[ApQueueDomain]['active'][] = [];
|
||||||
const dataDelayed = [];
|
const dataDelayed: Misskey.entities.QueueStats[ApQueueDomain]['delayed'][] = [];
|
||||||
const dataWaiting = [];
|
const dataWaiting: Misskey.entities.QueueStats[ApQueueDomain]['waiting'][] = [];
|
||||||
|
|
||||||
for (const stats of [...statsLog].reverse()) {
|
for (const stats of [...statsLog].reverse()) {
|
||||||
dataProcess.push(stats[props.domain].activeSincePrevTick);
|
dataProcess.push(stats[props.domain].activeSincePrevTick);
|
||||||
|
@ -101,14 +103,12 @@ const onStatsLog = (statsLog) => {
|
||||||
chartActive.value.setData(dataActive);
|
chartActive.value.setData(dataActive);
|
||||||
chartDelayed.value.setData(dataDelayed);
|
chartDelayed.value.setData(dataDelayed);
|
||||||
chartWaiting.value.setData(dataWaiting);
|
chartWaiting.value.setData(dataWaiting);
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.domain === 'inbox' || props.domain === 'deliver') {
|
|
||||||
misskeyApi(`admin/queue/${props.domain}-delayed`).then(result => {
|
misskeyApi(`admin/queue/${props.domain}-delayed`).then(result => {
|
||||||
jobs.value = result;
|
jobs.value = result;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
connection.on('stats', onStats);
|
connection.on('stats', onStats);
|
||||||
connection.on('statsLog', onStatsLog);
|
connection.on('statsLog', onStatsLog);
|
||||||
|
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, type Ref } from 'vue';
|
||||||
import XQueue from './queue.chart.vue';
|
import XQueue from './queue.chart.vue';
|
||||||
import XHeader from './_header_.vue';
|
import XHeader from './_header_.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
@ -25,7 +25,9 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
|
||||||
const tab = ref('deliver');
|
export type ApQueueDomain = 'deliver' | 'inbox';
|
||||||
|
|
||||||
|
const tab: Ref<ApQueueDomain> = ref('deliver');
|
||||||
|
|
||||||
function clear() {
|
function clear() {
|
||||||
os.confirm({
|
os.confirm({
|
||||||
|
|
|
@ -8218,7 +8218,7 @@ export type operations = {
|
||||||
/** @description OK (with results) */
|
/** @description OK (with results) */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
'application/json': ((string | number)[])[];
|
'application/json': [string, number][];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Client error */
|
/** @description Client error */
|
||||||
|
@ -8264,7 +8264,7 @@ export type operations = {
|
||||||
/** @description OK (with results) */
|
/** @description OK (with results) */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
'application/json': ((string | number)[])[];
|
'application/json': [string, number][];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Client error */
|
/** @description Client error */
|
||||||
|
|
Loading…
Reference in New Issue