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..52bddfb1 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", diff --git a/packages/ui/src/components/AddJobModal/AddJobModal.tsx b/packages/ui/src/components/AddJobModal/AddJobModal.tsx index 4c98b9c2..79867e99 100644 --- a/packages/ui/src/components/AddJobModal/AddJobModal.tsx +++ b/packages/ui/src/components/AddJobModal/AddJobModal.tsx @@ -1,35 +1,54 @@ -import { AppQueue } from '@bull-board/api/dist/typings/app'; -import * as Dialog from '@radix-ui/react-dialog'; -import React, { useState } from 'react'; +import { AppQueue } from '@bull-board/api/typings/app'; +import React, { FormEvent, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { QueueActions } from '../../../typings/app'; +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/SelectField'; 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 jobOptionsSchema = { + bull: bullJobOptionsSchema, + bullmq: bullMQJobOptionsSchema, +} as const; + +export const AddJobModal = ({ open, onClose }: AddJobModalProps) => { + const { queues, actions } = useQueues(); + const activeQueue = useActiveQueue(); + const [selectedQueue, setSelectedQueue] = useState(activeQueue); const { t } = useTranslation(); - const addJob = () => { - actions.addJob(queue.name, jobName || '__default__', jobData, { - delay: jobDelay ? +jobDelay : undefined, - attempts: jobAttempts ? +jobAttempts : undefined, - })(); + 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); + + await actions.addJob( + formData.queueName, + formData.jobName || '__default__', + formData.jobData, + formData.jobOptions + )(); + onClose(); }; return ( @@ -39,43 +58,37 @@ export const AddJobModal = ({ open, onClose, actions, queue }: AddJobModalProps) onClose={onClose} title={t('ADD_JOB.TITLE')} actionButton={ - - - + } > - setJobName(event.target.value)} - /> - setJobData(v)} - onValidationError={(errors) => setValid(!errors.length)} - /> - 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 f7fe6afb..6aae10d5 100644 --- a/packages/ui/src/components/Form/JsonField/JsonField.tsx +++ b/packages/ui/src/components/Form/JsonField/JsonField.tsx @@ -1,17 +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; - onValidationError?: (errors: Error[]) => 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/HeaderActions/HeaderActions.tsx b/packages/ui/src/components/HeaderActions/HeaderActions.tsx index 459fb416..26c418ba 100644 --- a/packages/ui/src/components/HeaderActions/HeaderActions.tsx +++ b/packages/ui/src/components/HeaderActions/HeaderActions.tsx @@ -1,24 +1,14 @@ -import React, { useState, Suspense } from 'react'; +import React, { Suspense } from 'react'; +import { useModal } from '../../hooks/useModal'; import { useUIConfig } from '../../hooks/useUIConfig'; +import { Button } from '../Button/Button'; import { CustomLinksDropdown } from '../CustomLinksDropdown/CustomLinksDropdown'; 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 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 RedisStatsModalLazy = React.lazy(() => import('../RedisStatsModal/RedisStatsModal').then(({ RedisStatsModal }) => ({ @@ -39,14 +29,14 @@ const onClickFullScreen = async () => { }; export const HeaderActions = () => { - const [openedModal, setModalOpen] = useState(null); const { miscLinks = [] } = useUIConfig(); + const modal = useModal(); return ( <>
  • -
  • @@ -56,7 +46,7 @@ export const HeaderActions = () => {
  • -
  • @@ -67,17 +57,11 @@ export const HeaderActions = () => { )}
- {(openedModal === 'redis' || openedModal === 'redisClosing') && ( - + {modal.isMounted('redis') && ( + )} - {(openedModal === 'settings' || openedModal === 'settingsClosing') && ( - + {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/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/QueueDropdownActions/QueueDropdownActions.tsx b/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx index ac105eb0..5bcc3477 100644 --- a/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx +++ b/packages/ui/src/components/QueueDropdownActions/QueueDropdownActions.tsx @@ -1,6 +1,6 @@ import { AppQueue } from '@bull-board/api/typings/app'; import { Item, Portal, Root, Trigger } from '@radix-ui/react-dropdown-menu'; -import React, { Suspense, useState } from 'react'; +import React from 'react'; import { useTranslation } from 'react-i18next'; import { QueueActions } from '../../../typings/app'; import { Button } from '../Button/Button'; @@ -12,34 +12,15 @@ 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, }: { queue: AppQueue; - actions: QueueActions; + actions: Omit & { addJob: () => void }; }) => { const { t } = useTranslation(); - const [openedModal, setModalOpen] = useState(null); + return ( @@ -50,7 +31,7 @@ export const QueueDropdownActions = ({ - setModalOpen('addJobs')}> + {t('QUEUE.ACTIONS.ADD_JOB')} @@ -77,16 +58,6 @@ export const QueueDropdownActions = ({ - - {(openedModal === 'addJobs' || openedModal === 'addJobsClosing') && ( - - )} - ); }; 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/components/StatusMenu/StatusMenu.tsx b/packages/ui/src/components/StatusMenu/StatusMenu.tsx index 6cc211db..fb818183 100644 --- a/packages/ui/src/components/StatusMenu/StatusMenu.tsx +++ b/packages/ui/src/components/StatusMenu/StatusMenu.tsx @@ -1,12 +1,11 @@ import { AppQueue } from '@bull-board/api/typings/app'; -import React from 'react'; +import React, { PropsWithChildren } from 'react'; import { useTranslation } from 'react-i18next'; import { NavLink } from 'react-router-dom'; import { links } from '../../utils/links'; -import { QueueDropdownActions } from '../QueueDropdownActions/QueueDropdownActions'; import s from './StatusMenu.module.css'; -export const StatusMenu = ({ queue, actions }: { queue: AppQueue; actions: any }) => { +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/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/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/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 163fc311..dc489229 100644 --- a/packages/ui/src/static/locales/en-US/messages.json +++ b/packages/ui/src/static/locales/en-US/messages.json @@ -56,13 +56,13 @@ "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?", "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?", - "ADD_JOB": "Add job" + "RESUME_QUEUE_CONFIRM_MSG": "Are you sure that you want to resume queue processing?" }, "STATUS": { "LATEST": "Latest", @@ -119,10 +119,10 @@ }, "ADD_JOB": { "TITLE": "Add job", + "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/yarn.lock b/yarn.lock index 44e7b74c..94bbc9b8 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" @@ -4016,6 +4163,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 +4275,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" @@ -5699,6 +5858,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 +5949,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 +6284,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 +6486,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 +6589,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 +6772,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 +6862,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 +6884,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 +6982,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 +7483,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" @@ -9612,6 +9838,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,7 +9861,7 @@ 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== @@ -9642,7 +9881,7 @@ 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== @@ -9915,6 +10154,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 +10201,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 +10512,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 +10537,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" @@ -10541,6 +10811,11 @@ modify-values@^1.0.0: 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 +10915,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 +10979,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 +10993,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" @@ -12307,6 +12592,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 +12673,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 +13303,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 +13665,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 +14086,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 +14615,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 +14662,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 +14873,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" @@ -14605,6 +14940,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 +15395,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"