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 = { 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; 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..4c98b9c2 --- /dev/null +++ b/packages/ui/src/components/AddJobModal/AddJobModal.tsx @@ -0,0 +1,81 @@ +import { AppQueue } from '@bull-board/api/dist/typings/app'; +import * as Dialog from '@radix-ui/react-dialog'; +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { QueueActions } from '../../../typings/app'; +import { Button } from '../Button/Button'; +import { InputField } from '../Form/InputField/InputField'; +import { JsonField } from '../Form/JsonField/JsonField'; +import { Modal } from '../Modal/Modal'; + +export interface AddJobModalProps { + open: boolean; + + onClose(): void; + + actions: QueueActions; + queue: AppQueue; +} + +export const AddJobModal = ({ open, onClose, actions, queue }: AddJobModalProps) => { + const [isValid, setValid] = useState(true); + const [jobName, setJobName] = useState(''); + const [jobData, setJobData] = useState({}); + const [jobDelay, setJobDelay] = useState(''); + const [jobAttempts, setJobAttempts] = useState(''); + const { t } = useTranslation(); + + const addJob = () => { + actions.addJob(queue.name, jobName || '__default__', jobData, { + delay: jobDelay ? +jobDelay : undefined, + attempts: jobAttempts ? +jobAttempts : undefined, + })(); + }; + + return ( + + + + } + > + setJobName(event.target.value)} + /> + setJobData(v)} + onValidationError={(errors) => setValid(!errors.length)} + /> + 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..f7fe6afb --- /dev/null +++ b/packages/ui/src/components/Form/JsonField/JsonField.tsx @@ -0,0 +1,17 @@ +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; + onValidationError?: (errors: Error[]) => void; +} + +export const JsonField = ({ label, id, ...props }: JsonFieldProps) => ( + + + +); diff --git a/packages/ui/src/components/Icons/Add.tsx b/packages/ui/src/components/Icons/Add.tsx new file mode 100644 index 00000000..3be7f05f --- /dev/null +++ b/packages/ui/src/components/Icons/Add.tsx @@ -0,0 +1,28 @@ +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..ac105eb0 100644 --- a/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx +++ b/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx @@ -1,16 +1,36 @@ import { AppQueue } from '@bull-board/api/typings/app'; import { Item, Portal, Root, Trigger } from '@radix-ui/react-dropdown-menu'; -import React from 'react'; +import React, { Suspense, useState } from 'react'; 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'; import { TrashIcon } from '../Icons/Trash'; import s from './QueueDropdownActions.module.css'; +type ModalTypes = 'addJobs'; +type AllModalTypes = ModalTypes | `${ModalTypes}Closing` | null; + +function waitForClosingAnimation( + state: ModalTypes, + setModalOpen: (newState: AllModalTypes) => void +) { + return () => { + setModalOpen(`${state}Closing`); + setTimeout(() => setModalOpen(null), 300); // fadeout animation duration + }; +} + +const AddJobModalLazy = React.lazy(() => + import('../AddJobModal/AddJobModal').then(({ AddJobModal }) => ({ + default: AddJobModal, + })) +); + export const QueueDropdownActions = ({ queue, actions, @@ -19,6 +39,7 @@ export const QueueDropdownActions = ({ actions: QueueActions; }) => { const { t } = useTranslation(); + const [openedModal, setModalOpen] = useState(null); return ( @@ -29,6 +50,10 @@ export const QueueDropdownActions = ({ + setModalOpen('addJobs')}> + + {t('QUEUE.ACTIONS.ADD_JOB')} + + + {(openedModal === 'addJobs' || openedModal === 'addJobsClosing') && ( + + )} + ); }; diff --git a/packages/ui/src/hooks/useQueues.ts b/packages/ui/src/hooks/useQueues.ts index dda34fdd..4e84b345 100644 --- a/packages/ui/src/hooks/useQueues.ts +++ b/packages/ui/src/hooks/useQueues.ts @@ -108,6 +108,13 @@ 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 + ); + return { queues, loading, @@ -120,6 +127,7 @@ export function useQueues(): Omit & { actions: Queu pauseQueue, resumeQueue, emptyQueue, + addJob, }, }; } diff --git a/packages/ui/src/services/Api.ts b/packages/ui/src/services/Api.ts index 5975d57e..f3572af2 100644 --- a/packages/ui/src/services/Api.ts +++ b/packages/ui/src/services/Api.ts @@ -79,6 +79,19 @@ export class Api { ); } + public addJob( + queueName: string, + jobName: string, + jobData: any, + jobOptions: any + ): Promise { + return this.axios.post(`/queues/${encodeURIComponent(queueName)}/add`, { + name: jobName, + data: jobData, + options: jobOptions, + }); + } + public pauseQueue(queueName: string) { return this.axios.put(`/queues/${encodeURIComponent(queueName)}/pause`); } diff --git a/packages/ui/src/static/locales/en-US/messages.json b/packages/ui/src/static/locales/en-US/messages.json index 07bdff50..163fc311 100644 --- a/packages/ui/src/static/locales/en-US/messages.json +++ b/packages/ui/src/static/locales/en-US/messages.json @@ -61,7 +61,8 @@ "PROMOTE_ALL_CONFIRM_MSG": "Are you sure that you want to promote all delayed jobs?", "PAUSE_QUEUE_CONFIRM_MSG": "Are you sure that you want to pause queue processing?", "EMPTY_QUEUE_CONFIRM_MSG": "Are you sure that you want to empty the queue?", - "RESUME_QUEUE_CONFIRM_MSG": "Are you sure that you want to resume queue processing?" + "RESUME_QUEUE_CONFIRM_MSG": "Are you sure that you want to resume queue processing?", + "ADD_JOB": "Add job" }, "STATUS": { "LATEST": "Latest", @@ -115,5 +116,13 @@ "COLLAPSE_JOB_DATA": "Collapse job data", "COLLAPSE_JOB_OPTIONS": "Collapse job options", "COLLAPSE_JOB_ERROR": "Collapse job error" + }, + "ADD_JOB": { + "TITLE": "Add job", + "JOB_NAME": "Job name", + "JOB_DATA": "Job data", + "JOB_DELAY": "delay (ms)", + "JOB_ATTEMPTS": "attempts", + "ADD": "Add" } } diff --git a/packages/ui/typings/app.d.ts b/packages/ui/typings/app.d.ts index 39b6784d..add0ba1b 100644 --- a/packages/ui/typings/app.d.ts +++ b/packages/ui/typings/app.d.ts @@ -19,6 +19,7 @@ export interface QueueActions { emptyQueue: (queueName: string) => () => Promise; updateQueues: () => Promise; pollQueues: () => void; + addJob: (queueName: string, jobName: string, jobData: any, jobOptions: any) => () => Promise; } export interface JobActions { diff --git a/packages/ui/typings/global.d.ts b/packages/ui/typings/global.d.ts index 3976bbe9..8ce1d328 100644 --- a/packages/ui/typings/global.d.ts +++ b/packages/ui/typings/global.d.ts @@ -2,3 +2,7 @@ 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 ed68a4f3..44e7b74c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3694,6 +3694,11 @@ 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" @@ -4546,6 +4551,11 @@ 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" @@ -4634,7 +4644,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.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -9116,6 +9126,11 @@ 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" @@ -9521,6 +9536,11 @@ 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" @@ -9607,6 +9627,11 @@ json-schema@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" @@ -9622,6 +9647,28 @@ json5@^2.1.2, json5@^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" @@ -9643,6 +9690,11 @@ 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" @@ -10479,6 +10531,11 @@ 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" @@ -11499,6 +11556,11 @@ 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" @@ -12189,7 +12251,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15, prop-types@^15.6.2, prop-types@^15.8.1: +prop-types@^15, prop-types@^15.6.2, prop-types@^15.7.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== @@ -14509,6 +14571,13 @@ 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"