diff --git a/docusaurus.config.ts b/docusaurus.config.ts index da14145d8..c477a0706 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -226,5 +226,13 @@ export default { }, } }, + [ + "@docusaurus/plugin-client-redirects", + { + redirects: [ + {to: "/config-generator", from: "/app/config"}, + ], + }, + ], ], } satisfies Config diff --git a/package-lock.json b/package-lock.json index b08348526..0be4abfbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,10 +21,17 @@ "@docusaurus/theme-search-algolia": "3.6.3", "@graphiql/create-fetcher": "^0.1.0", "@mdx-js/react": "^3.0.1", + "@rjsf/core": "^5.24.0", + "@rjsf/utils": "^5.24.0", + "@rjsf/validator-ajv8": "^5.24.0", + "@types/file-saver": "^2.0.7", + "@types/js-yaml": "^4.0.9", "autoprefixer": "^10.4.19", "clsx": "^2.1.1", + "file-saver": "^2.0.5", "graphiql": "^3.3.1", "graphql-ws": "^5.16.0", + "js-yaml": "^4.1.0", "lottie-light-react": "^2.4.0", "lucide-react": "^0.414.0", "postcss": "^8.4.38", @@ -38,6 +45,7 @@ "react-hot-toast": "^2.4.1", "react-on-screen": "^2.1.1", "react-platform-js": "^0.0.1", + "react-select": "^5.8.0", "tailwindcss": "^3.4.4" }, "devDependencies": { @@ -4573,6 +4581,71 @@ "node": ">=18.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, "node_modules/@emotion/is-prop-valid": { "version": "0.8.8", "license": "MIT", @@ -4586,6 +4659,82 @@ "license": "MIT", "optional": true }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/serialize/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "devOptional": true, @@ -6902,6 +7051,91 @@ "integrity": "sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==", "dev": true }, + "node_modules/@rjsf/core": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-5.24.0.tgz", + "integrity": "sha512-SDBUussRIa8ZVuL56HmvbxWV4SlK73hOw5KvZDH7McuQH/awhqbd0O2xE4AVmwN3UKwdwTf8M/ROg6IaKXKC1g==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "markdown-to-jsx": "^7.4.1", + "nanoid": "^3.3.7", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.23.x", + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/utils": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.24.0.tgz", + "integrity": "sha512-R3Dr0982lYrwAP1fdGaiWGsnamNUKhPNTm1P23njNW5DSwGUyJG56UKfW+7ibJMpaLnQZJVMSBgFdjvrwNxE/Q==", + "license": "Apache-2.0", + "dependencies": { + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/utils/node_modules/react-is": { + "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==", + "license": "MIT" + }, + "node_modules/@rjsf/validator-ajv8": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.24.0.tgz", + "integrity": "sha512-A7DOt2ZIWOGHB7jJ4pzFAJrZ4H3lD2N/U4sCrveq3iLbIrXkn8FH/ihDhbqlWX+zLWRIcNzGQA2JYEr8u1KWGw==", + "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.23.x" + } + }, + "node_modules/@rjsf/validator-ajv8/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@rjsf/validator-ajv8/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/@rspack/binding": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.1.3.tgz", @@ -7893,6 +8127,12 @@ "@types/send": "*" } }, + "node_modules/@types/file-saver": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz", + "integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==", + "license": "MIT" + }, "node_modules/@types/gtag.js": { "version": "0.0.12", "license": "MIT" @@ -7965,7 +8205,7 @@ "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -8034,17 +8274,6 @@ "csstype": "^3.0.2" } }, - "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-router": { "version": "5.1.20", "license": "MIT", @@ -8071,6 +8300,15 @@ "@types/react-router": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.0", "license": "MIT" @@ -9253,6 +9491,37 @@ "object.assign": "^4.1.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", "license": "MIT", @@ -10360,6 +10629,27 @@ "version": "5.1.2", "license": "MIT" }, + "node_modules/compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "dependencies": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "license": "MIT" @@ -11759,6 +12049,16 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "2.0.0", "license": "MIT", @@ -12652,6 +12952,22 @@ "fast-decode-uri-component": "^1.0.1" } }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fast-url-parser": { "version": "1.1.3", "dev": true, @@ -12828,6 +13144,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==", + "license": "MIT" + }, "node_modules/filesize": { "version": "8.0.7", "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", @@ -12890,6 +13212,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "license": "MIT", @@ -15115,6 +15443,8 @@ }, "node_modules/js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -15157,6 +15487,29 @@ "dev": true, "license": "(AFL-2.1 OR BSD-3-Clause)" }, + "node_modules/json-schema-compare": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", + "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.4" + } + }, + "node_modules/json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "license": "MIT", + "dependencies": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "license": "MIT" @@ -15206,6 +15559,15 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", @@ -15679,6 +16041,12 @@ "version": "4.17.21", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "license": "MIT" @@ -15924,6 +16292,23 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/markdown-to-jsx": { + "version": "7.7.17", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.7.17.tgz", + "integrity": "sha512-7mG/1feQ0TX5I7YyMZVDgCC/y2I3CiEhIRQIhyov9nGBP5eoVrOXXHuL5ZP8GRfxVZKRiXWJgwXkb9It+nQZfQ==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, "node_modules/mdast-util-directive": { "version": "3.0.0", "license": "MIT", @@ -16334,6 +16719,12 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "license": "MIT" @@ -21308,6 +21699,27 @@ "react": ">=15" } }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "license": "MIT", @@ -21329,6 +21741,22 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/react-waypoint": { "version": "10.3.0", "license": "MIT", @@ -23014,6 +23442,12 @@ "postcss": "^8.4.31" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, "node_modules/subscriptions-transport-ws": { "version": "0.9.19", "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz", @@ -24120,6 +24554,20 @@ } } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", + "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "license": "MIT", @@ -24169,6 +24617,39 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==", + "license": "MIT" + }, + "node_modules/validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" + }, + "node_modules/validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "dependencies": { + "validate.io-number": "^1.0.3" + } + }, + "node_modules/validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "node_modules/validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" + }, "node_modules/value-equal": { "version": "1.0.1", "license": "MIT" diff --git a/package.json b/package.json index 59dbedce6..a01a6ff01 100644 --- a/package.json +++ b/package.json @@ -31,11 +31,19 @@ "@docusaurus/plugin-ideal-image": "3.6.3", "@docusaurus/preset-classic": "3.6.3", "@docusaurus/theme-search-algolia": "3.6.3", + "@graphiql/create-fetcher": "^0.1.0", "@mdx-js/react": "^3.0.1", + "@rjsf/core": "^5.24.0", + "@rjsf/utils": "^5.24.0", + "@rjsf/validator-ajv8": "^5.24.0", + "@types/file-saver": "^2.0.7", + "@types/js-yaml": "^4.0.9", "autoprefixer": "^10.4.19", "clsx": "^2.1.1", + "file-saver": "^2.0.5", "graphiql": "^3.3.1", "graphql-ws": "^5.16.0", + "js-yaml": "^4.1.0", "lottie-light-react": "^2.4.0", "lucide-react": "^0.414.0", "postcss": "^8.4.38", @@ -49,8 +57,8 @@ "react-hot-toast": "^2.4.1", "react-on-screen": "^2.1.1", "react-platform-js": "^0.0.1", - "tailwindcss": "^3.4.4", - "@graphiql/create-fetcher": "^0.1.0" + "react-select": "^5.8.0", + "tailwindcss": "^3.4.4" }, "devDependencies": { "@babel/core": "^7.24.7", diff --git a/src/pages/config-generator.tsx b/src/pages/config-generator.tsx new file mode 100644 index 000000000..dd65f5925 --- /dev/null +++ b/src/pages/config-generator.tsx @@ -0,0 +1,438 @@ + +import React, {useState, useEffect, useCallback, useMemo} from "react" +import Select from "react-select" +import {saveAs} from "file-saver" +import yaml from "js-yaml" +import Layout from "@theme/Layout" + +const SCHEMA_URL = + "https://raw.githubusercontent.com/tailcallhq/tailcall/main/generated/.tailcallrc.schema.json" + +const DEFAULT_CONFIG = { + server: { + port: 8000, + hostname: "0.0.0.0", + workers: 1, + introspection: true, + queryValidation: false, + responseValidation: false, + batchRequests: false, + }, + upstream: { + connectTimeout: 60, + timeout: 600, + keepAliveInterval: 5, + keepAliveTimeout: 60, + userAgent: "Tailcall/1.0", + verifySSL: true, + }, + telemetry: {}, + links: [], +} + +const ConfigGeneratorPage = () => { + const [schema, setSchema] = useState(null) + const [formData, setFormData] = useState>(DEFAULT_CONFIG) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [activeTab, setActiveTab] = useState<"server"|"upstream"|"telemetry"|"links">("server") + const [configOutput, setConfigOutput] = useState("") + const [outputFormat, setOutputFormat] = useState<"json"|"yml">("yml") + const [copied, setCopied] = useState(false) + + useEffect(() => { + const fetchSchema = async () => { + try { + setLoading(true) + const res = await fetch(SCHEMA_URL) + if (!res.ok) throw new Error(`Failed to fetch schema: ${res.status}`) + const schemaData = await res.json() + setSchema(schemaData) + setError(null) + } catch (err: any) { + setError(err.message || "Failed to load schema") + } finally { + setLoading(false) + } + } + fetchSchema() + }, []) + + useEffect(() => { + if (Object.keys(formData).length === 0) return + const cleaned = deepClean(formData) + if (outputFormat === "yml") { + setConfigOutput(yaml.dump(cleaned, {indent: 2, lineWidth: 120, noRefs: true})) + } else { + setConfigOutput(JSON.stringify(cleaned, null, 2)) + } + }, [formData, outputFormat, schema]) + + const handleFieldChange = useCallback((section: string, value: any) => { + setFormData(prev => ({...prev, [section]: value})) + }, []) + + const handleDownload = useCallback(() => { + const ext = outputFormat === "yml" ? "yml" : "json" + const mime = outputFormat === "yml" ? "text/yaml" : "application/json" + const blob = new Blob([configOutput], {type: mime}) + saveAs(blob, `tailcall.${ext}`) + }, [configOutput, outputFormat]) + + const handleCopy = useCallback(async () => { + try { + await navigator.clipboard.writeText(configOutput) + } catch { + const ta = document.createElement("textarea") + ta.value = configOutput + document.body.appendChild(ta) + ta.select() + document.execCommand("copy") + document.body.removeChild(ta) + } + setCopied(true) + setTimeout(() => setCopied(false), 2000) + }, [configOutput]) + + const handleReset = useCallback(() => setFormData(DEFAULT_CONFIG), []) + + if (loading) { + return ( + +
+
+
+

Loading Tailcall config schema...

+
+
+
+ ) + } + + if (error) { + return ( + +
+
+
+

Failed to load schema

+

{error}

+ +
+
+
+ ) + } + + const propSchema = schema?.properties?.[activeTab] + const definitions = schema?.$defs || schema?.definitions + + return ( + + + +
+ {/* Header */} +
+

Tailcall Config Generator

+

+ Visually generate valid Tailcall Runtime Configuration files. Edit fields, then download or copy as JSON or YAML. +

+
+ + {/* Controls */} +
+ Output: + onChange(e.target.checked)} /> + {(value ?? false) ? "Enabled" : "Disabled"} + + {descEl} +
+ ) + + if (type === "integer" || type === "number") return ( +
+ {labelEl} + { const v = e.target.value; onChange(v===""?undefined:type==="integer"?parseInt(v,10):parseFloat(v)) }} /> + {descEl} +
+ ) + + if (type === "string" && s?.enum?.length > 0) { + const opts = s.enum.map((v: any) => ({value: v, label: String(v)})) + return ( +
+ {labelEl} + onChange(e.target.value || undefined)} /> + {descEl} +
+ ) + + if (type === "array") { + const items: any[] = Array.isArray(value) ? value : [] + const itemSchema = s?.items || {type: "string"} + return ( +
+ {labelEl} + {items.map((item, i) => ( +
+
+ { const n = [...items]; n[i] = v; onChange(n) }} /> +
+ +
+ ))} + + {descEl} +
+ ) + } + + if (type === "object") { + if (s?.properties) { +
+ {labelEl} +
+ +
+ {descEl} +
+ } + const entries: [string, any][] = value ? Object.entries(value) : [] + return ( +
+ {labelEl} + {entries.map(([k, v], i) => ( +
+ { const ne = [...entries]; ne[i] = [e.target.value, v]; onChange(Object.fromEntries(ne)) }} + placeholder="Key" /> + { const ne = [...entries]; ne[i] = [k, e.target.value]; onChange(Object.fromEntries(ne)) }} + placeholder="Value" /> + +
+ ))} + + {descEl} +
+ ) + } + + return ( +
+ {labelEl} + { try { onChange(JSON.parse(e.target.value)) } catch { onChange(e.target.value) } }} /> + {descEl} +
+ ) +} + +function deepClean(obj: any): any { + if (Array.isArray(obj)) { const c = obj.map(deepClean).filter((v: any) => v != null); return c.length > 0 ? c : undefined } + if (obj !== null && typeof obj === "object") { + const c: Record = {} + for (const [k, v] of Object.entries(obj)) { const cv = deepClean(v); if (cv != null) c[k] = cv } + return Object.keys(c).length > 0 ? c : undefined + } + return obj +} + +function defaultVal(schema: any, defs: any): any { + if (schema?.$ref) { const p = schema.$ref.replace("#/$defs/","").replace("#/definitions/",""); schema = defs?.[p] || schema } + if (schema?.default !== undefined) return schema.default + if (schema?.oneOf) return defaultVal(schema.oneOf[0], defs) + if (schema?.anyOf) { const nn = schema.anyOf.filter((s: any) => s.type !== "null"); return nn.length > 0 ? defaultVal(nn[0], defs) : null } + switch (schema?.type) { + case "string": return ""; case "integer": case "number": return schema.minimum ?? 0 + case "boolean": return false; case "array": return []; case "object": return {}; default: return "" + } +} + +export default ConfigGeneratorPage diff --git a/src/pages/playground.tsx b/src/pages/playground.tsx index e38dbc11c..364ca87d8 100644 --- a/src/pages/playground.tsx +++ b/src/pages/playground.tsx @@ -1,12 +1,14 @@ -import React, {useEffect} from "react" +import React, {useEffect, useState} from "react" import ReactGA from "react-ga4" import Layout from "@theme/Layout" import PlaygroundPage from "../components/playground" +import ConfigGeneratorPage from "./config-generator" import {useLocation} from "@docusaurus/router" import {PageDescription, PageTitle} from "../constants/titles" const Playground = () => { const location = useLocation() + const [activeTab, setActiveTab] = useState<"graphql" | "config">("graphql") useEffect(() => { ReactGA.send({hitType: "pageview", page: location.pathname, title: "Playground Page"}) @@ -14,7 +16,33 @@ const Playground = () => { return ( - + {/* Tab switcher */} +
+
+ + +
+
+ + {activeTab === "graphql" ? : }
) }