From 5b3f7c36654d5a5cbc7a0c4bea42bffd7ca5b8b3 Mon Sep 17 00:00:00 2001 From: Wes Date: Tue, 7 May 2024 16:44:11 -0700 Subject: [PATCH] feat: new verb page layout and features (#1433) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a fairly hefty change to the verb page on the console. I have many follow on tasks, but this PR was getting a bit insane and most things are working better than before now. Some highlights include: - New code editor (using code mirror now) - Postman style interface that improves how test requests can be made - Remove prettier and improve estlint config ![Screenshot 2024-05-07 at 2 43 05 PM](https://github.com/TBD54566975/ftl/assets/51647/ce787ae2-89a9-4be3-b237-ff7d66bce20d) ![Screenshot 2024-05-07 at 2 43 19 PM](https://github.com/TBD54566975/ftl/assets/51647/0c989478-8720-4668-bdd8-bdf30093128d) ![Screenshot 2024-05-07 at 2 43 37 PM](https://github.com/TBD54566975/ftl/assets/51647/751776ab-0b25-4054-aeee-bc1e06f6d76f) ![Screenshot 2024-05-07 at 2 43 39 PM](https://github.com/TBD54566975/ftl/assets/51647/0a4b9391-9205-4fcb-b5b5-c822d46624ad) ![Screenshot 2024-05-07 at 2 43 49 PM](https://github.com/TBD54566975/ftl/assets/51647/eff8626e-4aee-418e-90e5-a6e02d022079) ![Screenshot 2024-05-07 at 2 49 33 PM](https://github.com/TBD54566975/ftl/assets/51647/31ddb276-c3b1-4b66-9891-08110f6088f8) --- backend/controller/console.go | 13 +- frontend/.eslintrc.cjs | 33 +- frontend/.prettierignore | 2 - frontend/.prettierrc | 6 - frontend/package-lock.json | 1220 ++++++++++++----- frontend/package.json | 21 +- frontend/src/App.tsx | 2 +- frontend/src/components/CodeEditor.tsx | 124 ++ frontend/src/components/ResizablePanels.tsx | 100 ++ .../components/ResizeableVerticalPanels.tsx | 76 + frontend/src/features/console/BottomPanel.tsx | 11 +- frontend/src/features/console/ConsolePage.tsx | 83 +- frontend/src/features/verbs/VerbForm.tsx | 120 -- frontend/src/features/verbs/VerbFormInput.tsx | 52 + frontend/src/features/verbs/VerbPage.tsx | 52 +- .../src/features/verbs/VerbRequestForm.tsx | 152 ++ frontend/src/features/verbs/verb.utils.ts | 136 +- 17 files changed, 1617 insertions(+), 586 deletions(-) delete mode 100644 frontend/.prettierignore delete mode 100644 frontend/.prettierrc create mode 100644 frontend/src/components/CodeEditor.tsx create mode 100644 frontend/src/components/ResizablePanels.tsx create mode 100644 frontend/src/components/ResizeableVerticalPanels.tsx delete mode 100644 frontend/src/features/verbs/VerbForm.tsx create mode 100644 frontend/src/features/verbs/VerbFormInput.tsx create mode 100644 frontend/src/features/verbs/VerbRequestForm.tsx diff --git a/backend/controller/console.go b/backend/controller/console.go index a6051d3ca5..9aff7bd93f 100644 --- a/backend/controller/console.go +++ b/backend/controller/console.go @@ -204,12 +204,15 @@ func (c *ConsoleService) StreamEvents(ctx context.Context, req *connect.Request[ return err } - err = stream.Send(&pbconsole.StreamEventsResponse{ - Events: slices.Map(events, eventDALToProto), - }) - if err != nil { - return err + if len(events) > 0 { + err = stream.Send(&pbconsole.StreamEventsResponse{ + Events: slices.Map(events, eventDALToProto), + }) + if err != nil { + return err + } } + lastEventTime = thisRequestTime select { case <-time.After(updateInterval): diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index ad545b8dd1..0519f20724 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { browser: true, es2021: true, }, - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'prettier'], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended'], overrides: [ { env: { @@ -22,6 +22,13 @@ module.exports = { }, plugins: ['@typescript-eslint', 'react'], rules: { + 'semi': ['error', 'never'], + 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': true }], + 'jsx-quotes': ['error', 'prefer-single'], + 'no-trailing-spaces': 'error', + 'no-multiple-empty-lines': ['error', { 'max': 1, 'maxEOF': 0, 'maxBOF': 0 }], + 'eol-last': ['error', 'always'], + 'max-len': ['error', { 'code': 120, 'tabWidth': 4, 'ignoreUrls': true, 'ignoreComments': false, 'ignoreRegExpLiterals': true, 'ignoreStrings': true, 'ignoreTemplateLiterals': true }], 'react/react-in-jsx-scope': 'off', 'react/jsx-uses-react': 'off', 'func-style': ['error', 'expression'], @@ -34,6 +41,30 @@ module.exports = { 'ts-ignore': 'allow-with-description', }, ], + 'indent': ['error', 2, { + 'SwitchCase': 1, + 'VariableDeclarator': 1, + 'outerIIFEBody': 1, + 'MemberExpression': 1, + 'FunctionDeclaration': { + 'parameters': 1, + 'body': 1 + }, + 'FunctionExpression': { + 'parameters': 1, + 'body': 1 + }, + 'CallExpression': { + 'arguments': 1 + }, + 'ArrayExpression': 1, + 'ObjectExpression': 1, + 'ImportDeclaration': 1, + 'flatTernaryExpressions': false, + 'ignoreComments': false + }], + 'react/jsx-indent': ['error', 2], + 'react/jsx-indent-props': ['error', 2] }, settings: { react: { diff --git a/frontend/.prettierignore b/frontend/.prettierignore deleted file mode 100644 index c297d665f3..0000000000 --- a/frontend/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -src/protos/**/* -dist/**/* diff --git a/frontend/.prettierrc b/frontend/.prettierrc deleted file mode 100644 index ac3a5e86a7..0000000000 --- a/frontend/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "semi": false, - "singleQuote": true, - "jsxSingleQuote": true, - "printWidth": 120 -} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e4216b3f4a..aa0d2495a5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,29 +9,41 @@ "version": "0.0.0", "dependencies": { "@bufbuild/protoc-gen-es": "1.9.0", + "@codemirror/commands": "^6.5.0", + "@codemirror/gutter": "^0.19.9", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/language": "^6.10.1", + "@codemirror/state": "^6.4.1", + "@codemirror/theme-one-dark": "^6.1.2", + "@codemirror/view": "^6.26.3", "@connectrpc/connect": "^1.1.2", "@connectrpc/connect-web": "^1.1.2", "@connectrpc/protoc-gen-connect-es": "1.4.0", "@headlessui/react": "1.7.19", "@heroicons/react": "2.1.3", - "@monaco-editor/react": "4.6.0", "@svgdotjs/svg.js": "3.2.0", "@svgdotjs/svg.panzoom.js": "2.1.2", "@tailwindcss/forms": "^0.5.6", + "@uiw/codemirror-theme-atomone": "^4.22.0", + "@uiw/codemirror-theme-github": "^4.22.0", "@vitejs/plugin-react": "^4.0.4", "@viz-js/viz": "3.4.0", + "codemirror": "^5.65.16", + "codemirror-json-schema": "^0.7.1", "elkjs": "^0.9.2", "fnv1a": "^1.1.1", "highlight.js": "^11.8.0", "json-schema": "0.4.0", "json-schema-faker": "0.5.6", "react": "18.3.1", + "react-codemirror2": "^8.0.0", "react-dom": "18.3.1", "react-router-dom": "6.23.0", "react-use": "^17.5.0", "reactflow": "11.11.3", "svg-pan-zoom": "^3.6.1", "tailwindcss": "^3.3.3", + "type-fest": "^4.18.2", "vite": "^4.4.9" }, "devDependencies": { @@ -40,6 +52,7 @@ "@swc/jest": "0.2.36", "@testing-library/jest-dom": "6.4.5", "@testing-library/react": "15.0.6", + "@types/codemirror": "^5.60.15", "@types/p5": "1.7.6", "@types/react": "18.3.1", "@types/react-dom": "18.3.0", @@ -50,7 +63,6 @@ "buffer": "^6.0.3", "chokidar": "3.6.0", "eslint": "^8.57.0", - "eslint-config-prettier": "9.1.0", "eslint-plugin-compat": "4.2.0", "eslint-plugin-react": "7.34.1", "fast-glob": "3.3.2", @@ -61,7 +73,6 @@ "npm-run-all2": "6.1.2", "postcss": "8.4.38", "postcss-nesting": "12.1.2", - "prettier": "3.2.5", "process": "^0.11.10", "start-server-and-test": "2.0.3", "typed-css-modules": "0.9.1", @@ -103,94 +114,40 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "license": "MIT", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "license": "MIT" - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.3", - "license": "MIT", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.5", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.5", - "@babel/parser": "^7.23.5", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -213,12 +170,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.5", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", "dependencies": { - "@babel/types": "^7.23.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -226,12 +184,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "license": "MIT", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -241,21 +200,24 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { "version": "7.23.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -266,7 +228,8 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { "@babel/types": "^7.22.5" }, @@ -275,24 +238,26 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "license": "MIT", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -309,65 +274,73 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "license": "MIT", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "license": "MIT", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.5", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -375,7 +348,8 @@ }, "node_modules/@babel/highlight/node_modules/ansi-styles": { "version": "3.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { "color-convert": "^1.9.0" }, @@ -385,7 +359,8 @@ }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -397,32 +372,37 @@ }, "node_modules/@babel/highlight/node_modules/color-convert": { "version": "1.9.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dependencies": { "color-name": "1.1.3" } }, "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { "node": ">=4" } }, "node_modules/@babel/highlight/node_modules/supports-color": { "version": "5.5.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { "has-flag": "^3.0.0" }, @@ -431,8 +411,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.5", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -640,30 +621,32 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "license": "MIT", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.5", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.5", - "@babel/types": "^7.23.5", - "debug": "^4.1.0", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -672,17 +655,19 @@ }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "engines": { "node": ">=4" } }, "node_modules/@babel/types": { - "version": "7.23.5", - "license": "MIT", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -743,6 +728,184 @@ "node": ">=4.2.0" } }, + "node_modules/@changesets/changelog-github": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", + "integrity": "sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==", + "dependencies": { + "@changesets/get-github-info": "^0.5.2", + "@changesets/types": "^5.2.1", + "dotenv": "^8.1.0" + } + }, + "node_modules/@changesets/get-github-info": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.5.2.tgz", + "integrity": "sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==", + "dependencies": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "node_modules/@changesets/types": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz", + "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==" + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.16.0.tgz", + "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" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.5.0.tgz", + "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" + } + }, + "node_modules/@codemirror/gutter": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/gutter/-/gutter-0.19.9.tgz", + "integrity": "sha512-PFrtmilahin1g6uL27aG5tM/rqR9DZzZYZsIrCXA5Uc2OFTFqx4owuhoU9hqfYxHp5ovfvBwQ+txFzqS4vog6Q==", + "deprecated": "As of 0.20.0, this package has been merged into @codemirror/view", + "dependencies": { + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.23" + } + }, + "node_modules/@codemirror/gutter/node_modules/@codemirror/state": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.19.9.tgz", + "integrity": "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw==", + "dependencies": { + "@codemirror/text": "^0.19.0" + } + }, + "node_modules/@codemirror/gutter/node_modules/@codemirror/view": { + "version": "0.19.48", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.19.48.tgz", + "integrity": "sha512-0eg7D2Nz4S8/caetCTz61rK0tkHI17V/d15Jy0kLOT8dTLGGNJUponDnW28h2B6bERmPlVHKh8MJIr5OCp1nGw==", + "dependencies": { + "@codemirror/rangeset": "^0.19.5", + "@codemirror/state": "^0.19.3", + "@codemirror/text": "^0.19.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz", + "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-yaml": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.1.tgz", + "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" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz", + "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" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.7.0.tgz", + "integrity": "sha512-LTLOL2nT41ADNSCCCCw8Q/UmdAFzB23OUYSjsHTdsVaH0XEo+orhuqbDNWzrzodm14w6FOxqxpmy4LF8Lixqjw==", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/rangeset": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.9.tgz", + "integrity": "sha512-V8YUuOvK+ew87Xem+71nKcqu1SXd5QROMRLMS/ljT5/3MCxtgrRie1Cvild0G/Z2f1fpWxzX78V0U4jjXBorBQ==", + "deprecated": "As of 0.20.0, this package has been merged into @codemirror/state", + "dependencies": { + "@codemirror/state": "^0.19.0" + } + }, + "node_modules/@codemirror/rangeset/node_modules/@codemirror/state": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.19.9.tgz", + "integrity": "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw==", + "dependencies": { + "@codemirror/text": "^0.19.0" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "node_modules/@codemirror/text": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/@codemirror/text/-/text-0.19.6.tgz", + "integrity": "sha512-T9jnREMIygx+TPC1bOuepz18maGq/92q2a+n4qTqObKwvNMg+8cMTslb8yxeEDEq7S3kpgGWxgO1UWbQRij0dA==", + "deprecated": "As of 0.20.0, this package has been merged into @codemirror/state" + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz", + "integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.3.tgz", + "integrity": "sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@connectrpc/connect": { "version": "1.4.0", "license": "Apache-2.0", @@ -886,6 +1049,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@eslint/js": { "version": "8.57.0", "dev": true, @@ -1188,9 +1373,10 @@ } }, "node_modules/@jest/core/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/@jest/create-cache-key-function": { "version": "29.7.0", @@ -1406,12 +1592,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "license": "MIT", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -1425,8 +1612,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "license": "MIT", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -1436,40 +1624,60 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "license": "MIT", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mdn/browser-compat-data": { - "version": "5.3.13", - "dev": true, - "license": "CC0-1.0" + "node_modules/@lezer/common": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", + "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==" + }, + "node_modules/@lezer/highlight": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", + "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz", + "integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } }, - "node_modules/@monaco-editor/loader": { + "node_modules/@lezer/lr": { "version": "1.4.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz", + "integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==", "dependencies": { - "state-local": "^1.0.6" - }, - "peerDependencies": { - "monaco-editor": ">= 0.21.0 < 1" + "@lezer/common": "^1.0.0" } }, - "node_modules/@monaco-editor/react": { - "version": "4.6.0", - "license": "MIT", + "node_modules/@lezer/yaml": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.3.tgz", + "integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==", "dependencies": { - "@monaco-editor/loader": "^1.4.0" - }, - "peerDependencies": { - "monaco-editor": ">= 0.25.0 < 1", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.4.0" } }, + "node_modules/@mdn/browser-compat-data": { + "version": "5.3.13", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "license": "MIT", @@ -1612,6 +1820,20 @@ "node": ">=14.0.0" } }, + "node_modules/@sagold/json-pointer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@sagold/json-pointer/-/json-pointer-5.1.2.tgz", + "integrity": "sha512-+wAhJZBXa6MNxRScg6tkqEbChEHMgVZAhTHVJ60Y7sbtXtu9XA49KfUkdWlS2x78D6H9nryiKePiYozumauPfA==" + }, + "node_modules/@sagold/json-query": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@sagold/json-query/-/json-query-6.2.0.tgz", + "integrity": "sha512-7bOIdUE6eHeoWtFm8TvHQHfTVSZuCs+3RpOKmZCDBIOrxpvF/rNFTeuvIyjHva/RR0yVS3kQtr+9TW72LQEZjA==", + "dependencies": { + "@sagold/json-pointer": "^5.1.2", + "ebnf": "^1.9.1" + } + }, "node_modules/@sideway/address": { "version": "4.1.4", "dev": true, @@ -2086,6 +2308,15 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/codemirror": { + "version": "5.60.15", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz", + "integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==", + "dev": true, + "dependencies": { + "@types/tern": "*" + } + }, "node_modules/@types/d3": { "version": "7.4.0", "license": "MIT", @@ -2277,6 +2508,12 @@ "@types/d3-selection": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "node_modules/@types/geojson": { "version": "7946.0.10", "license": "MIT" @@ -2328,12 +2565,10 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/node": { "version": "20.5.6", - "devOptional": true, "license": "MIT" }, "node_modules/@types/p5": { @@ -2376,6 +2611,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/tough-cookie": { "version": "4.0.2", "dev": true, @@ -2615,6 +2859,46 @@ "debug": "^4.1.1" } }, + "node_modules/@uiw/codemirror-theme-atomone": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-atomone/-/codemirror-theme-atomone-4.22.0.tgz", + "integrity": "sha512-jc4XWBeEOMyyu3WaVSJ/z0uXYuESSBriTzKAdShhtp+urg5BRpOBlow1yjCY+hXu151IBOzMtoY5MLAi3lEdfw==", + "dependencies": { + "@uiw/codemirror-themes": "4.22.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/@uiw/codemirror-theme-github": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-github/-/codemirror-theme-github-4.22.0.tgz", + "integrity": "sha512-toRG+V8xCKVvqZnyEHgR9posQ8fA28U0m8ALqn0fWTRRFuGPvYCSSX+i2mpA3HF06Sv7GWCzgHe8ioyYbrN2Lg==", + "dependencies": { + "@uiw/codemirror-themes": "4.22.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/@uiw/codemirror-themes": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.22.0.tgz", + "integrity": "sha512-nn7K+lkfdLOSQN6NZx651ae24L5L2RiCuNOxIeP3/CcGm9tnic8i+9pq42IXZe+hEoxX64yUTZisoB5qtocvrQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@codemirror/language": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "dev": true, @@ -2698,21 +2982,6 @@ "node": ">= 6.0.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "dev": true, @@ -2781,7 +3050,6 @@ }, "node_modules/argparse": { "version": "2.0.1", - "dev": true, "license": "Python-2.0" }, "node_modules/aria-query": { @@ -3425,9 +3693,10 @@ "license": "MIT" }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.0.0", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -3522,6 +3791,54 @@ "node": ">= 0.12.0" } }, + "node_modules/codemirror": { + "version": "5.65.16", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", + "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" + }, + "node_modules/codemirror-json-schema": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/codemirror-json-schema/-/codemirror-json-schema-0.7.1.tgz", + "integrity": "sha512-AaAIBYcWAewlcUuSW4tHC1FFJn3AJmbtPfhPUxC2vae//skCASKNsl/oOCo+C/JjQZ9sjUZKoVlzXjYjSlcwWQ==", + "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" + }, + "peerDependencies": { + "@codemirror/language": "^6.8.0", + "@codemirror/lint": "^6.4.0", + "@codemirror/state": "^6.2.1", + "@codemirror/view": "^6.14.1", + "@lezer/common": "^1.0.3" + } + }, + "node_modules/codemirror-json5": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/codemirror-json5/-/codemirror-json5-1.0.3.tgz", + "integrity": "sha512-HmmoYO2huQxoaoG5ARKjqQc9mz7/qmNPvMbISVfIE2Gk1+4vZQg9X3G6g49MYM5IK00Ol3aijd7OKrySuOkA7Q==", + "optional": true, + "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" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "dev": true, @@ -3603,6 +3920,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "peer": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "dev": true, @@ -3776,6 +4099,11 @@ "node": ">=12" } }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==" + }, "node_modules/debug": { "version": "4.3.4", "license": "MIT", @@ -3816,7 +4144,6 @@ }, "node_modules/deepmerge": { "version": "4.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3913,6 +4240,11 @@ "node": ">=8" } }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==" + }, "node_modules/dlv": { "version": "1.1.3", "license": "MIT" @@ -3944,6 +4276,14 @@ "node": ">=12" } }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "engines": { + "node": ">=10" + } + }, "node_modules/duplexer": { "version": "0.1.2", "dev": true, @@ -3954,6 +4294,14 @@ "dev": true, "license": "MIT" }, + "node_modules/ebnf": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ebnf/-/ebnf-1.9.1.tgz", + "integrity": "sha512-uW2UKSsuty9ANJ3YByIQE4ANkD8nqUPO7r6Fwcc1ADKPe9FRdcPpMl3VEput4JSvKBJ4J86npIC2MLP0pYkCuw==", + "bin": { + "ebnf": "dist/bin.js" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.690", "license": "ISC" @@ -3981,7 +4329,6 @@ }, "node_modules/entities": { "version": "4.5.0", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -4269,17 +4616,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, "node_modules/eslint-plugin-compat": { "version": "4.2.0", "dev": true, @@ -4379,6 +4715,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "dev": true, @@ -4390,6 +4742,12 @@ "node": ">=10.13.0" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/espree": { "version": "9.6.1", "dev": true, @@ -4518,6 +4876,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "license": "MIT" @@ -4848,14 +5211,14 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -4877,9 +5240,10 @@ } }, "node_modules/globals": { - "version": "13.21.0", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -4890,6 +5254,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globalthis": { "version": "1.0.3", "dev": true, @@ -5607,13 +5983,14 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.1", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" }, @@ -5781,9 +6158,10 @@ } }, "node_modules/jest-circus/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-cli": { "version": "29.7.0", @@ -5886,9 +6264,10 @@ } }, "node_modules/jest-config/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-diff": { "version": "29.7.0", @@ -5929,9 +6308,10 @@ } }, "node_modules/jest-diff/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-docblock": { "version": "29.7.0", @@ -5984,9 +6364,10 @@ } }, "node_modules/jest-each/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-environment-jsdom": { "version": "29.7.0", @@ -6099,9 +6480,10 @@ } }, "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-matcher-utils": { "version": "29.7.0", @@ -6142,9 +6524,10 @@ } }, "node_modules/jest-matcher-utils/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-message-util": { "version": "29.7.0", @@ -6190,9 +6573,10 @@ } }, "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-mock": { "version": "29.7.0", @@ -6396,9 +6780,10 @@ } }, "node_modules/jest-snapshot/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-util": { "version": "29.7.0", @@ -6468,9 +6853,10 @@ } }, "node_modules/jest-validate/node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/jest-watcher": { "version": "29.7.0", @@ -6637,6 +7023,20 @@ "jsf": "bin/gen.cjs" } }, + "node_modules/json-schema-library": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/json-schema-library/-/json-schema-library-9.3.4.tgz", + "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" + } + }, "node_modules/json-schema-ref-parser": { "version": "6.1.0", "license": "MIT", @@ -6664,11 +7064,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "dev": true, @@ -6754,6 +7149,15 @@ "node": ">= 0.8.0" } }, + "node_modules/lezer-json5": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lezer-json5/-/lezer-json5-2.0.2.tgz", + "integrity": "sha512-NRmtBlKW/f8mA7xatKq8IUOq045t8GVHI4kZXrUtYYUdiVeGiO6zKGAV7/nUAnf5q+rYTY+SWX/gvQdFXMjNxQ==", + "optional": true, + "dependencies": { + "@lezer/lr": "^1.0.0" + } + }, "node_modules/lightningcss": { "version": "1.21.7", "license": "MPL-2.0", @@ -6811,6 +7215,14 @@ "version": "1.2.4", "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/lint-staged": { "version": "15.2.2", "dev": true, @@ -6920,9 +7332,10 @@ } }, "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.2.0", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^4.0.0" }, @@ -7024,9 +7437,10 @@ "license": "MIT" }, "node_modules/listr2/node_modules/string-width": { - "version": "7.0.0", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -7117,12 +7531,10 @@ } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.0", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^3.0.0" - }, "engines": { "node": ">=14.16" }, @@ -7187,9 +7599,10 @@ } }, "node_modules/log-update/node_modules/string-width": { - "version": "7.0.0", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -7216,17 +7629,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/log-update/node_modules/type-fest": { - "version": "3.13.1", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "9.0.0", "dev": true, @@ -7255,7 +7657,8 @@ }, "node_modules/lru-cache": { "version": "5.1.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dependencies": { "yallist": "^3.0.2" } @@ -7294,11 +7697,32 @@ "version": "0.1.0", "dev": true }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "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" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/mdn-data": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, "node_modules/memorystream": { "version": "0.3.1", "dev": true, @@ -7390,9 +7814,10 @@ } }, "node_modules/minipass": { - "version": "7.0.4", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", + "integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==", "dev": true, - "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -7411,10 +7836,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/monaco-editor": { - "version": "0.41.0", - "license": "MIT", - "peer": true + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" }, "node_modules/ms": { "version": "2.1.2", @@ -7469,6 +7894,70 @@ "dev": true, "license": "MIT" }, + "node_modules/nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, + "node_modules/nearley/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "dev": true, @@ -7545,9 +8034,10 @@ } }, "node_modules/npm-run-all2/node_modules/minimatch": { - "version": "9.0.3", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -7825,11 +8315,12 @@ "license": "MIT" }, "node_modules/path-scurry": { - "version": "1.10.1", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -7840,9 +8331,10 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true, - "license": "ISC", "engines": { "node": "14 || >=16.14" } @@ -8008,8 +8500,9 @@ } }, "node_modules/postcss-import/node_modules/resolve": { - "version": "1.22.4", - "license": "MIT", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -8188,20 +8681,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "3.2.5", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/pretty-format": { "version": "27.5.1", "dev": true, @@ -8293,6 +8772,14 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.0.4", "dev": true, @@ -8331,6 +8818,23 @@ ], "license": "MIT" }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==" + }, + "node_modules/randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -8342,6 +8846,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-codemirror2": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-8.0.0.tgz", + "integrity": "sha512-JIbhXoghvX0BrasIoCQvRxBPIU78plfjF1Buz0gaMFvZXwEDjkCYBkQhucoOtudQ7ikbB1jJUnmCsutElti7yA==", + "peerDependencies": { + "codemirror": "5.x", + "react": ">=15.5 <=18.x" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -8474,9 +8987,10 @@ } }, "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", "dev": true, - "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -8628,6 +9142,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, "node_modules/reusify": { "version": "1.0.4", "license": "MIT", @@ -8927,6 +9449,17 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/smtp-address-parser": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/smtp-address-parser/-/smtp-address-parser-1.0.10.tgz", + "integrity": "sha512-Osg9LmvGeAG/hyao4mldbflLOkkr3a+h4m1lwKCK5U8M6ZAr7tdXEz/+/vr752TSGE4MNUlUl9cIK2cB8cgzXg==", + "dependencies": { + "nearley": "^2.20.1" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/source-map": { "version": "0.6.1", "license": "BSD-3-Clause", @@ -9048,10 +9581,6 @@ "node": ">=16" } }, - "node_modules/state-local": { - "version": "1.0.7", - "license": "MIT" - }, "node_modules/stream-combiner": { "version": "0.0.4", "dev": true, @@ -9270,6 +9799,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, "node_modules/stylis": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", @@ -9302,24 +9836,6 @@ "node": ">= 6" } }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/supports-color": { "version": "7.2.0", "dev": true, @@ -9559,11 +10075,11 @@ } }, "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz", + "integrity": "sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==", "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -9684,15 +10200,16 @@ } }, "node_modules/typed-css-modules/node_modules/glob": { - "version": "10.3.10", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -9705,9 +10222,10 @@ } }, "node_modules/typed-css-modules/node_modules/minimatch": { - "version": "9.0.3", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -9731,6 +10249,11 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + }, "node_modules/unbox-primitive": { "version": "1.0.2", "dev": true, @@ -9822,6 +10345,11 @@ "node": ">=10.12.0" } }, + "node_modules/valid-url": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", + "integrity": "sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==" + }, "node_modules/vite": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", @@ -9876,6 +10404,11 @@ } } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "dev": true, @@ -10192,7 +10725,8 @@ }, "node_modules/yallist": { "version": "3.1.1", - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "2.3.4", diff --git a/frontend/package.json b/frontend/package.json index 7637e734d3..268b0fe491 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,15 +10,13 @@ "dev": "vite", "lint": "eslint . --ext .ts,.tsx,.js,.cjs", "lint:fix": "npm run lint -- --fix --quiet", - "prettier": "prettier . --write", "test": "jest ./src", "test:coverage": "jest ./src --coverage", "test:watch": "jest ./src --watch --verbose" }, "lint-staged": { "*.(js|cjs|tsx|ts)": [ - "npm run lint:fix", - "npm run prettier" + "npm run lint:fix" ] }, "browserslist": [ @@ -27,29 +25,41 @@ "source": "index.html", "dependencies": { "@bufbuild/protoc-gen-es": "1.9.0", + "@codemirror/commands": "^6.5.0", + "@codemirror/gutter": "^0.19.9", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/language": "^6.10.1", + "@codemirror/state": "^6.4.1", + "@codemirror/theme-one-dark": "^6.1.2", + "@codemirror/view": "^6.26.3", "@connectrpc/connect": "^1.1.2", "@connectrpc/connect-web": "^1.1.2", "@connectrpc/protoc-gen-connect-es": "1.4.0", "@headlessui/react": "1.7.19", "@heroicons/react": "2.1.3", - "@monaco-editor/react": "4.6.0", "@svgdotjs/svg.js": "3.2.0", "@svgdotjs/svg.panzoom.js": "2.1.2", "@tailwindcss/forms": "^0.5.6", + "@uiw/codemirror-theme-atomone": "^4.22.0", + "@uiw/codemirror-theme-github": "^4.22.0", "@vitejs/plugin-react": "^4.0.4", "@viz-js/viz": "3.4.0", + "codemirror": "^5.65.16", + "codemirror-json-schema": "^0.7.1", "elkjs": "^0.9.2", "fnv1a": "^1.1.1", "highlight.js": "^11.8.0", "json-schema": "0.4.0", "json-schema-faker": "0.5.6", "react": "18.3.1", + "react-codemirror2": "^8.0.0", "react-dom": "18.3.1", "react-router-dom": "6.23.0", "react-use": "^17.5.0", "reactflow": "11.11.3", "svg-pan-zoom": "^3.6.1", "tailwindcss": "^3.3.3", + "type-fest": "^4.18.2", "vite": "^4.4.9" }, "devDependencies": { @@ -58,6 +68,7 @@ "@swc/jest": "0.2.36", "@testing-library/jest-dom": "6.4.5", "@testing-library/react": "15.0.6", + "@types/codemirror": "^5.60.15", "@types/p5": "1.7.6", "@types/react": "18.3.1", "@types/react-dom": "18.3.0", @@ -68,7 +79,6 @@ "buffer": "^6.0.3", "chokidar": "3.6.0", "eslint": "^8.57.0", - "eslint-config-prettier": "9.1.0", "eslint-plugin-compat": "4.2.0", "eslint-plugin-react": "7.34.1", "fast-glob": "3.3.2", @@ -79,7 +89,6 @@ "npm-run-all2": "6.1.2", "postcss": "8.4.38", "postcss-nesting": "12.1.2", - "prettier": "3.2.5", "process": "^0.11.10", "start-server-and-test": "2.0.3", "typed-css-modules": "0.9.1", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 27a751c976..626a554a93 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,7 +5,7 @@ import { TimelinePage } from './features/timeline/TimelinePage.tsx' import { VerbPage } from './features/verbs/VerbPage.tsx' import { Layout } from './layout/Layout.tsx' import { NotFoundPage } from './layout/NotFoundPage.tsx' -import ConsolePage from './features/console/ConsolePage.tsx' +import { ConsolePage } from './features/console/ConsolePage.tsx' export const App = () => { return ( diff --git a/frontend/src/components/CodeEditor.tsx b/frontend/src/components/CodeEditor.tsx new file mode 100644 index 0000000000..c517dc3cc0 --- /dev/null +++ b/frontend/src/components/CodeEditor.tsx @@ -0,0 +1,124 @@ +import { EditorState, Extension } from '@codemirror/state' +import { + gutter, + EditorView, + hoverTooltip, + lineNumbers, + drawSelection, + keymap, + highlightActiveLineGutter, +} from '@codemirror/view' + +import { lintGutter } from '@codemirror/lint' +import { lintKeymap } from '@codemirror/lint' +import { linter } from '@codemirror/lint' +import { + + indentOnInput, + bracketMatching, + foldGutter, + foldKeymap, +} from '@codemirror/language' + +import { githubLight } from '@uiw/codemirror-theme-github' +import { atomone } from '@uiw/codemirror-theme-atomone' +import { + autocompletion, + closeBrackets, + closeBracketsKeymap, +} from '@codemirror/autocomplete' + +import { useRef, useEffect, useCallback } from 'react' +import { json, jsonParseLinter } from '@codemirror/lang-json' +import { jsonSchemaLinter, jsonSchemaHover, stateExtensions, handleRefresh } from 'codemirror-json-schema' +import { useDarkMode } from '../providers/dark-mode-provider' +import { defaultKeymap } from '@codemirror/commands' + +const commonExtensions = [ + gutter({ class: 'CodeMirror-lint-markers' }), + bracketMatching(), + highlightActiveLineGutter(), + closeBrackets(), + keymap.of([ + ...closeBracketsKeymap, + ...foldKeymap, + ...lintKeymap, + ...defaultKeymap + ]), + EditorView.lineWrapping, + EditorState.tabSize.of(2), +] + +export interface InitialState { + initialText: string + schema?: string + readonly?: boolean +} + +export const CodeEditor = ( + { initialState, onTextChanged }: + { initialState: InitialState, onTextChanged?: (text: string) => void } +) => { + const { isDarkMode } = useDarkMode() + const editorContainerRef = useRef(null) + const editorViewRef = useRef(null) + + const handleEditorTextChange = useCallback((state: EditorState) => { + const currentText = state.doc.toString() + onTextChanged && onTextChanged(currentText) + }, [onTextChanged]) + + useEffect(() => { + if (editorContainerRef.current) { + const sch = initialState.schema ? JSON.parse(initialState.schema) : null + + const editingExtensions: Extension[] = initialState.readonly || false ? [ + EditorState.readOnly.of(true) + ] : [ + autocompletion(), + lineNumbers(), + lintGutter(), + indentOnInput(), + drawSelection(), + foldGutter(), + linter(jsonParseLinter(), { + delay: 300 + }), + linter(jsonSchemaLinter(), { + needsRefresh: handleRefresh, + }), + hoverTooltip(jsonSchemaHover()), + EditorView.updateListener.of((update) => { + if (update.docChanged) { + handleEditorTextChange(update.state) + } + }), + stateExtensions(sch), + ] + + const state = EditorState.create({ + doc: initialState.initialText, + extensions: [ + commonExtensions, + isDarkMode ? atomone : githubLight, + json(), + + editingExtensions + ], + }) + + const view = new EditorView({ + state, + parent: editorContainerRef.current, + }) + + editorViewRef.current = view + + return () => { + view.destroy() + } + } + }, [initialState, isDarkMode]) + + return
+} diff --git a/frontend/src/components/ResizablePanels.tsx b/frontend/src/components/ResizablePanels.tsx new file mode 100644 index 0000000000..a8f974a845 --- /dev/null +++ b/frontend/src/components/ResizablePanels.tsx @@ -0,0 +1,100 @@ +import React, { useState } from 'react' +import { ExpandablePanelProps } from '../features/console/ExpandablePanel' +import RightPanel from '../features/console/right-panel/RightPanel' +import useLocalStorage from '../hooks/use-local-storage' + +interface ResizablePanelsProps { + initialRightPanelWidth?: number; + initialBottomPanelHeight?: number; + minRightPanelWidth?: number; + minBottomPanelHeight?: number; + topBarHeight?: number; + rightPanelHeader: React.ReactNode; + rightPanelPanels: ExpandablePanelProps[] + bottomPanelContent: React.ReactNode; + mainContent: React.ReactNode; +} + +export const ResizablePanels: React.FC = ({ + initialRightPanelWidth = 300, + initialBottomPanelHeight = 200, + minRightPanelWidth = 200, + minBottomPanelHeight = 200, + rightPanelHeader, + rightPanelPanels, + bottomPanelContent, + mainContent, +}) => { + const [rightPanelWidth, setRightPanelWidth] = useLocalStorage('rightPanelWidth', initialRightPanelWidth) + const [bottomPanelHeight, setBottomPanelHeight] = useLocalStorage('bottomPanelHeight', initialBottomPanelHeight) + + const [isDraggingHorizontal, setIsDraggingHorizontal] = useState(false) + const [isDraggingVertical, setIsDraggingVertical] = useState(false) + + const startDraggingHorizontal = (e: React.MouseEvent) => { + e.preventDefault() + setIsDraggingHorizontal(true) + } + + const startDraggingVertical = (e: React.MouseEvent) => { + e.preventDefault() + setIsDraggingVertical(true) + } + + const stopDragging = () => { + setIsDraggingHorizontal(false) + setIsDraggingVertical(false) + } + + const onDragHorizontal = (e: React.MouseEvent) => { + if (isDraggingHorizontal) { + const newWidth = Math.max(window.innerWidth - e.clientX, minRightPanelWidth) + setRightPanelWidth(newWidth) + } + } + + const onDragVertical = (e: React.MouseEvent) => { + if (isDraggingVertical) { + const newHeight = Math.max(window.innerHeight - e.clientY, minBottomPanelHeight) + setBottomPanelHeight(newHeight) + } + } + + return ( +
{ + if (isDraggingHorizontal) onDragHorizontal(e) + if (isDraggingVertical) onDragVertical(e) + }} + onMouseUp={stopDragging} + onMouseLeave={stopDragging} + > +
+
+ {mainContent} +
+
+ +
+
+
+ {bottomPanelContent} +
+
+ ) +} diff --git a/frontend/src/components/ResizeableVerticalPanels.tsx b/frontend/src/components/ResizeableVerticalPanels.tsx new file mode 100644 index 0000000000..0e8d8660d5 --- /dev/null +++ b/frontend/src/components/ResizeableVerticalPanels.tsx @@ -0,0 +1,76 @@ +import React, { useEffect, useRef, useState } from 'react' + +interface ResizableVerticalPanelsProps { + topPanelContent: React.ReactNode; + bottomPanelContent: React.ReactNode; + initialTopPanelHeightPercent?: number; + minTopPanelHeight?: number; + minBottomPanelHeight?: number; +} + +export const ResizableVerticalPanels: React.FC = ({ + topPanelContent, + bottomPanelContent, + initialTopPanelHeightPercent = 50, + minTopPanelHeight = 100, + minBottomPanelHeight = 100, +}) => { + const containerRef = useRef(null) + const [topPanelHeight, setTopPanelHeight] = useState() + const [isDragging, setIsDragging] = useState(false) + + useEffect(() => { + const updateDimensions = () => { + if (containerRef.current) { + const parentHeight = containerRef.current.getBoundingClientRect().height + const initialHeight = parentHeight * (initialTopPanelHeightPercent / 100) + setTopPanelHeight(initialHeight) + } + } + + updateDimensions() + window.addEventListener('resize', updateDimensions) + return () => window.removeEventListener('resize', updateDimensions) + },[initialTopPanelHeightPercent]) + + const startDragging = (e: React.MouseEvent) => { + e.preventDefault() + setIsDragging(true) + } + + const stopDragging = () => { + setIsDragging(false) + } + + const onDrag = (e: React.MouseEvent) => { + if (isDragging) { + const newHeight = e.clientY + const maxHeight = window.innerHeight - minBottomPanelHeight + if (newHeight >= minTopPanelHeight && newHeight <= maxHeight) { + setTopPanelHeight(newHeight - 44) + } + } + } + + return ( +
+
+ {topPanelContent} +
+
+
+ {bottomPanelContent} +
+
+ ) +} diff --git a/frontend/src/features/console/BottomPanel.tsx b/frontend/src/features/console/BottomPanel.tsx index bc625a8047..6e432ec52d 100644 --- a/frontend/src/features/console/BottomPanel.tsx +++ b/frontend/src/features/console/BottomPanel.tsx @@ -1,19 +1,14 @@ -import React, { useMemo } from 'react' +import { useMemo } from 'react' import { Timeline } from '../timeline/Timeline' -interface BottomPanelProps { - height: number -} const timeSettings = { isTailing: true, isPaused: false } -const BottomPanel: React.FC = ({ height }) => { +const BottomPanel = () => { const filters = useMemo(() => { return [] }, []) return ( -
- {} -
+ ) } diff --git a/frontend/src/features/console/ConsolePage.tsx b/frontend/src/features/console/ConsolePage.tsx index 05ef8bc1c6..08314672b9 100644 --- a/frontend/src/features/console/ConsolePage.tsx +++ b/frontend/src/features/console/ConsolePage.tsx @@ -1,5 +1,4 @@ -import React, { useContext, useState } from 'react' -import RightPanel from './right-panel/RightPanel' +import { useContext, useState } from 'react' import BottomPanel from './BottomPanel' import { Config, Module, Secret, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb' import { ExpandablePanelProps } from './ExpandablePanel' @@ -13,85 +12,23 @@ import { headerForNode } from './right-panel/RightPanelHeader' import { modulePanels } from './right-panel/ModulePanels' import { secretPanels } from './right-panel/SecretPanels' import { configPanels } from './right-panel/ConfigPanels' +import { ResizablePanels } from '../../components/ResizablePanels' -const MIN_RIGHT_PANEL_WIDTH = 200 -const MIN_BOTTOM_PANEL_HEIGHT = 200 -const TOP_BAR_APPROX_HEIGHT = 44 - -const ConsolePage = () => { +export const ConsolePage = () => { const modules = useContext(modulesContext) const navigate = useNavigate() - const [rightPanelWidth, setRightPanelWidth] = useState(300) - const [bottomPanelHeight, setBottomPanelHeight] = useState(250) - const [isDraggingHorizontal, setIsDraggingHorizontal] = useState(false) - const [isDraggingVertical, setIsDraggingVertical] = useState(false) const [selectedNode, setSelectedNode] = useState(null) - const startDraggingHorizontal = (e: React.MouseEvent) => { - e.preventDefault() - setIsDraggingHorizontal(true) - } - - const startDraggingVertical = (e: React.MouseEvent) => { - e.preventDefault() - setIsDraggingVertical(true) - } - - const stopDragging = () => { - setIsDraggingHorizontal(false) - setIsDraggingVertical(false) - } - - const onDragHorizontal = (e: React.MouseEvent) => { - if (isDraggingHorizontal) { - const newWidth = Math.max(window.innerWidth - e.clientX, MIN_RIGHT_PANEL_WIDTH) - setRightPanelWidth(newWidth > 0 ? newWidth : 0) - } - } - - const onDragVertical = (e: React.MouseEvent) => { - if (isDraggingVertical) { - const newHeight = Math.max(window.innerHeight - e.clientY + TOP_BAR_APPROX_HEIGHT, MIN_BOTTOM_PANEL_HEIGHT) - setBottomPanelHeight(newHeight > 0 ? newHeight : 0) - } - } - return ( } title='Console' /> -
{ - if (isDraggingHorizontal) onDragHorizontal(e) - if (isDraggingVertical) onDragVertical(e) - }} - onMouseUp={stopDragging} - onMouseLeave={stopDragging} - > -
-
- -
-
- -
-
- -
+ } + rightPanelHeader={headerForNode(selectedNode)} + rightPanelPanels={panelsForNode(modules.modules, selectedNode, navigate)} + bottomPanelContent={} + /> ) @@ -110,5 +47,3 @@ const panelsForNode = (modules: Module[], node: FTLNode | null, navigate: Naviga return [] as ExpandablePanelProps[] } } - -export default ConsolePage diff --git a/frontend/src/features/verbs/VerbForm.tsx b/frontend/src/features/verbs/VerbForm.tsx deleted file mode 100644 index 5d32155812..0000000000 --- a/frontend/src/features/verbs/VerbForm.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -import Editor, { Monaco } from '@monaco-editor/react' -import type { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema' -import { JSONSchemaFaker } from 'json-schema-faker' -import React, { useEffect, useState } from 'react' -import { CodeBlock } from '../../components/CodeBlock' -import { useClient } from '../../hooks/use-client' -import { Module, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb' -import { VerbService } from '../../protos/xyz/block/ftl/v1/ftl_connect' -import { Ref } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' -import { useDarkMode } from '../../providers/dark-mode-provider' - -export type Schema = JSONSchema4 | JSONSchema6 | JSONSchema7 - -export const VerbForm = ({ module, verb }: { module?: Module; verb?: Verb }) => { - const client = useClient(VerbService) - const { isDarkMode } = useDarkMode() - const [editorText, setEditorText] = useState('') - const [response, setResponse] = useState(null) - const [error, setError] = useState(null) - const [schema, setSchema] = useState() - const [monaco, setMonaco] = useState() - - useEffect(() => { - if (verb?.jsonRequestSchema) { - JSONSchemaFaker.option('maxItems', 2) - JSONSchemaFaker.option('alwaysFakeOptionals', true) - - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - const verbSchema = JSON.parse(verb.jsonRequestSchema) as Schema - setSchema(verbSchema) - setEditorText(JSON.stringify(JSONSchemaFaker.generate(verbSchema), null, 2)) - } - }, [module, verb]) - - const handleEditorChange = (value: string | undefined) => { - setEditorText(value ?? '') - } - - const handleSubmit: React.FormEventHandler = async (event) => { - event.preventDefault() - - setResponse(null) - setError(null) - - try { - const verbRef: Ref = { - name: verb?.verb?.name, - module: module?.name, - } as Ref - - const buffer = Buffer.from(editorText) - const uint8Array = new Uint8Array(buffer) - const response = await client.call({ verb: verbRef, body: uint8Array }) - if (response.response.case === 'body') { - const jsonString = Buffer.from(response.response.value).toString('utf-8') - - setResponse(JSON.stringify(JSON.parse(jsonString), null, 2)) - } else if (response.response.case === 'error') { - setError(response.response.value.message) - } - } catch (error) { - console.error('There was an error with the request:', error) - setError(String(error)) - } - } - const handleEditorWillMount = (monaco: Monaco) => { - setMonaco(monaco) - } - - useEffect(() => { - schema && - monaco?.languages.json.jsonDefaults.setDiagnosticsOptions({ - validate: true, - schemas: [{ schema, uri: 'http://myserver/foo-schema.json', fileMatch: ['*'] }], - }) - }, [monaco, schema]) - - return ( - <> -
-
- -
-
- -
-
- {response && ( -
- -
- )} - {error && ( -
- {error} -
- )} - - ) -} diff --git a/frontend/src/features/verbs/VerbFormInput.tsx b/frontend/src/features/verbs/VerbFormInput.tsx new file mode 100644 index 0000000000..b41eda3b19 --- /dev/null +++ b/frontend/src/features/verbs/VerbFormInput.tsx @@ -0,0 +1,52 @@ +import { useEffect, useState } from 'react' + +export const VerbFormInput = ( + { requestType, initialPath, requestPath, readOnly, onSubmit }: + { + requestType: string, + initialPath: string, + requestPath: string, + readOnly: boolean, + onSubmit: (path: string) => void + } +) => { + const [path, setPath] = useState(initialPath) + + const handleSubmit: React.FormEventHandler = async (event) => { + event.preventDefault() + onSubmit(path) + } + + useEffect(() => { + setPath(initialPath) + }, [initialPath]) + + return ( +
+
+ + {requestType} + + setPath(event.target.value)} + /> + +
+ {!readOnly && ( + {requestPath} + ) + } +
+ ) +} diff --git a/frontend/src/features/verbs/VerbPage.tsx b/frontend/src/features/verbs/VerbPage.tsx index 1e49dba726..57d62ba2e5 100644 --- a/frontend/src/features/verbs/VerbPage.tsx +++ b/frontend/src/features/verbs/VerbPage.tsx @@ -1,15 +1,17 @@ -import { Square3Stack3DIcon } from '@heroicons/react/24/outline' +import { BoltIcon, Square3Stack3DIcon } from '@heroicons/react/24/outline' import { useContext, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' -import { CodeBlock } from '../../components/CodeBlock' import { Page } from '../../layout' import { CallEvent, EventType, Module, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb' import { modulesContext } from '../../providers/modules-provider' import { SidePanelProvider } from '../../providers/side-panel-provider' import { callFilter, eventTypesFilter, streamEvents } from '../../services/console.service' -import { CallList } from '../calls/CallList' -import { VerbForm } from './VerbForm' import { NotificationType, NotificationsContext } from '../../providers/notifications-provider' +import { ResizablePanels } from '../../components/ResizablePanels' +import { CodeBlock } from '../../components/CodeBlock' +import { ExpandablePanelProps } from '../console/ExpandablePanel' +import { CallList } from '../calls/CallList' +import { VerbRequestForm } from './VerbRequestForm' export const VerbPage = () => { const { deploymentKey, verbName } = useParams() @@ -34,7 +36,6 @@ export const VerbPage = () => { message: `The previous deployment of ${module?.deploymentKey} was not found. Showing the latest deployment of ${module?.name}.${verbName} instead.`, type: NotificationType.Info, }) - setModule(module) } } setModule(module) @@ -57,6 +58,7 @@ export const VerbPage = () => { }, }) } + streamCalls() return () => { @@ -64,6 +66,22 @@ export const VerbPage = () => { } }, [module]) + const panels = [ + { + title: 'Schema', + expanded: true, + children: verb?.verb?.response?.toJsonString() && , + padding: 'p-0', + }, + ] as ExpandablePanelProps[] + + const header = ( +
+ +
Verb
+
+ ) + return ( @@ -75,20 +93,16 @@ export const VerbPage = () => { { label: module?.deploymentKey || '', link: `/deployments/${module?.deploymentKey}` }, ]} /> - -
-
-
- {verb?.verb?.request?.toJsonString() && } -
-
- -
-
-
- -
-
+ + + +
} + rightPanelHeader={header} + rightPanelPanels={panels} + bottomPanelContent={} + /> diff --git a/frontend/src/features/verbs/VerbRequestForm.tsx b/frontend/src/features/verbs/VerbRequestForm.tsx new file mode 100644 index 0000000000..b9541d118a --- /dev/null +++ b/frontend/src/features/verbs/VerbRequestForm.tsx @@ -0,0 +1,152 @@ +import { useEffect, useState } from 'react' +import { Module, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb' +import { Ref } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' +import { classNames } from '../../utils' +import { CodeEditor, InitialState } from '../../components/CodeEditor' +import { useClient } from '../../hooks/use-client' +import { VerbService } from '../../protos/xyz/block/ftl/v1/ftl_connect' +import { VerbFormInput } from './VerbFormInput' +import { createVerbRequest, defaultRequest, httpPopulatedRequestPath, isHttpIngress, requestPath, requestType, simpleJsonSchema } from './verb.utils' + +export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb }) => { + const client = useClient(VerbService) + const [activeTabId, setActiveTabId] = useState('body') + const [initialEditorState, setInitialEditorText] = useState({ initialText: '' }) + const [editorText, setEditorText] = useState('') + const [initialHeadersState, setInitialHeadersText] = useState({ initialText: '' }) + const [headersText, setHeadersText] = useState('') + const [response, setResponse] = useState(null) + const [error, setError] = useState(null) + + const editorTextKey = `${module?.name}-${verb?.verb?.name}-editor-text` + + useEffect(() => { + if (verb) { + const savedValue = localStorage.getItem(editorTextKey) + let value: string + if (savedValue != null && savedValue !== '') { + value = savedValue + } else { + value = defaultRequest(verb) + } + + const schemaString = JSON.stringify(simpleJsonSchema(verb)) + setInitialEditorText({ initialText: value, schema: schemaString }) + localStorage.setItem(editorTextKey, value) + handleEditorTextChanged(value) + + const headerText = '{\n "console": ["example"]\n}' + setInitialHeadersText({ initialText: headerText }) + setHeadersText(headerText) + } + }, [verb, activeTabId]) + + const handleEditorTextChanged = (text: string) => { + setEditorText(text) + localStorage.setItem(editorTextKey, text) + } + + const handleTabClick = (e: React.MouseEvent, id: string) => { + e.preventDefault() + setActiveTabId(id) + } + + const tabs = [ + { id: 'body', name: 'Body' }, + { id: 'jsonschema', name: 'JSONSchema' } + ] + + if (isHttpIngress(verb)) { + tabs.push({ id: 'headers', name: 'Headers' }) + } + + const handleSubmit = async (path: string) => { + setResponse(null) + setError(null) + + try { + const verbRef: Ref = { + name: verb?.verb?.name, + module: module?.name, + } as Ref + + const requestBytes = createVerbRequest(path, verb, editorText, headersText) + const response = await client.call({ verb: verbRef, body: requestBytes }) + if (response.response.case === 'body') { + const jsonString = Buffer.from(response.response.value).toString('utf-8') + + setResponse(JSON.stringify(JSON.parse(jsonString), null, 2)) + } else if (response.response.case === 'error') { + setError(response.response.value.message) + } + } catch (error) { + console.error('There was an error with the request:', error) + setError(String(error)) + } + } + + return ( +
+ +
+ +
+
+ +
+
+
+
+
+ {activeTabId === 'body' && ( + + )} + {activeTabId === 'headers' && ( + + )} + {activeTabId === 'jsonschema' && ( + + )} +
+ +
+ {response && ( + <> +
+

Response

+ + + )} + {error && ( + <> +
+

Error

+ + + )} +
+
+
) +} diff --git a/frontend/src/features/verbs/verb.utils.ts b/frontend/src/features/verbs/verb.utils.ts index 89e468c1e7..73a7a4e154 100644 --- a/frontend/src/features/verbs/verb.utils.ts +++ b/frontend/src/features/verbs/verb.utils.ts @@ -1,5 +1,139 @@ -import { Ref } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' +import { JsonValue } from 'type-fest/source/basic' +import { Module, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb' +import { MetadataCronJob, MetadataIngress, Ref } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' +import { JSONSchemaFaker } from 'json-schema-faker' + +const basePath = 'http://localhost:8892/ingress/' export const verbRefString = (verb: Ref): string => { return `${verb.module}.${verb.name}` } + +interface JsonMap { [key: string]: JsonValue } + +const processJsonValue = (value: JsonValue): JsonValue =>{ + if (Array.isArray(value)) { + return value.map(item => processJsonValue(item)) + } else if (typeof value === 'object' && value !== null) { + const result: JsonMap = {} + Object.entries(value).forEach(([key, val]) => { + result[key] = processJsonValue(val) + }) + return result + } else if (typeof value === 'string') { + return '' + } else if (typeof value === 'number') { + return 0 + } else if (typeof value === 'boolean') { + return false + } + return value +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const simpleJsonSchema = (verb: Verb): any => { + let schema = JSON.parse(verb.jsonRequestSchema) + + if (schema.properties && isHttpIngress(verb)) { + schema = { + ...schema, + type: schema.properties.body.type, + properties: { + body: schema.properties.body + }, + required: schema.required.includes('body') ? ['body'] : [] + } + } + + return schema +} + +export const defaultRequest = (verb?: Verb): string => { + if (!verb || !verb.jsonRequestSchema) { + return '{}' + } + + const schema = simpleJsonSchema(verb) + + JSONSchemaFaker.option({ + alwaysFakeOptionals: false, + useDefaultValue: true, + requiredOnly: true + }) + + let fake = JSONSchemaFaker.generate(schema) + if (fake) { + fake = processJsonValue(fake) + } + + return JSON.stringify(fake, null, 2) ?? '{}' +} + +const ingress = (verb?: Verb) => { + return verb?.verb?.metadata?.find(meta => meta.value.case === 'ingress')?.value?.value as MetadataIngress || null +} + +const cron = (verb?: Verb) => { + return verb?.verb?.metadata?.find(meta => meta.value.case === 'cronJob')?.value?.value as MetadataCronJob || null +} + +export const requestType = (verb?: Verb) => { + const ingress = verb?.verb?.metadata?.find(meta => meta.value.case === 'ingress')?.value?.value as MetadataIngress || null + const cron = verb?.verb?.metadata?.find(meta => meta.value.case === 'cronJob')?.value?.value as MetadataCronJob || null + + return ingress?.method ?? cron?.cron?.toUpperCase() ?? 'CALL' +} + +export const requestPath = (module?: Module, verb?: Verb) => { + const ingress = verb?.verb?.metadata?.find(meta => meta.value.case === 'ingress')?.value?.value as MetadataIngress || null + if (ingress) { + return basePath + ingress.path.map(p => { + switch (p.value.case) { + case 'ingressPathLiteral': + return p.value.value.text + case 'ingressPathParameter': + return `{${p.value.value.name}}` + default: + return '' + } + }).join('/') + } + const cron = verb?.verb?.metadata?.find(meta => meta.value.case === 'cronJob')?.value?.value as MetadataCronJob || null + if (cron) { + return cron.cron + } + + return [module?.name, verb?.verb?.name].filter(Boolean).map(v => v).join('.') +} + +export const httpPopulatedRequestPath = ( module?: Module, verb?: Verb) => { + return requestPath(module, verb).replaceAll(/{([^}]*)}/g, '$1') +} + +export const isHttpIngress = (verb?: Verb) => { + return ingress(verb)?.type === 'http' +} + +export const isCron = (verb?: Verb) => { + return !!cron(verb) +} + +export const createVerbRequest = (path: string, verb?: Verb, editorText?: string, headers?: string) => { + if (!verb || !editorText) { + return new Uint8Array() + } + + const requestJson = JSON.parse(editorText) + + if (isHttpIngress(verb)) { + const httpIngress = ingress(verb) + if (httpIngress) { + requestJson['method'] = httpIngress.method + requestJson['path'] = path.replace(basePath, '') + } + requestJson.headers = JSON.parse(headers ?? '{}') + } + + const buffer = Buffer.from(JSON.stringify(requestJson)) + return new Uint8Array(buffer) +}