From d10fae661e5a772fc3a1e063ee13635e1aae9280 Mon Sep 17 00:00:00 2001 From: Diluka W Date: Fri, 17 May 2024 10:36:09 +0800 Subject: [PATCH 1/5] feat(api): add job route --- packages/api/src/handlers/addJob.ts | 23 +++++++++++++++++++++++ packages/api/src/queueAdapters/base.ts | 3 +++ packages/api/src/queueAdapters/bull.ts | 5 +++++ packages/api/src/queueAdapters/bullMQ.ts | 5 +++++ packages/api/src/routes.ts | 6 ++++++ packages/api/typings/app.ts | 6 ++++++ 6 files changed, 48 insertions(+) create mode 100644 packages/api/src/handlers/addJob.ts diff --git a/packages/api/src/handlers/addJob.ts b/packages/api/src/handlers/addJob.ts new file mode 100644 index 00000000..a45810ee --- /dev/null +++ b/packages/api/src/handlers/addJob.ts @@ -0,0 +1,23 @@ +import { BaseAdapter } from '../queueAdapters/base'; +import { BullBoardRequest, ControllerHandlerReturnType } from '../../typings/app'; +import { queueProvider } from '../providers/queue'; +import { formatJob } from './queues'; + +async function addJob( + req: BullBoardRequest, + queue: BaseAdapter +): Promise { + const { name, data, options } = req.body; + + const job = await queue.addJob(name, data, options); + + return { + status: 200, + body: { + job: formatJob(job, queue), + status: job.getState(), + }, + }; +} + +export const addJobHandler = queueProvider(addJob); diff --git a/packages/api/src/queueAdapters/base.ts b/packages/api/src/queueAdapters/base.ts index 82e7d2e9..ecb22a94 100644 --- a/packages/api/src/queueAdapters/base.ts +++ b/packages/api/src/queueAdapters/base.ts @@ -5,6 +5,7 @@ import { JobStatus, QueueAdapterOptions, QueueJob, + QueueJobOptions, Status, } from '../../typings/app'; @@ -45,6 +46,8 @@ export abstract class BaseAdapter { public abstract clean(queueStatus: JobCleanStatus, graceTimeMs: number): Promise; + public abstract addJob(name: string, data: any, options: QueueJobOptions): Promise; + public abstract getJob(id: string): Promise; public abstract getJobCounts(): Promise; diff --git a/packages/api/src/queueAdapters/bull.ts b/packages/api/src/queueAdapters/bull.ts index 7cf30111..af57bbc2 100644 --- a/packages/api/src/queueAdapters/bull.ts +++ b/packages/api/src/queueAdapters/bull.ts @@ -4,6 +4,7 @@ import { JobCounts, JobStatus, QueueAdapterOptions, + QueueJobOptions, Status, } from '../../typings/app'; import { STATUSES } from '../constants/statuses'; @@ -26,6 +27,10 @@ export class BullAdapter extends BaseAdapter { return this.queue.clean(graceTimeMs, jobStatus as any); } + public addJob(name: string, data: any, options: QueueJobOptions) { + return this.queue.add(name, data, options); + } + public getJob(id: string): Promise { return this.queue.getJob(id).then((job) => job && this.alignJobData(job)); } diff --git a/packages/api/src/queueAdapters/bullMQ.ts b/packages/api/src/queueAdapters/bullMQ.ts index 357a9391..d25815f3 100644 --- a/packages/api/src/queueAdapters/bullMQ.ts +++ b/packages/api/src/queueAdapters/bullMQ.ts @@ -4,6 +4,7 @@ import { JobCounts, JobStatus, QueueAdapterOptions, + QueueJobOptions, Status, } from '../../typings/app'; import { STATUSES } from '../constants/statuses'; @@ -27,6 +28,10 @@ export class BullMQAdapter extends BaseAdapter { await this.queue.clean(graceTimeMs, 1000, jobStatus); } + public addJob(name: string, data: any, options: QueueJobOptions) { + return this.queue.add(name, data, options); + } + public getJob(id: string): Promise { return this.queue.getJob(id); } diff --git a/packages/api/src/routes.ts b/packages/api/src/routes.ts index 421b7745..5990488e 100644 --- a/packages/api/src/routes.ts +++ b/packages/api/src/routes.ts @@ -1,4 +1,5 @@ import { AppRouteDefs } from '../typings/app'; +import { addJobHandler } from './handlers/addJob'; import { cleanAllHandler } from './handlers/cleanAll'; import { cleanJobHandler } from './handlers/cleanJob'; import { emptyQueueHandler } from './handlers/emptyQueue'; @@ -33,6 +34,11 @@ export const appRoutes: AppRouteDefs = { route: '/api/queues/:queueName/:jobId', handler: jobHandler, }, + { + method: 'post', + route: '/api/queues/:queueName/add', + handler: addJobHandler, + }, { method: 'put', route: '/api/queues/:queueName/retry/:queueStatus', diff --git a/packages/api/typings/app.ts b/packages/api/typings/app.ts index 7a7244d9..b9601afd 100644 --- a/packages/api/typings/app.ts +++ b/packages/api/typings/app.ts @@ -71,6 +71,11 @@ export interface QueueJobJson { parentKey?: string; } +export interface QueueJobOptions { + delay?: number; + attempts?: number; +} + export interface RedisStats { version: string; mode: RedisInfo['redis_mode']; @@ -127,6 +132,7 @@ export interface BullBoardRequest { queues: BullBoardQueues; query: Record; params: Record; + body: Record; } export type ControllerHandlerReturnType = { From 98c5c798a18480abd71eaac6975294708d9d208e Mon Sep 17 00:00:00 2001 From: Diluka W Date: Fri, 17 May 2024 12:03:01 +0800 Subject: [PATCH 2/5] feat(adapter): pass body --- packages/express/src/ExpressAdapter.ts | 2 ++ packages/fastify/src/FastifyAdapter.ts | 1 + packages/h3/src/H3Adapter.ts | 12 +++++++----- packages/hapi/src/HapiAdapter.ts | 1 + packages/hono/src/HonoAdapter.ts | 1 + packages/koa/src/KoaAdapter.ts | 1 + 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/express/src/ExpressAdapter.ts b/packages/express/src/ExpressAdapter.ts index a74d4aba..55102330 100644 --- a/packages/express/src/ExpressAdapter.ts +++ b/packages/express/src/ExpressAdapter.ts @@ -52,6 +52,7 @@ export class ExpressAdapter implements IServerAdapter { throw new Error(`Please call 'setQueues' before using 'registerPlugin'`); } const router = Router(); + router.use(express.json()); routes.forEach((route) => (Array.isArray(route.method) ? route.method : [route.method]).forEach( @@ -63,6 +64,7 @@ export class ExpressAdapter implements IServerAdapter { queues: this.bullBoardQueues as BullBoardQueues, query: req.query, params: req.params, + body: req.body, }); res.status(response.status || 200).json(response.body); diff --git a/packages/fastify/src/FastifyAdapter.ts b/packages/fastify/src/FastifyAdapter.ts index dbf0b48b..eedaa904 100644 --- a/packages/fastify/src/FastifyAdapter.ts +++ b/packages/fastify/src/FastifyAdapter.ts @@ -139,6 +139,7 @@ export class FastifyAdapter implements IServerAdapter { queues: this.bullBoardQueues as any, params: request.params as any, query: request.query as any, + body: request.body as any, }); return reply.status(response.status || 200).send(response.body); diff --git a/packages/h3/src/H3Adapter.ts b/packages/h3/src/H3Adapter.ts index f5d1f348..d21f22cf 100644 --- a/packages/h3/src/H3Adapter.ts +++ b/packages/h3/src/H3Adapter.ts @@ -3,22 +3,23 @@ import { AppViewRoute, BullBoardQueues, ControllerHandlerReturnType, + HTTPMethod, IServerAdapter, UIConfig, } from '@bull-board/api/dist/typings/app'; +import ejs from 'ejs'; import { readFileSync, statSync } from 'fs'; -import { resolve, normalize } from 'node:path'; import { + createError, createRouter, eventHandler, - getRouterParams, getQuery, + getRouterParams, + readBody, serveStatic, - createError, } from 'h3'; -import ejs from 'ejs'; +import { normalize, resolve } from 'node:path'; import { getContentType } from './utils/getContentType'; -import { HTTPMethod } from '@bull-board/api/dist/typings/app'; export class H3Adapter implements IServerAdapter { private uiHandler = createRouter(); @@ -183,6 +184,7 @@ export class H3Adapter implements IServerAdapter { queues: this.bullBoardQueues as BullBoardQueues, params: getRouterParams(event), query: getQuery(event), + body: readBody(event), }); return body; diff --git a/packages/hapi/src/HapiAdapter.ts b/packages/hapi/src/HapiAdapter.ts index 5d9984c0..d73f4ef6 100644 --- a/packages/hapi/src/HapiAdapter.ts +++ b/packages/hapi/src/HapiAdapter.ts @@ -155,6 +155,7 @@ export class HapiAdapter implements IServerAdapter { queues: this.bullBoardQueues as any, params: request.params as any, query: request.query as any, + body: request.payload as any, }); return h.response(response.body).code(response.status || 200); diff --git a/packages/hono/src/HonoAdapter.ts b/packages/hono/src/HonoAdapter.ts index 20a72a72..fbd6ec85 100644 --- a/packages/hono/src/HonoAdapter.ts +++ b/packages/hono/src/HonoAdapter.ts @@ -106,6 +106,7 @@ export class HonoAdapter implements IServerAdapter { queues: bullBoardQueues, params: c.req.param(), query: c.req.query(), + body: c.req.json(), }); if (response.status == 204) return c.body(null, 204); return c.json(response.body, response.status || 200); diff --git a/packages/koa/src/KoaAdapter.ts b/packages/koa/src/KoaAdapter.ts index 1b7b59b5..208ed0b6 100644 --- a/packages/koa/src/KoaAdapter.ts +++ b/packages/koa/src/KoaAdapter.ts @@ -135,6 +135,7 @@ export class KoaAdapter implements IServerAdapter { queues: this.bullBoardQueues as any, params: ctx.params, query: ctx.query, + body: ctx.body, }); ctx.status = response.status || 200; From 2f8fff532043219d6fcce9f653c55c9a0536b90c Mon Sep 17 00:00:00 2001 From: Diluka W Date: Fri, 17 May 2024 14:33:28 +0800 Subject: [PATCH 3/5] feat(ui): add job modal --- packages/ui/package.json | 2 + .../components/AddJobModal/AddJobModal.tsx | 92 +++++++++++++++++++ .../components/Form/JsonField/JsonField.tsx | 16 ++++ .../HeaderActions/HeaderActions.tsx | 20 +++- packages/ui/src/components/Icons/Add.tsx | 28 ++++++ packages/ui/src/hooks/useQueues.ts | 8 ++ packages/ui/src/services/Api.ts | 13 +++ .../ui/src/static/locales/en-US/messages.json | 9 ++ packages/ui/typings/app.d.ts | 1 + packages/ui/typings/global.d.ts | 4 + yarn.lock | 73 ++++++++++++++- 11 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 packages/ui/src/components/AddJobModal/AddJobModal.tsx create mode 100644 packages/ui/src/components/Form/JsonField/JsonField.tsx create mode 100644 packages/ui/src/components/Icons/Add.tsx diff --git a/packages/ui/package.json b/packages/ui/package.json index 9c462206..8675795e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -65,6 +65,8 @@ "i18next-hmr": "^3.0.3", "i18next-http-backend": "^2.4.2", "i18next-locales-sync": "^2.0.1", + "jsoneditor": "^10.0.3", + "jsoneditor-react": "^3.1.2", "mini-css-extract-plugin": "^2.6.0", "nanoid": "^4.0.1", "postcss": "^8.4.12", diff --git a/packages/ui/src/components/AddJobModal/AddJobModal.tsx b/packages/ui/src/components/AddJobModal/AddJobModal.tsx new file mode 100644 index 00000000..e2ff6913 --- /dev/null +++ b/packages/ui/src/components/AddJobModal/AddJobModal.tsx @@ -0,0 +1,92 @@ +import * as Dialog from '@radix-ui/react-dialog'; +import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useQueues } from '../../hooks/useQueues'; +import { Button } from '../Button/Button'; +import { InputField } from '../Form/InputField/InputField'; +import { JsonField } from '../Form/JsonField/JsonField'; +import { SelectField } from '../Form/SelectField/InputField'; +import { Modal } from '../Modal/Modal'; + +export interface AddJobModalProps { + open: boolean; + + onClose(): void; +} + +export const AddJobModal = ({ open, onClose }: AddJobModalProps) => { + const { actions, queues } = useQueues(); + const [queueName, setQueueName] = useState(''); + const [jobName, setJobName] = useState(''); + const [jobData, setJobData] = useState({}); + const [jobDelay, setJobDelay] = useState(''); + const [jobAttempts, setJobAttempts] = useState(''); + const { t } = useTranslation(); + + useEffect(() => { + if (queues && queues.length) { + setQueueName(queues[0].name); + } + }, [queues]); + + const addJob = () => { + actions.addJob(queueName, jobName || '__default__', jobData, { + delay: jobDelay ? +jobDelay : undefined, + attempts: jobAttempts ? +jobAttempts : undefined, + })(); + }; + + return ( + + + + } + > + ({ + text: queue.name, + value: queue.name, + }))} + value={queueName} + onChange={(event) => setQueueName(event.target.value)} + /> + setJobName(event.target.value)} + /> + setJobData(v)} + /> + setJobDelay(event.target.value)} + /> + setJobAttempts(event.target.value)} + /> + + ); +}; diff --git a/packages/ui/src/components/Form/JsonField/JsonField.tsx b/packages/ui/src/components/Form/JsonField/JsonField.tsx new file mode 100644 index 00000000..00e26477 --- /dev/null +++ b/packages/ui/src/components/Form/JsonField/JsonField.tsx @@ -0,0 +1,16 @@ +import { JsonEditor as Editor } from 'jsoneditor-react'; +import 'jsoneditor-react/es/editor.min.css'; +import React, { HTMLProps } from 'react'; +import { Field } from '../Field/Field'; + +interface JsonFieldProps extends HTMLProps { + label?: string; + value?: any; + onChange?: (v: any) => void; +} + +export const JsonField = ({ label, id, ...props }: JsonFieldProps) => ( + + + +); diff --git a/packages/ui/src/components/HeaderActions/HeaderActions.tsx b/packages/ui/src/components/HeaderActions/HeaderActions.tsx index 459fb416..e7da0f3f 100644 --- a/packages/ui/src/components/HeaderActions/HeaderActions.tsx +++ b/packages/ui/src/components/HeaderActions/HeaderActions.tsx @@ -1,13 +1,14 @@ import React, { useState, Suspense } from 'react'; import { useUIConfig } from '../../hooks/useUIConfig'; import { CustomLinksDropdown } from '../CustomLinksDropdown/CustomLinksDropdown'; +import { AddIcon } from '../Icons/Add'; import { FullscreenIcon } from '../Icons/Fullscreen'; import { RedisIcon } from '../Icons/Redis'; import { Settings } from '../Icons/Settings'; import { Button } from '../Button/Button'; import s from './HeaderActions.module.css'; -type ModalTypes = 'redis' | 'settings'; +type ModalTypes = 'redis' | 'settings' | 'addJobs'; type AllModalTypes = ModalTypes | `${ModalTypes}Closing` | null; function waitForClosingAnimation( @@ -38,6 +39,12 @@ const onClickFullScreen = async () => { return document.exitFullscreen(); }; +const AddJobModalLazy = React.lazy(() => + import('../AddJobModal/AddJobModal').then(({ AddJobModal }) => ({ + default: AddJobModal, + })) +); + export const HeaderActions = () => { const [openedModal, setModalOpen] = useState(null); const { miscLinks = [] } = useUIConfig(); @@ -55,6 +62,11 @@ export const HeaderActions = () => { +
  • + +
  • @@ -63,12 +46,7 @@ export const HeaderActions = () => {
  • - -
  • -
  • -
  • @@ -79,23 +57,11 @@ export const HeaderActions = () => { )} - {(openedModal === 'redis' || openedModal === 'redisClosing') && ( - - )} - {(openedModal === 'settings' || openedModal === 'settingsClosing') && ( - + {modal.isMounted('redis') && ( + )} - {(openedModal === 'addJobs' || openedModal === 'addJobsClosing') && ( - + {modal.isMounted('settings') && ( + )} diff --git a/packages/ui/src/components/Icons/Add.tsx b/packages/ui/src/components/Icons/Add.tsx index 3be7f05f..e7946b4d 100644 --- a/packages/ui/src/components/Icons/Add.tsx +++ b/packages/ui/src/components/Icons/Add.tsx @@ -1,28 +1,7 @@ import React from 'react'; export const AddIcon = () => ( - - - - - - - + + ); diff --git a/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx b/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx index e3597f20..5bcc3477 100644 --- a/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx +++ b/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'; import { QueueActions } from '../../../typings/app'; import { Button } from '../Button/Button'; import { DropdownContent } from '../DropdownContent/DropdownContent'; +import { AddIcon } from '../Icons/Add'; import { EllipsisVerticalIcon } from '../Icons/EllipsisVertical'; import { PauseIcon } from '../Icons/Pause'; import { PlayIcon } from '../Icons/Play'; @@ -16,9 +17,10 @@ export const QueueDropdownActions = ({ actions, }: { queue: AppQueue; - actions: QueueActions; + actions: Omit & { addJob: () => void }; }) => { const { t } = useTranslation(); + return ( @@ -29,6 +31,10 @@ export const QueueDropdownActions = ({ + + + {t('QUEUE.ACTIONS.ADD_JOB')} + { +export const StatusMenu = ({ queue, children }: PropsWithChildren<{ queue: AppQueue }>) => { const { t } = useTranslation(); return ( @@ -29,11 +28,7 @@ export const StatusMenu = ({ queue, actions }: { queue: AppQueue; actions: any } ); })} - {!queue.readOnlyMode && ( -
    - -
    - )} + {!!children &&
    {children}
    } ); }; diff --git a/packages/ui/src/hooks/useModal.ts b/packages/ui/src/hooks/useModal.ts new file mode 100644 index 00000000..97653e54 --- /dev/null +++ b/packages/ui/src/hooks/useModal.ts @@ -0,0 +1,24 @@ +import { useState } from 'react'; + +export function useModal() { + type AllModalTypes = ModalTypes | `${ModalTypes}Closing` | null; + const [openedModal, setModalOpen] = useState(null); + + return { + isOpen(modal: ModalTypes): boolean { + return openedModal === modal; + }, + isMounted(modal: ModalTypes): boolean { + return [modal, `${modal}Closing`].includes(openedModal as any); + }, + open(modal: ModalTypes): void { + setModalOpen(modal); + }, + close(modal: ModalTypes): () => void { + return () => { + setModalOpen(`${modal}Closing`); + setTimeout(() => setModalOpen(null), 300); // fadeout animation duration + }; + }, + }; +} diff --git a/packages/ui/src/pages/QueuePage/QueuePage.tsx b/packages/ui/src/pages/QueuePage/QueuePage.tsx index 521b4880..028ba8b1 100644 --- a/packages/ui/src/pages/QueuePage/QueuePage.tsx +++ b/packages/ui/src/pages/QueuePage/QueuePage.tsx @@ -5,20 +5,29 @@ import { useTranslation } from 'react-i18next'; import { JobCard } from '../../components/JobCard/JobCard'; import { Pagination } from '../../components/Pagination/Pagination'; import { QueueActions } from '../../components/QueueActions/QueueActions'; +import { QueueDropdownActions } from '../../components/QueueDropdownActions/QueueDropdownActions'; import { StatusMenu } from '../../components/StatusMenu/StatusMenu'; import { StickyHeader } from '../../components/StickyHeader/StickyHeader'; import { useActiveQueue } from '../../hooks/useActiveQueue'; import { useJob } from '../../hooks/useJob'; +import { useModal } from '../../hooks/useModal'; import { useQueues } from '../../hooks/useQueues'; import { useSelectedStatuses } from '../../hooks/useSelectedStatuses'; import { links } from '../../utils/links'; +const AddJobModalLazy = React.lazy(() => + import('../../components/AddJobModal/AddJobModal').then(({ AddJobModal }) => ({ + default: AddJobModal, + })) +); + export const QueuePage = () => { const { t } = useTranslation(); const selectedStatus = useSelectedStatuses(); const { actions } = useQueues(); const { actions: jobActions } = useJob(); const queue = useActiveQueue(); + const modal = useModal<'addJob'>(); actions.pollQueues(); if (!queue) { @@ -50,7 +59,14 @@ export const QueuePage = () => { } > - + + {!queue.readOnlyMode && ( + modal.open('addJob') }} + /> + )} + {queue.jobs.map((job) => ( { allowRetries={(job.isFailed || queue.allowCompletedRetries) && queue.allowRetries} /> ))} + {modal.isMounted('addJob') && ( + + )} ); }; diff --git a/packages/ui/src/static/locales/en-US/messages.json b/packages/ui/src/static/locales/en-US/messages.json index 3e5f9dab..27643279 100644 --- a/packages/ui/src/static/locales/en-US/messages.json +++ b/packages/ui/src/static/locales/en-US/messages.json @@ -56,6 +56,7 @@ "RESUME": "Resume", "PAUSE": "Pause", "EMPTY": "Empty", + "ADD_JOB": "Add job", "RETRY_ALL_CONFIRM_MSG": "Are you sure that you want to retry all {{status}} jobs?", "CLEAN_ALL_CONFIRM_MSG": "Are you sure that you want to clean all {{status}} jobs?", "PROMOTE_ALL_CONFIRM_MSG": "Are you sure that you want to promote all delayed jobs?", From 95bc66198f37e137a66e266a6fecd06b3f754765 Mon Sep 17 00:00:00 2001 From: Felix Mosheev <9304194+felixmosh@users.noreply.github.com> Date: Wed, 22 May 2024 11:48:57 +0300 Subject: [PATCH 5/5] feat: add new job to queue --- .eslintrc.js | 1 + packages/api/src/handlers/queues.ts | 1 + packages/api/src/queueAdapters/base.ts | 4 + packages/api/src/queueAdapters/bull.ts | 2 +- packages/api/src/queueAdapters/bullMQ.ts | 2 +- packages/api/typings/app.ts | 3 + packages/ui/package.json | 15 +- .../components/AddJobModal/AddJobModal.tsx | 124 ++--- .../components/Form/JsonField/JsonField.tsx | 14 +- .../{InputField.tsx => SelectField.tsx} | 0 .../src/components/JsonEditor/JsonEditor.tsx | 151 ++++++ .../ui/src/components/Modal/Modal.module.css | 8 +- .../SettingsModal/SettingsModal.tsx | 2 +- packages/ui/src/hooks/useQueues.ts | 12 +- packages/ui/src/schemas/bull/jobOptions.json | 232 +++++++++ .../ui/src/schemas/bullmq/jobOptions.json | 236 ++++++++++ packages/ui/src/services/Api.ts | 4 +- .../ui/src/static/locales/en-US/messages.json | 3 +- packages/ui/src/theme.css | 59 +-- packages/ui/typings/global.d.ts | 4 - yarn.lock | 440 ++++++++++++++---- 21 files changed, 1117 insertions(+), 200 deletions(-) rename packages/ui/src/components/Form/SelectField/{InputField.tsx => SelectField.tsx} (100%) create mode 100644 packages/ui/src/components/JsonEditor/JsonEditor.tsx create mode 100644 packages/ui/src/schemas/bull/jobOptions.json create mode 100644 packages/ui/src/schemas/bullmq/jobOptions.json diff --git a/.eslintrc.js b/.eslintrc.js index f357a79e..276b4082 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -36,6 +36,7 @@ module.exports = { files: ['*.{ts,tsx}'], extends: ['plugin:@typescript-eslint/recommended'], rules: { + '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-use-before-define': 'off', diff --git a/packages/api/src/handlers/queues.ts b/packages/api/src/handlers/queues.ts index 5b022d06..49bf5cfb 100644 --- a/packages/api/src/handlers/queues.ts +++ b/packages/api/src/handlers/queues.ts @@ -89,6 +89,7 @@ async function getAppQueues( allowRetries: queue.allowRetries, allowCompletedRetries: queue.allowCompletedRetries, isPaused, + type: queue.type, }; }) ); diff --git a/packages/api/src/queueAdapters/base.ts b/packages/api/src/queueAdapters/base.ts index ecb22a94..4973d1f0 100644 --- a/packages/api/src/queueAdapters/base.ts +++ b/packages/api/src/queueAdapters/base.ts @@ -6,6 +6,7 @@ import { QueueAdapterOptions, QueueJob, QueueJobOptions, + QueueType, Status, } from '../../typings/app'; @@ -15,9 +16,11 @@ export abstract class BaseAdapter { public readonly allowCompletedRetries: boolean; public readonly prefix: string; public readonly description: string; + public readonly type: QueueType; private formatters = new Map any>(); protected constructor( + type: QueueType, options: Partial = {} ) { this.readOnlyMode = options.readOnlyMode === true; @@ -25,6 +28,7 @@ export abstract class BaseAdapter { this.allowCompletedRetries = this.allowRetries && options.allowCompletedRetries !== false; this.prefix = options.prefix || ''; this.description = options.description || ''; + this.type = type; } public getDescription(): string { diff --git a/packages/api/src/queueAdapters/bull.ts b/packages/api/src/queueAdapters/bull.ts index af57bbc2..bf50c5e1 100644 --- a/packages/api/src/queueAdapters/bull.ts +++ b/packages/api/src/queueAdapters/bull.ts @@ -12,7 +12,7 @@ import { BaseAdapter } from './base'; export class BullAdapter extends BaseAdapter { constructor(public queue: Queue, options: Partial = {}) { - super({ ...options, allowCompletedRetries: false }); + super('bull', { ...options, allowCompletedRetries: false }); } public getRedisInfo(): Promise { diff --git a/packages/api/src/queueAdapters/bullMQ.ts b/packages/api/src/queueAdapters/bullMQ.ts index d25815f3..fa03a730 100644 --- a/packages/api/src/queueAdapters/bullMQ.ts +++ b/packages/api/src/queueAdapters/bullMQ.ts @@ -12,7 +12,7 @@ import { BaseAdapter } from './base'; export class BullMQAdapter extends BaseAdapter { constructor(private queue: Queue, options: Partial = {}) { - super(options); + super('bullmq', options); } public async getRedisInfo(): Promise { diff --git a/packages/api/typings/app.ts b/packages/api/typings/app.ts index b9601afd..299fdd22 100644 --- a/packages/api/typings/app.ts +++ b/packages/api/typings/app.ts @@ -112,6 +112,8 @@ export interface AppJob { isFailed: boolean; } +export type QueueType = 'bull' | 'bullmq'; + export interface AppQueue { name: string; description?: string; @@ -123,6 +125,7 @@ export interface AppQueue { allowRetries: boolean; allowCompletedRetries: boolean; isPaused: boolean; + type: QueueType; } export type HTTPMethod = 'get' | 'post' | 'put'; diff --git a/packages/ui/package.json b/packages/ui/package.json index 8675795e..700aba7e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -26,7 +26,10 @@ "build": "NODE_ENV=production webpack --mode=production", "build:analyze": "NODE_ENV=production ANALYZE=true webpack --mode=production", "clean": "rm -rf dist", - "sync:locales": "npx i18next-locales-sync -c ./localesSync.config.js" + "sync:locales": "npx i18next-locales-sync -c ./localesSync.config.js", + "gen:jsonSchema": "npm run gen:jsonSchema:bullmq && npm run gen:jsonSchema:bull", + "gen:jsonSchema:bullmq": "npx ts-json-schema-generator --path '../../node_modules/bullmq/dist/esm/interfaces/**/*.ts' --type 'JobsOptions' --out './src/schemas/bullmq/jobOptions.json'", + "gen:jsonSchema:bull": "npx ts-json-schema-generator --path '../../node_modules/bull/*.ts' --type 'Bull.JobOptions' --out './src/schemas/bull/jobOptions.json'" }, "dependencies": { "@bull-board/api": "5.17.1" @@ -40,6 +43,13 @@ "@babel/preset-react": "^7.12.13", "@babel/preset-typescript": "^7.13.0", "@babel/runtime": "^7.17.9", + "@codemirror/commands": "^6.5.0", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/language": "^6.10.1", + "@codemirror/lint": "^6.7.1", + "@codemirror/state": "^6.4.1", + "@codemirror/view": "^6.26.3", + "@lezer/common": "^1.2.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5", "@radix-ui/react-alert-dialog": "^1.0.4", "@radix-ui/react-collapsible": "^1.0.3", @@ -54,6 +64,7 @@ "babel-loader": "^9.1.3", "clean-webpack-plugin": "^4.0.0", "clsx": "^1.1.1", + "codemirror-json-schema": "^0.7.2", "copy-webpack-plugin": "^10.2.4", "css-loader": "^6.7.1", "css-minimizer-webpack-plugin": "^3.4.1", @@ -65,8 +76,6 @@ "i18next-hmr": "^3.0.3", "i18next-http-backend": "^2.4.2", "i18next-locales-sync": "^2.0.1", - "jsoneditor": "^10.0.3", - "jsoneditor-react": "^3.1.2", "mini-css-extract-plugin": "^2.6.0", "nanoid": "^4.0.1", "postcss": "^8.4.12", diff --git a/packages/ui/src/components/AddJobModal/AddJobModal.tsx b/packages/ui/src/components/AddJobModal/AddJobModal.tsx index e2ff6913..79867e99 100644 --- a/packages/ui/src/components/AddJobModal/AddJobModal.tsx +++ b/packages/ui/src/components/AddJobModal/AddJobModal.tsx @@ -1,11 +1,14 @@ -import * as Dialog from '@radix-ui/react-dialog'; -import React, { useEffect, useState } from 'react'; +import { AppQueue } from '@bull-board/api/typings/app'; +import React, { FormEvent, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useActiveQueue } from '../../hooks/useActiveQueue'; import { useQueues } from '../../hooks/useQueues'; +import bullJobOptionsSchema from '../../schemas/bull/jobOptions.json'; +import bullMQJobOptionsSchema from '../../schemas/bullmq/jobOptions.json'; import { Button } from '../Button/Button'; import { InputField } from '../Form/InputField/InputField'; import { JsonField } from '../Form/JsonField/JsonField'; -import { SelectField } from '../Form/SelectField/InputField'; +import { SelectField } from '../Form/SelectField/SelectField'; import { Modal } from '../Modal/Modal'; export interface AddJobModalProps { @@ -14,26 +17,38 @@ export interface AddJobModalProps { onClose(): void; } +const jobOptionsSchema = { + bull: bullJobOptionsSchema, + bullmq: bullMQJobOptionsSchema, +} as const; + export const AddJobModal = ({ open, onClose }: AddJobModalProps) => { - const { actions, queues } = useQueues(); - const [queueName, setQueueName] = useState(''); - const [jobName, setJobName] = useState(''); - const [jobData, setJobData] = useState({}); - const [jobDelay, setJobDelay] = useState(''); - const [jobAttempts, setJobAttempts] = useState(''); + const { queues, actions } = useQueues(); + const activeQueue = useActiveQueue(); + const [selectedQueue, setSelectedQueue] = useState(activeQueue); const { t } = useTranslation(); - useEffect(() => { - if (queues && queues.length) { - setQueueName(queues[0].name); - } - }, [queues]); + if (!queues || !activeQueue || !selectedQueue) { + return null; + } + + const addJob = async (evt: FormEvent) => { + evt.preventDefault(); + const form = evt.target as HTMLFormElement; + const formData = Object.fromEntries( + Array.from(form.elements).map((input: any) => [input.name, input.value]) + ); + + formData.jobData = JSON.parse(formData.jobData); + formData.jobOptions = JSON.parse(formData.jobOptions); - const addJob = () => { - actions.addJob(queueName, jobName || '__default__', jobData, { - delay: jobDelay ? +jobDelay : undefined, - attempts: jobAttempts ? +jobAttempts : undefined, - })(); + await actions.addJob( + formData.queueName, + formData.jobName || '__default__', + formData.jobData, + formData.jobOptions + )(); + onClose(); }; return ( @@ -43,50 +58,37 @@ export const AddJobModal = ({ open, onClose }: AddJobModalProps) => { onClose={onClose} title={t('ADD_JOB.TITLE')} actionButton={ - - - + } > - ({ - text: queue.name, - value: queue.name, - }))} - value={queueName} - onChange={(event) => setQueueName(event.target.value)} - /> - setJobName(event.target.value)} - /> - setJobData(v)} - /> - setJobDelay(event.target.value)} - /> - setJobAttempts(event.target.value)} - /> +
    + ({ + text: queue.name, + value: queue.name, + }))} + name="queueName" + value={selectedQueue.name || ''} + onChange={(event) => setSelectedQueue(queues.find((q) => q.name === event.target.value)!)} + /> + + + + ); }; diff --git a/packages/ui/src/components/Form/JsonField/JsonField.tsx b/packages/ui/src/components/Form/JsonField/JsonField.tsx index 00e26477..6aae10d5 100644 --- a/packages/ui/src/components/Form/JsonField/JsonField.tsx +++ b/packages/ui/src/components/Form/JsonField/JsonField.tsx @@ -1,16 +1,14 @@ -import { JsonEditor as Editor } from 'jsoneditor-react'; -import 'jsoneditor-react/es/editor.min.css'; import React, { HTMLProps } from 'react'; +import { JsonEditor } from '../../JsonEditor/JsonEditor'; import { Field } from '../Field/Field'; -interface JsonFieldProps extends HTMLProps { - label?: string; - value?: any; - onChange?: (v: any) => void; +interface JsonFieldProps extends Omit, 'value' | 'ref'> { + value?: Record; + schema?: Record; } -export const JsonField = ({ label, id, ...props }: JsonFieldProps) => ( +export const JsonField = ({ label, id, value, ...rest }: JsonFieldProps) => ( - + ); diff --git a/packages/ui/src/components/Form/SelectField/InputField.tsx b/packages/ui/src/components/Form/SelectField/SelectField.tsx similarity index 100% rename from packages/ui/src/components/Form/SelectField/InputField.tsx rename to packages/ui/src/components/Form/SelectField/SelectField.tsx diff --git a/packages/ui/src/components/JsonEditor/JsonEditor.tsx b/packages/ui/src/components/JsonEditor/JsonEditor.tsx new file mode 100644 index 00000000..7ea89e08 --- /dev/null +++ b/packages/ui/src/components/JsonEditor/JsonEditor.tsx @@ -0,0 +1,151 @@ +import { + autocompletion, + closeBrackets, + closeBracketsKeymap, + completionKeymap, +} from '@codemirror/autocomplete'; +import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'; +import { + bracketMatching, + foldGutter, + foldKeymap, + HighlightStyle, + indentOnInput, + syntaxHighlighting, +} from '@codemirror/language'; +import { diagnosticCount, lintGutter, lintKeymap } from '@codemirror/lint'; +import { Annotation, EditorState } from '@codemirror/state'; +import { + drawSelection, + EditorView, + gutter, + highlightActiveLineGutter, + keymap, + lineNumbers, + ViewUpdate, +} from '@codemirror/view'; +import { tags } from '@lezer/highlight'; +import { jsonSchema, updateSchema } from 'codemirror-json-schema'; +import React, { HTMLProps, useEffect, useRef, useState } from 'react'; + +const customStyle = HighlightStyle.define([ + { tag: tags.atom, color: '#990073' }, + { tag: tags.keyword, color: '#990073' }, + { tag: tags.bool, color: '#990073' }, + { tag: tags.string, color: '#d14' }, + { tag: tags.number, color: 'teal' }, + { tag: tags.brace, color: '#718096' }, + { tag: tags.punctuation, color: '#718096' }, + { tag: tags.propertyName, color: '#458' }, +]); + +const theme = EditorView.theme({ + '&': { + height: '200px', + backgroundColor: '#fff', + border: '1px #d1d5db solid', + borderRadius: '0.375rem', + boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)', + marginTop: '0.25rem', + fontSize: '0.875rem', + transition: 'border-color 0.2s ease-out, box-shadow 0.2s ease-out', + }, + '&.cm-focused': { + outline: 'none', + borderColor: 'hsl(215, 12%, 74%)', + boxShadow: '0 1px 3px hsl(215, 12%, 84%)', + }, + '.cm-gutters': { borderRadius: '0.375rem 0 0 0.375rem' }, + '.cm-scroller': { overflow: 'auto' }, + '.cm-tooltip': { padding: '0.25rem 0.5rem', borderRadius: '0.275rem' }, +}); + +const commonExtensions = [ + gutter({ class: 'CodeMirror-lint-markers' }), + bracketMatching(), + highlightActiveLineGutter(), + // basicSetup, + closeBrackets(), + history(), + autocompletion(), + lineNumbers(), + lintGutter(), + indentOnInput(), + drawSelection(), + foldGutter(), + keymap.of([ + ...closeBracketsKeymap, + ...defaultKeymap, + ...historyKeymap, + ...foldKeymap, + ...completionKeymap, + ...lintKeymap, + ]), + EditorView.lineWrapping, + EditorState.tabSize.of(2), + syntaxHighlighting(customStyle), + theme, +]; + +const External = Annotation.define(); + +interface IJsonEditorProps extends HTMLProps { + doc: Record; + schema?: Record; +} + +export const JsonEditor = ({ doc, schema, ...inputProps }: IJsonEditorProps) => { + const editorRef = useRef(null); + const inputRef = useRef(null); + const [editor, setEditor] = useState(null); + + useEffect(() => { + const onUpdate = EditorView.updateListener.of((vu: ViewUpdate) => { + if (!inputRef.current) { + return; + } + const errorCount = diagnosticCount(vu.state); + + if ( + !vu.docChanged && // waits for linter + !vu.transactions.some((tr) => tr.annotation(External)) && + errorCount === 0 + ) { + const doc = vu.state.doc; + inputRef.current.value = doc.toString(); + } else if (errorCount > 0) { + inputRef.current.value = ''; + } + }); + + const state = EditorState.create({ + doc: JSON.stringify(doc, null, 2), + extensions: [commonExtensions, onUpdate, jsonSchema(schema || {})], + }); + + const editor = new EditorView({ + state, + parent: editorRef.current!, + }); + + setEditor(editor); + + return () => editor.destroy(); + }, []); + + useEffect( + () => { + if (editor) { + updateSchema(editor!, schema || {}); + } + }, + schema ? [schema] : [] + ); + + return ( + <> +
    + + + ); +}; diff --git a/packages/ui/src/components/Modal/Modal.module.css b/packages/ui/src/components/Modal/Modal.module.css index 9e3bcfb6..ca47f879 100644 --- a/packages/ui/src/components/Modal/Modal.module.css +++ b/packages/ui/src/components/Modal/Modal.module.css @@ -88,6 +88,9 @@ background-color: white; border-radius: 0.5rem; padding: 1rem; + max-height: 100%; + display: flex; + flex-direction: column; } .content.wide { @@ -111,6 +114,7 @@ } .description { - margin: 1rem 0; - padding: 0 0.5rem; + margin: 0; + padding: 1rem 0.5rem; + overflow: auto; } diff --git a/packages/ui/src/components/SettingsModal/SettingsModal.tsx b/packages/ui/src/components/SettingsModal/SettingsModal.tsx index c9e1c302..6d9fdb89 100644 --- a/packages/ui/src/components/SettingsModal/SettingsModal.tsx +++ b/packages/ui/src/components/SettingsModal/SettingsModal.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { useSettingsStore } from '../../hooks/useSettings'; import { InputField } from '../Form/InputField/InputField'; -import { SelectField } from '../Form/SelectField/InputField'; +import { SelectField } from '../Form/SelectField/SelectField'; import { SwitchField } from '../Form/SwitchField/SwitchField'; import { Modal } from '../Modal/Modal'; import { availableJobTabs } from '../../hooks/useDetailsTabs'; diff --git a/packages/ui/src/hooks/useQueues.ts b/packages/ui/src/hooks/useQueues.ts index 4e84b345..57c8ab00 100644 --- a/packages/ui/src/hooks/useQueues.ts +++ b/packages/ui/src/hooks/useQueues.ts @@ -108,12 +108,12 @@ export function useQueues(): Omit & { actions: Queu confirmQueueActions ); - const addJob = (queueName: string, jobName:string, jobData: any, jobOptions: any) => - withConfirmAndUpdate( - () => api.addJob(queueName, jobName, jobData, jobOptions), - t('QUEUE.ACTIONS.ADD_JOB_CONFIRM_MSG'), - false - ); + const addJob = ( + queueName: string, + jobName: string, + jobData: Record, + jobOptions: Record + ) => withConfirmAndUpdate(() => api.addJob(queueName, jobName, jobData, jobOptions), '', false); return { queues, diff --git a/packages/ui/src/schemas/bull/jobOptions.json b/packages/ui/src/schemas/bull/jobOptions.json new file mode 100644 index 00000000..17a0baa1 --- /dev/null +++ b/packages/ui/src/schemas/bull/jobOptions.json @@ -0,0 +1,232 @@ +{ + "$ref": "#/definitions/Bull.JobOptions", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "Bull.BackoffOptions": { + "additionalProperties": false, + "properties": { + "delay": { + "description": "Backoff delay, in milliseconds", + "type": "number" + }, + "options": { + "description": "Options for custom strategies" + }, + "type": { + "description": "Backoff type, which can be either `fixed` or `exponential`", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "Bull.JobId": { + "type": [ + "number", + "string" + ] + }, + "Bull.JobOptions": { + "additionalProperties": false, + "properties": { + "attempts": { + "description": "The total number of attempts to try the job until it completes", + "type": "number" + }, + "backoff": { + "anyOf": [ + { + "type": "number" + }, + { + "$ref": "#/definitions/Bull.BackoffOptions" + } + ], + "description": "Backoff setting for automatic retries if the job fails" + }, + "delay": { + "description": "An amount of miliseconds to wait until this job can be processed. Note that for accurate delays, both server and clients should have their clocks synchronized. [optional]", + "type": "number" + }, + "jobId": { + "$ref": "#/definitions/Bull.JobId", + "description": "Override the job ID - by default, the job ID is a unique integer, but you can use this setting to override it. If you use this option, it is up to you to ensure the jobId is unique. If you attempt to add a job with an id that already exists, it will not be added." + }, + "lifo": { + "description": "A boolean which, if true, adds the job to the right of the queue instead of the left (default false)", + "type": "boolean" + }, + "preventParsingData": { + "description": "Prevents JSON data from being parsed.", + "type": "boolean" + }, + "priority": { + "description": "Optional priority value. ranges from 1 (highest priority) to MAX_INT (lowest priority). Note that using priorities has a slight impact on performance, so do not use it if not required", + "type": "number" + }, + "removeOnComplete": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "$ref": "#/definitions/Bull.KeepJobsOptions" + } + ], + "description": "A boolean which, if true, removes the job when it successfully completes. When a number, it specifies the amount of jobs to keep. Default behavior is to keep the job in the completed set. See KeepJobsOptions if using that interface instead." + }, + "removeOnFail": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "$ref": "#/definitions/Bull.KeepJobsOptions" + } + ], + "description": "A boolean which, if true, removes the job when it fails after all attempts. When a number, it specifies the amount of jobs to keep. Default behavior is to keep the job in the failed set. See KeepJobsOptions if using that interface instead." + }, + "repeat": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "count": { + "description": "The start value for the repeat iteration count.", + "type": "number" + }, + "cron": { + "description": "Cron pattern specifying when the job should execute", + "type": "string" + }, + "endDate": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "description": "End date when the repeat job should stop repeating" + }, + "key": { + "description": "The key for the repeatable job metadata in Redis.", + "type": "string" + }, + "limit": { + "description": "Number of times the job should repeat at max.", + "type": "number" + }, + "startDate": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "description": "Start date when the repeat job should start repeating (only with cron)." + }, + "tz": { + "description": "Timezone", + "type": "string" + } + }, + "required": [ + "cron" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "count": { + "description": "The start value for the repeat iteration count.", + "type": "number" + }, + "endDate": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "description": "End date when the repeat job should stop repeating" + }, + "every": { + "description": "Repeat every millis (cron setting cannot be used together with this setting.)", + "type": "number" + }, + "key": { + "description": "The key for the repeatable job metadata in Redis.", + "type": "string" + }, + "limit": { + "description": "Number of times the job should repeat at max.", + "type": "number" + }, + "tz": { + "description": "Timezone", + "type": "string" + } + }, + "required": [ + "every" + ], + "type": "object" + } + ], + "description": "Repeat job according to a cron specification" + }, + "stackTraceLimit": { + "description": "Limits the amount of stack trace lines that will be recorded in the stacktrace.", + "type": "number" + }, + "timeout": { + "description": "The number of milliseconds after which the job should be fail with a timeout error", + "type": "number" + } + }, + "type": "object" + }, + "Bull.KeepJobsOptions": { + "additionalProperties": false, + "description": "Specify which jobs to keep after finishing processing this job. If both age and count are specified, then the jobs kept will be the ones that satisfies both properties.", + "properties": { + "age": { + "description": "Maximum age in *seconds* for job to be kept.", + "type": "number" + }, + "count": { + "description": "Maximum count of jobs to be kept.", + "type": "number" + } + }, + "type": "object" + } + } +} \ No newline at end of file diff --git a/packages/ui/src/schemas/bullmq/jobOptions.json b/packages/ui/src/schemas/bullmq/jobOptions.json new file mode 100644 index 00000000..c371e3f6 --- /dev/null +++ b/packages/ui/src/schemas/bullmq/jobOptions.json @@ -0,0 +1,236 @@ +{ + "$ref": "#/definitions/JobsOptions", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "BackoffOptions": { + "additionalProperties": false, + "description": "Settings for backing off failed jobs.", + "properties": { + "delay": { + "description": "Delay in milliseconds.", + "type": "number" + }, + "type": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "fixed", + "exponential" + ], + "type": "string" + } + ], + "description": "Name of the backoff strategy." + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "DateType": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "JobsOptions": { + "additionalProperties": false, + "properties": { + "attempts": { + "description": "The total number of attempts to try the job until it completes.", + "type": "number" + }, + "backoff": { + "anyOf": [ + { + "type": "number" + }, + { + "$ref": "#/definitions/BackoffOptions" + } + ], + "description": "Backoff setting for automatic retries if the job fails" + }, + "delay": { + "description": "An amount of milliseconds to wait until this job can be processed. Note that for accurate delays, worker and producers should have their clocks synchronized.", + "type": "number" + }, + "failParentOnFailure": { + "description": "If true, moves parent to failed.", + "type": "boolean" + }, + "jobId": { + "description": "Override the job ID - by default, the job ID is a unique integer, but you can use this setting to override it. If you use this option, it is up to you to ensure the jobId is unique. If you attempt to add a job with an id that already exists, it will not be added.", + "type": "string" + }, + "keepLogs": { + "description": "Maximum amount of log entries that will be preserved", + "type": "number" + }, + "lifo": { + "description": "If true, adds the job to the right of the queue instead of the left (default false)", + "type": "boolean" + }, + "parent": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "queue": { + "description": "It includes the prefix, the namespace separator :, and queue name.", + "type": "string" + } + }, + "required": [ + "id", + "queue" + ], + "type": "object" + }, + "prevMillis": { + "description": "Internal property used by repeatable jobs.", + "type": "number" + }, + "priority": { + "description": "Ranges from 1 (highest priority) to 2 097 152 (lowest priority). Note that using priorities has a slight impact on performance, so do not use it if not required.", + "type": "number" + }, + "removeDependencyOnFailure": { + "description": "If true, removes the job from its parent dependencies when it fails after all attempts.", + "type": "boolean" + }, + "removeOnComplete": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "$ref": "#/definitions/KeepJobs" + } + ], + "description": "If true, removes the job when it successfully completes When given a number, it specifies the maximum amount of jobs to keep, or you can provide an object specifying max age and/or count to keep. It overrides whatever setting is used in the worker. Default behavior is to keep the job in the completed set." + }, + "removeOnFail": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "$ref": "#/definitions/KeepJobs" + } + ], + "description": "If true, removes the job when it fails after all attempts. When given a number, it specifies the maximum amount of jobs to keep, or you can provide an object specifying max age and/or count to keep. It overrides whatever setting is used in the worker. Default behavior is to keep the job in the failed set." + }, + "repeat": { + "$ref": "#/definitions/RepeatOptions", + "description": "Repeat this job, for example based on a `cron` schedule." + }, + "repeatJobKey": { + "description": "Internal property used by repeatable jobs to save base repeat job key.", + "type": "string" + }, + "sizeLimit": { + "description": "Limits the size in bytes of the job's data payload (as a JSON serialized string).", + "type": "number" + }, + "stackTraceLimit": { + "description": "Limits the amount of stack trace lines that will be recorded in the stacktrace.", + "type": "number" + }, + "timestamp": { + "description": "Timestamp when the job was created.", + "type": "number" + } + }, + "type": "object" + }, + "KeepJobs": { + "additionalProperties": false, + "description": "KeepJobs\n\nSpecify which jobs to keep after finishing. If both age and count are specified, then the jobs kept will be the ones that satisfies both properties.", + "properties": { + "age": { + "description": "Maximum age in seconds for job to be kept.", + "type": "number" + }, + "count": { + "description": "Maximum count of jobs to be kept.", + "type": "number" + } + }, + "type": "object" + }, + "RepeatOptions": { + "additionalProperties": false, + "description": "Settings for repeatable jobs", + "properties": { + "count": { + "description": "The start value for the repeat iteration count.", + "type": "number" + }, + "currentDate": { + "$ref": "#/definitions/DateType" + }, + "endDate": { + "$ref": "#/definitions/DateType" + }, + "every": { + "description": "Repeat after this amount of milliseconds (`pattern` setting cannot be used together with this setting.)", + "type": "number" + }, + "immediately": { + "description": "Repeated job should start right now ( work only with every settings)", + "type": "boolean" + }, + "jobId": { + "type": "string" + }, + "limit": { + "description": "Number of times the job should repeat at max.", + "type": "number" + }, + "nthDayOfWeek": { + "type": "number" + }, + "offset": { + "type": "number" + }, + "pattern": { + "description": "A repeat pattern", + "type": "string" + }, + "prevMillis": { + "type": "number" + }, + "startDate": { + "$ref": "#/definitions/DateType" + }, + "tz": { + "type": "string" + }, + "utc": { + "type": "boolean" + } + }, + "type": "object" + } + } +} \ No newline at end of file diff --git a/packages/ui/src/services/Api.ts b/packages/ui/src/services/Api.ts index f3572af2..8a2c8a58 100644 --- a/packages/ui/src/services/Api.ts +++ b/packages/ui/src/services/Api.ts @@ -82,8 +82,8 @@ export class Api { public addJob( queueName: string, jobName: string, - jobData: any, - jobOptions: any + jobData: Record, + jobOptions: Record ): Promise { return this.axios.post(`/queues/${encodeURIComponent(queueName)}/add`, { name: jobName, diff --git a/packages/ui/src/static/locales/en-US/messages.json b/packages/ui/src/static/locales/en-US/messages.json index 27643279..dc489229 100644 --- a/packages/ui/src/static/locales/en-US/messages.json +++ b/packages/ui/src/static/locales/en-US/messages.json @@ -122,8 +122,7 @@ "QUEUE_NAME": "Queue name", "JOB_NAME": "Job name", "JOB_DATA": "Job data", - "JOB_DELAY": "delay (ms)", - "JOB_ATTEMPTS": "attempts", + "JOB_OPTIONS": "Job options", "ADD": "Add" } } diff --git a/packages/ui/src/theme.css b/packages/ui/src/theme.css index b2ec5c75..714da218 100644 --- a/packages/ui/src/theme.css +++ b/packages/ui/src/theme.css @@ -1,96 +1,101 @@ .hljs { - display: block; - padding: 0.5em; - white-space: pre-wrap; - word-break: break-all; + display: block; + padding: 0.5em; + white-space: pre-wrap; + word-break: break-all; } .hljs-comment, .hljs-quote { - color: #998; - font-style: italic; + color: #998; + font-style: italic; } .hljs-keyword, .hljs-selector-tag, .hljs-subst { - font-weight: 500; + font-weight: 500; } -.hljs-literal, .hljs-number, .hljs-tag .hljs-attr, .hljs-template-variable, .hljs-variable { - color: teal; + color: teal; } .hljs-doctag, .hljs-string { - color: #d14; + color: #d14; } .hljs-section, .hljs-selector-id, .hljs-title { - color: #d73a49; - font-weight: 500; + color: #d73a49; + font-weight: 500; } .hljs-class .hljs-title, .hljs-type, .hljs-attr { - color: #458; - font-weight: 500; + color: #458; + font-weight: 500; } +.hljs-keyword, .hljs-attribute, .hljs-name, .hljs-tag { - color: navy; - font-weight: 400; + color: navy; + font-weight: 400; } .hljs-link, .hljs-regexp { - color: #009926; + color: #009926; } +.hljs-keyword, .hljs-bullet, .hljs-symbol { - color: #990073; + color: #990073; } .hljs-built_in, .hljs-builtin-name { - color: #0086b3; + color: #0086b3; } .hljs-meta { - color: #999; - font-weight: 500; + color: #999; + font-weight: 500; } .hljs-deletion { - background: #fdd; + background: #fdd; } .hljs-addition { - background: #dfd; + background: #dfd; } .hljs-emphasis { - font-style: italic; + font-style: italic; } .hljs-strong { - font-weight: 500; + font-weight: 500; } .hljs-trace-line { - color: #aaa; + color: #aaa; } .hljs-trace-line .hljs-code-path { - color: #454b52; + color: #454b52; +} + +.hljs-punctuation { + color: #718096; } diff --git a/packages/ui/typings/global.d.ts b/packages/ui/typings/global.d.ts index 8ce1d328..3976bbe9 100644 --- a/packages/ui/typings/global.d.ts +++ b/packages/ui/typings/global.d.ts @@ -2,7 +2,3 @@ declare module '*.css' { const resource: Record; export = resource; } - -declare module 'jsoneditor-react' { - export const JsonEditor: (options: any) => JSX.Element; -} diff --git a/yarn.lock b/yarn.lock index 44e7b74c..7ea919b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1175,11 +1175,108 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@changesets/changelog-github@^0.4.8": + version "0.4.8" + resolved "https://registry.yarnpkg.com/@changesets/changelog-github/-/changelog-github-0.4.8.tgz#b7f8ae85d0c0ff08028d924c5e59a1cbd3742634" + integrity sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw== + dependencies: + "@changesets/get-github-info" "^0.5.2" + "@changesets/types" "^5.2.1" + dotenv "^8.1.0" + +"@changesets/get-github-info@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@changesets/get-github-info/-/get-github-info-0.5.2.tgz#0cde2cadba57db85c714dc303c077da919a574e5" + integrity sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg== + dependencies: + dataloader "^1.4.0" + node-fetch "^2.5.0" + +"@changesets/types@^5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@changesets/types/-/types-5.2.1.tgz#a228c48004aa8a93bce4be2d1d31527ef3bf21f6" + integrity sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg== + "@cloudflare/workers-types@^4.20231218.0": version "4.20231218.0" resolved "https://registry.yarnpkg.com/@cloudflare/workers-types/-/workers-types-4.20231218.0.tgz#3deac906c68aa5c8d8cdefe828146215eed6804c" integrity sha512-Vs1FKjfUjXYGbCsXzkl+ITp0Iyb6QiW6+vTERTNThC+v96T0IvPVAioH4tT20rXwoxAfxh380mAaxYtTrJUNVg== +"@codemirror/autocomplete@^6.0.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.16.0.tgz#595eb30099ba91a835ed65ed8ff7497388f604b3" + integrity sha512-P/LeCTtZHRTCU4xQsa89vSKWecYv1ZqwzOd5topheGRf+qtacFgBeIMQi3eL8Kt/BUNvxUWkx+5qP2jlGoARrg== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.17.0" + "@lezer/common" "^1.0.0" + +"@codemirror/commands@^6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.5.0.tgz#e7dfb7918e7af8889d5731ff4c46ffafd7687353" + integrity sha512-rK+sj4fCAN/QfcY9BEzYMgp4wwL/q5aj/VfNSoH1RWPF9XS/dUwBkvlL3hpWgEjOqlpdN1uLC9UkjJ4tmyjJYg== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.4.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.1.0" + +"@codemirror/lang-json@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-6.0.1.tgz#0a0be701a5619c4b0f8991f9b5e95fe33f462330" + integrity sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ== + dependencies: + "@codemirror/language" "^6.0.0" + "@lezer/json" "^1.0.0" + +"@codemirror/lang-yaml@^6.0.0": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@codemirror/lang-yaml/-/lang-yaml-6.1.1.tgz#6f6e4e16c5a4e6d549f462c9dc2053439e070d0d" + integrity sha512-HV2NzbK9bbVnjWxwObuZh5FuPCowx51mEfoFT9y3y+M37fA3+pbxx4I7uePuygFzDsAmCTwQSc/kXh/flab4uw== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.2.0" + "@lezer/yaml" "^1.0.0" + +"@codemirror/language@^6.0.0", "@codemirror/language@^6.10.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.10.1.tgz#428c932a158cb75942387acfe513c1ece1090b05" + integrity sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.23.0" + "@lezer/common" "^1.1.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + style-mod "^4.0.0" + +"@codemirror/lint@^6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.7.1.tgz#bed4b3a38785678efbe683efe0e61d8ccf478d58" + integrity sha512-rELba6QJD20/bNXWP/cKTGLrwVEcpa2ViwULCV03ONcY1Je85++7sczVRUlnE4TJMjatx3IJTz6HX4NXi+moXw== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" + +"@codemirror/state@^6.0.0", "@codemirror/state@^6.4.0", "@codemirror/state@^6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.4.1.tgz#da57143695c056d9a3c38705ed34136e2b68171b" + integrity sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A== + +"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.26.3": + version "6.26.3" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.26.3.tgz#47aebd49a6ee3c8d36b82046d3bffe6056b8039f" + integrity sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw== + dependencies: + "@codemirror/state" "^6.4.0" + style-mod "^4.1.0" + w3c-keyname "^2.2.4" + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -2912,6 +3009,43 @@ npmlog "^4.1.2" write-file-atomic "^3.0.3" +"@lezer/common@^1.0.0", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0", "@lezer/common@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.1.tgz#198b278b7869668e1bebbe687586e12a42731049" + integrity sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ== + +"@lezer/highlight@^1.0.0", "@lezer/highlight@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.0.tgz#e5898c3644208b4b589084089dceeea2966f7780" + integrity sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA== + dependencies: + "@lezer/common" "^1.0.0" + +"@lezer/json@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@lezer/json/-/json-1.0.2.tgz#bdc849e174113e2d9a569a5e6fb1a27e2f703eaf" + integrity sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ== + dependencies: + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/lr@^1.0.0", "@lezer/lr@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.0.tgz#ed52a75dbbfbb0d1eb63710ea84c35ee647cb67e" + integrity sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg== + dependencies: + "@lezer/common" "^1.0.0" + +"@lezer/yaml@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@lezer/yaml/-/yaml-1.0.3.tgz#b23770ab42b390056da6b187d861b998fd60b1ff" + integrity sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA== + dependencies: + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.4.0" + "@lukeed/csprng@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" @@ -3653,6 +3787,19 @@ dependencies: "@babel/runtime" "^7.13.10" +"@sagold/json-pointer@^5.1.1", "@sagold/json-pointer@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@sagold/json-pointer/-/json-pointer-5.1.2.tgz#7f07884050fd2139eeb5d7423e917160ee7e0b8d" + integrity sha512-+wAhJZBXa6MNxRScg6tkqEbChEHMgVZAhTHVJ60Y7sbtXtu9XA49KfUkdWlS2x78D6H9nryiKePiYozumauPfA== + +"@sagold/json-query@^6.1.3": + version "6.2.0" + resolved "https://registry.yarnpkg.com/@sagold/json-query/-/json-query-6.2.0.tgz#2204a0259ea10f36cd5cb0a1505078e6d751eecd" + integrity sha512-7bOIdUE6eHeoWtFm8TvHQHfTVSZuCs+3RpOKmZCDBIOrxpvF/rNFTeuvIyjHva/RR0yVS3kQtr+9TW72LQEZjA== + dependencies: + "@sagold/json-pointer" "^5.1.2" + ebnf "^1.9.1" + "@sideway/address@^4.1.3": version "4.1.4" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" @@ -3694,11 +3841,6 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@sphinxxxx/color-conversion@^2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz#03ecc29279e3c0c832f6185a5bfa3497858ac8ca" - integrity sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw== - "@szmarczak/http-timer@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" @@ -4016,6 +4158,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/keygrip@*": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" @@ -4123,6 +4270,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.14.tgz#a621ad26e7eb076d6846dd3d39557ddf9d89f04b" integrity sha512-ZE/5aB73CyGqgQULkLG87N9GnyGe5TcQjv34pwS8tfBs1IkCh0ASM69mydb2znqd6v0eX+9Ytvk6oQRqu8T1Vw== +"@types/node@^20.4.2": + version "20.12.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" + integrity sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw== + dependencies: + undici-types "~5.26.4" + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -4551,11 +4705,6 @@ accepts@^1.3.5, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -ace-builds@^1.33.1: - version "1.33.2" - resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.33.2.tgz#4ce274f940491b4825f37881c633f7e0593e010b" - integrity sha512-uDqCe+XDIdnADaDrA8o+x+qAfbM6uqyDQ43QcE6qC7zBPTvQSMOSPcXW+HvjZhEc2YbVYSaxXJX1qQKPgYqi5w== - acorn-import-assertions@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" @@ -4644,7 +4793,7 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6: +ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -5699,6 +5848,38 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== +codemirror-json-schema@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/codemirror-json-schema/-/codemirror-json-schema-0.7.2.tgz#f2f8ea2733bfc55814d8b4f72621e6b5afe92fc9" + integrity sha512-7NY/3bEV3szrp3IqJfFQ7KspZc6WAHs1pFijpy64s8mvteylYfD2AhPUazX7P+j4UkxXdfb9f1Si67dw3by4+g== + dependencies: + "@changesets/changelog-github" "^0.4.8" + "@codemirror/lang-yaml" "^6.0.0" + "@sagold/json-pointer" "^5.1.1" + "@types/json-schema" "^7.0.12" + "@types/node" "^20.4.2" + json-schema "^0.4.0" + json-schema-library "^9.1.2" + markdown-it "^14.0.0" + yaml "^2.3.4" + optionalDependencies: + "@codemirror/lang-json" "^6.0.1" + codemirror-json5 "^1.0.3" + json5 "^2.2.3" + +codemirror-json5@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/codemirror-json5/-/codemirror-json5-1.0.3.tgz#046101609776a97ae3bd0bfc4b9f15638e317793" + integrity sha512-HmmoYO2huQxoaoG5ARKjqQc9mz7/qmNPvMbISVfIE2Gk1+4vZQg9X3G6g49MYM5IK00Ol3aijd7OKrySuOkA7Q== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/highlight" "^1.0.0" + json5 "^2.2.1" + lezer-json5 "^2.0.2" + collect-v8-coverage@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" @@ -5758,7 +5939,7 @@ commander@^10.0.0, commander@^10.0.1: resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== -commander@^2.20.0: +commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -6093,6 +6274,11 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +crelt@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + cron-parser@^4.2.1, cron-parser@^4.6.0: version "4.9.0" resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.9.0.tgz#0340694af3e46a0894978c6f52a6dbb5c0f11ad5" @@ -6290,6 +6476,11 @@ data-uri-to-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz#db89a9e279c2ffe74f50637a59a32fb23b3e4d7c" integrity sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg== +dataloader@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8" + integrity sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw== + date-fns@2.28.0: version "2.28.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" @@ -6388,7 +6579,7 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deepmerge@^4.2.2: +deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== @@ -6571,6 +6762,11 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +discontinuous-range@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" + integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ== + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -6656,6 +6852,11 @@ dot-prop@^6.0.1: dependencies: is-obj "^2.0.0" +dotenv@^8.1.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + duplexer@^0.1.1, duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" @@ -6673,6 +6874,11 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ebnf@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ebnf/-/ebnf-1.9.1.tgz#64c25d8208ec0d221ec11c3c5e8094015131a9d3" + integrity sha512-uW2UKSsuty9ANJ3YByIQE4ANkD8nqUPO7r6Fwcc1ADKPe9FRdcPpMl3VEput4JSvKBJ4J86npIC2MLP0pYkCuw== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -6766,6 +6972,11 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + env-paths@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -7262,6 +7473,11 @@ fast-content-type-parse@^1.0.0: resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-1.0.0.tgz#cddce00df7d7efb3727d375a598e4904bfcb751c" integrity sha512-Xbc4XcysUXcsP5aHUU7Nq3OwvHq97C+WnbkeIefpeYLX+ryzFJlU6OStFJhs6Ol0LkUGpcK+wL0JwfM+FCU5IA== +fast-copy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.2.tgz#59c68f59ccbcac82050ba992e0d5c389097c9d35" + integrity sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ== + fast-decode-uri-component@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" @@ -9126,11 +9342,6 @@ jake@^10.8.5: filelist "^1.0.4" minimatch "^3.1.2" -javascript-natural-sort@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" - integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw== - jest-changed-files@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.6.3.tgz#97cfdc93f74fb8af2a1acb0b78f836f1fb40c449" @@ -9536,11 +9747,6 @@ jest@^29.6.1: import-local "^3.0.2" jest-cli "^29.6.4" -jmespath@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" - integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== - joi@^17.3.0, joi@^17.7.0: version "17.9.2" resolved "https://registry.yarnpkg.com/joi/-/joi-17.9.2.tgz#8b2e4724188369f55451aebd1d0b1d9482470690" @@ -9612,6 +9818,19 @@ json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-schema-library@^9.1.2: + version "9.3.4" + resolved "https://registry.yarnpkg.com/json-schema-library/-/json-schema-library-9.3.4.tgz#e9ed78d289eece9d59bf8157d637e0bced9cd6cb" + integrity sha512-220lm9RVt9BUeF2QhBT711aX4IogUHhPT8Tjhkksc4CUw8WmChFMuf0mJdpDAHDfJDkI064jcZIH8P70HdPAOA== + dependencies: + "@sagold/json-pointer" "^5.1.2" + "@sagold/json-query" "^6.1.3" + deepmerge "^4.3.1" + fast-copy "^3.0.2" + fast-deep-equal "^3.1.3" + smtp-address-parser "1.0.10" + valid-url "^1.0.9" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -9622,16 +9841,11 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@0.4.0: +json-schema@0.4.0, json-schema@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== -json-source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/json-source-map/-/json-source-map-0.6.1.tgz#e0b1f6f4ce13a9ad57e2ae165a24d06e62c79a0f" - integrity sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -9642,33 +9856,11 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^2.1.2, json5@^2.2.3: +json5@^2.1.2, json5@^2.2.1, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsoneditor-react@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/jsoneditor-react/-/jsoneditor-react-3.1.2.tgz#bc36356ac5ecb0d8f88d49a5ccbeecdd7f996164" - integrity sha512-XqU8BMdIhrlS5HUnn7rGhgZw315bdJGQrf6NG5UH40FSw2xNirQrxnM05aeAplHkp8FNkzN2WX0tfvEWdl2UUA== - dependencies: - prop-types "^15.7.2" - -jsoneditor@^10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/jsoneditor/-/jsoneditor-10.0.3.tgz#10a3d5a977e1484bbf089c60894f2bdd26f6fd13" - integrity sha512-dCEtrms+zsIQjDZC5Yo6FBWNvNlXSR2nZ5aprEjawAD689CI8/qqv/Ytj0wPqcz6H1p1ebFfM/wkf8L1wrWk5w== - dependencies: - ace-builds "^1.33.1" - ajv "^6.12.6" - javascript-natural-sort "^0.7.1" - jmespath "^0.16.0" - json-source-map "^0.6.1" - jsonrepair "^3.7.0" - mobius1-selectr "^2.4.13" - picomodal "^3.0.0" - vanilla-picker "^2.12.3" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -9690,11 +9882,6 @@ jsonparse@^1.2.0, jsonparse@^1.3.1: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -jsonrepair@^3.7.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/jsonrepair/-/jsonrepair-3.8.0.tgz#33a1b0d3630c452e9945ef07d760469cdfad8823" - integrity sha512-89lrxpwp+IEcJ6kwglF0HH3Tl17J08JEpYfXnvvjdp4zV4rjSoGu2NdQHxBs7yTOk3ETjTn9du48pBy8iBqj1w== - jsprim@^1.2.2: version "1.4.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" @@ -9915,6 +10102,13 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lezer-json5@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lezer-json5/-/lezer-json5-2.0.2.tgz#ba3756e0d352d9529517dcf264d27db8579ae577" + integrity sha512-NRmtBlKW/f8mA7xatKq8IUOq045t8GVHI4kZXrUtYYUdiVeGiO6zKGAV7/nUAnf5q+rYTY+SWX/gvQdFXMjNxQ== + dependencies: + "@lezer/lr" "^1.0.0" + libnpmaccess@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" @@ -9955,6 +10149,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== + dependencies: + uc.micro "^2.0.0" + load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -10259,6 +10460,18 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== +markdown-it@^14.0.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.0" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" + matcher-collection@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29" @@ -10272,6 +10485,11 @@ mdn-data@2.0.14: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -10531,16 +10749,16 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mobius1-selectr@^2.4.13: - version "2.4.13" - resolved "https://registry.yarnpkg.com/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz#0019dfd9f984840d6e40f70683ab3ec78ce3b5df" - integrity sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw== - modify-values@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== +moo@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c" + integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q== + mrmime@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" @@ -10640,6 +10858,16 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +nearley@^2.20.1: + version "2.20.1" + resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474" + integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ== + dependencies: + commander "^2.19.0" + moo "^0.5.0" + railroad-diagrams "^1.0.0" + randexp "0.4.6" + negotiator@0.6.3, negotiator@^0.6.2: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" @@ -10694,6 +10922,13 @@ node-fetch@3.3.1: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" +node-fetch@^2.5.0, node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.12" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" @@ -10701,13 +10936,6 @@ node-fetch@^2.6.1, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.12: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - node-forge@^1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -11556,11 +11784,6 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -picomodal@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/picomodal/-/picomodal-3.0.0.tgz#facd30f4fbf34a809c1e04ea525f004f399c0b82" - integrity sha512-FoR3TDfuLlqUvcEeK5ifpKSVVns6B4BQvc8SDF6THVMuadya6LLtji0QgUDSStw0ZR2J7I6UGi5V2V23rnPWTw== - pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -12251,7 +12474,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15, prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -12307,6 +12530,11 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + punycode@^2.1.0, punycode@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -12383,6 +12611,19 @@ radix3@^1.1.0: resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.0.tgz#9745df67a49c522e94a33d0a93cf743f104b6e0d" integrity sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A== +railroad-diagrams@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" + integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A== + +randexp@0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" + integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ== + dependencies: + discontinuous-range "1.0.0" + ret "~0.1.10" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -13000,6 +13241,11 @@ restore-cursor@^4.0.0: onetime "^5.1.0" signal-exit "^3.0.2" +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + ret@~0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c" @@ -13357,6 +13603,13 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== +smtp-address-parser@1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/smtp-address-parser/-/smtp-address-parser-1.0.10.tgz#9fc4ed6021f13dc3d8f591e0ad0d50454073025e" + integrity sha512-Osg9LmvGeAG/hyao4mldbflLOkkr3a+h4m1lwKCK5U8M6ZAr7tdXEz/+/vr752TSGE4MNUlUl9cIK2cB8cgzXg== + dependencies: + nearley "^2.20.1" + sockjs@^0.3.24: version "0.3.24" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" @@ -13771,6 +14024,11 @@ style-loader@^3.3.3: resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff" integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== +style-mod@^4.0.0, style-mod@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.2.tgz#ca238a1ad4786520f7515a8539d5a63691d7bf67" + integrity sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw== + stylehacks@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" @@ -14295,6 +14553,11 @@ typescript@^5.1.3, typescript@^5.1.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== + ufo@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.2.tgz#c7d719d0628a1c80c006d2240e0d169f6e3c0496" @@ -14337,6 +14600,11 @@ uncrypto@^0.1.3: resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + unenv@^1.8.0: version "1.9.0" resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.9.0.tgz#469502ae85be1bd3a6aa60f810972b1a904ca312" @@ -14543,6 +14811,11 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" +valid-url@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" + integrity sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA== + validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -14571,13 +14844,6 @@ value-equal@^1.0.1: resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== -vanilla-picker@^2.12.3: - version "2.12.3" - resolved "https://registry.yarnpkg.com/vanilla-picker/-/vanilla-picker-2.12.3.tgz#1cc47b641a2b9c9afc5ac3a9a02febace0f1b17a" - integrity sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ== - dependencies: - "@sphinxxxx/color-conversion" "^2.2.2" - vary@^1.1.2, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -14605,6 +14871,11 @@ void-elements@3.1.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== +w3c-keyname@^2.2.4: + version "2.2.8" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + walk-sync@^2.0.2: version "2.2.0" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-2.2.0.tgz#80786b0657fcc8c0e1c0b1a042a09eae2966387a" @@ -15055,6 +15326,11 @@ yaml@^1.10.0, yaml@^1.10.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.3.4: + version "2.4.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.2.tgz#7a2b30f2243a5fc299e1f14ca58d475ed4bc5362" + integrity sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA== + yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"