diff --git a/.github/workflows/python.yaml b/.github/workflows/python.yaml index cd792ec975..0ac51d4705 100644 --- a/.github/workflows/python.yaml +++ b/.github/workflows/python.yaml @@ -47,6 +47,17 @@ jobs: run: pip install mypy && mypy --install-types --non-interactive xinference - name: codespell run: pip install codespell && codespell xinference + - name: Set up Node.js + uses: actions/setup-node@v1 + with: + node-version: 16 + # ESLint and Prettier must be in `package.json` + - name: Install Node.js dependencies + run: cd xinference/web/ui && npm ci + - name: ESLint Check + run: cd xinference/web/ui && npx eslint . + - name: Prettier Check + run: cd xinference/web/ui && ./node_modules/.bin/prettier --check . build_test_job: runs-on: ${{ matrix.os }} diff --git a/xinference/web/ui/.eslintignore b/xinference/web/ui/.eslintignore new file mode 100644 index 0000000000..563fcbd9ad --- /dev/null +++ b/xinference/web/ui/.eslintignore @@ -0,0 +1,5 @@ +.idea +.github +node_modules +build +public diff --git a/xinference/web/ui/.eslintrc.yml b/xinference/web/ui/.eslintrc.yml new file mode 100644 index 0000000000..194a169d94 --- /dev/null +++ b/xinference/web/ui/.eslintrc.yml @@ -0,0 +1,30 @@ +env: + browser: true + es2021: true + node: true +extends: + - 'eslint:recommended' + - 'plugin:react/recommended' + - 'prettier' +parserOptions: + parser: '@babel/eslint-parser' + requireConfigFile: false + ecmaFeatures: + jsx: true + ecmaVersion: 12 + sourceType: module +plugins: + - react + - simple-import-sort +rules: + new-cap: 'error' + no-var: 'error' + simple-import-sort/imports: 'error' + simple-import-sort/exports: 'error' + quote-props: ['error', 'consistent'] + 'react/react-in-jsx-scope': 'off' + 'react/prop-types': 'off' + 'react/jsx-key': 'off' +settings: + react: + version: 'detect' diff --git a/xinference/web/ui/.prettierignore b/xinference/web/ui/.prettierignore new file mode 100644 index 0000000000..563fcbd9ad --- /dev/null +++ b/xinference/web/ui/.prettierignore @@ -0,0 +1,5 @@ +.idea +.github +node_modules +build +public diff --git a/xinference/web/ui/.prettierrc.yml b/xinference/web/ui/.prettierrc.yml new file mode 100644 index 0000000000..a794136336 --- /dev/null +++ b/xinference/web/ui/.prettierrc.yml @@ -0,0 +1,9 @@ +trailingComma: 'es5' +tabWidth: 2 +semi: false +singleQuote: true +printWidth: 80 +bracketSpacing: true +bracketSameLine: false +arrowParens: 'always' +quoteProps: 'consistent' diff --git a/xinference/web/ui/package-lock.json b/xinference/web/ui/package-lock.json index 7c34e83118..dfd1fc9d1b 100644 --- a/xinference/web/ui/package-lock.json +++ b/xinference/web/ui/package-lock.json @@ -37,7 +37,14 @@ "yup": "^1.2.0" }, "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "^7.21.11" + "@babel/core": "^7.21.0", + "@babel/eslint-parser": "^7.19.1", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-react": "^7.24.0", + "eslint-plugin-simple-import-sort": "^8.0.0", + "prettier": "2.8.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2497,44 +2504,36 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dependencies": { "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dependencies": { "type-fest": "^0.20.2" }, @@ -2545,15 +2544,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/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==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "engines": { + "node": ">= 4" } }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { @@ -2568,9 +2564,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -2645,13 +2641,13 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^1.2.0", "debug": "^4.1.1", - "minimatch": "^3.0.5" + "minimatch": "^3.0.4" }, "engines": { "node": ">=10.10.0" @@ -3837,26 +3833,6 @@ "eslint-scope": "5.1.1" } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/@nicolo-ribaudo/semver-v6": { "version": "6.3.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz", @@ -4347,9 +4323,9 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" }, "node_modules/@rushstack/eslint-patch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", - "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.0.tgz", + "integrity": "sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA==" }, "node_modules/@sinclair/typebox": { "version": "0.24.51", @@ -5472,9 +5448,9 @@ "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==" + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==" }, "node_modules/@types/send": { "version": "0.17.1", @@ -5732,26 +5708,6 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", @@ -5768,6 +5724,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -6071,6 +6032,14 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -6171,14 +6140,14 @@ "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "is-string": "^1.0.7" }, "engines": { @@ -6196,14 +6165,32 @@ "node": ">=8" } }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -6214,13 +6201,13 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -6260,21 +6247,57 @@ "get-intrinsic": "^1.1.3" } }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "engines": { + "node": ">=8" + } }, "node_modules/async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, + "node_modules/asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dependencies": { + "has-symbols": "^1.0.3" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -6332,9 +6355,9 @@ } }, "node_modules/axe-core": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", - "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", "engines": { "node": ">=4" } @@ -6824,12 +6847,13 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7908,6 +7932,19 @@ "node": ">= 10" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -7917,10 +7954,11 @@ } }, "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dependencies": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -8254,6 +8292,18 @@ "node": ">=10.13.0" } }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -8279,24 +8329,25 @@ } }, "node_modules/es-abstract": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.3.tgz", - "integrity": "sha512-ZU4miiY1j3sGPFLJ34VJXEqhpmL+HGByCinGHv4HC+Fxl2fI2Z4yR6tl0mORnDr6PA8eihWo4LmSWDbvhALckg==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dependencies": { "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -8304,20 +8355,23 @@ "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", + "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.10" + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -8350,6 +8404,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-iterator-helpers": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", + "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", + "dependencies": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.0.1" + } + }, "node_modules/es-module-lexer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", @@ -8443,95 +8518,81 @@ } }, "node_modules/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.3.2", + "debug": "^4.0.1", "doctrine": "^3.0.0", + "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", - "esquery": "^1.4.2", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.0.4", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^10.12.0 || >=12.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-react-app": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", - "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" }, "peerDependencies": { - "eslint": "^8.0.0" + "eslint": ">=7.0.0" } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dependencies": { "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -8566,43 +8627,28 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", - "dependencies": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@babel/plugin-syntax-flow": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.9", - "eslint": "^8.1.0" - } - }, "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", + "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" }, "engines": { "node": ">=4" @@ -8662,26 +8708,26 @@ } }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" }, "engines": { "node": ">=4.0" @@ -8690,14 +8736,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-plugin-react": { "version": "7.32.2", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", @@ -8772,10 +8810,19 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz", + "integrity": "sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-plugin-testing-library": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", - "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz", + "integrity": "sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw==", "dependencies": { "@typescript-eslint/utils": "^5.58.0" }, @@ -8788,24 +8835,51 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "engines": { + "node": ">=4" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -8920,6 +8994,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -8934,11 +9016,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -8981,6 +9058,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/eslint/node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", @@ -9003,15 +9099,12 @@ "node": ">=8" } }, - "node_modules/eslint/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==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "node_modules/eslint/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "engines": { + "node": ">= 4" } }, "node_modules/eslint/node_modules/supports-color": { @@ -9037,19 +9130,35 @@ } }, "node_modules/espree": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", - "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" }, - "funding": { - "url": "https://opencollective.com/eslint" + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "engines": { + "node": ">=4" } }, "node_modules/esprima": { @@ -9750,19 +9859,22 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -9771,6 +9883,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" + }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -9796,14 +9913,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10078,6 +10195,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -10525,6 +10653,20 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -10574,11 +10716,11 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10620,6 +10762,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -10636,6 +10789,20 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -10815,15 +10982,11 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.11" }, "engines": { "node": ">= 0.4" @@ -10985,6 +11148,18 @@ "node": ">=8" } }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, "node_modules/jake": { "version": "10.8.7", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", @@ -13075,9 +13250,9 @@ } }, "node_modules/jsx-ast-utils": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz", - "integrity": "sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -13118,11 +13293,14 @@ "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" }, "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dependencies": { - "language-subtag-registry": "~0.3.2" + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/launch-editor": { @@ -13232,6 +13410,11 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -13685,9 +13868,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -13733,26 +13916,26 @@ } }, "node_modules/object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -13779,6 +13962,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, "node_modules/object.hasown": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", @@ -13792,13 +13986,13 @@ } }, "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -15393,6 +15587,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz", + "integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -15442,6 +15651,14 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", @@ -15920,37 +16137,322 @@ } } }, - "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==", + "node_modules/react-scripts/node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "node_modules/react-scripts/node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dependencies": { - "pify": "^2.3.0" + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/react-scripts/node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==" + }, + "node_modules/react-scripts/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-scripts/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/react-scripts/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/react-scripts/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/react-scripts/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/react-scripts/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/eslint": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/react-scripts/node_modules/eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@babel/plugin-syntax-flow": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.9", + "eslint": "^8.1.0" + } + }, + "node_modules/react-scripts/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/react-scripts/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/react-scripts/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-scripts/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/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==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/react-scripts/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-scripts/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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "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/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { "node": ">= 6" @@ -15990,6 +16492,25 @@ "node": ">=8" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -16025,13 +16546,13 @@ "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "set-function-name": "^2.0.0" }, "engines": { "node": ">= 0.4" @@ -16040,6 +16561,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/regexpu-core": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", @@ -16122,11 +16654,11 @@ "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "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.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -16343,12 +16875,12 @@ } }, "node_modules/safe-array-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", - "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -16658,6 +17190,33 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -16721,6 +17280,52 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -16947,13 +17552,13 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -16963,26 +17568,26 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -17284,6 +17889,41 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/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==" + }, "node_modules/tailwindcss": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", @@ -17667,6 +18307,36 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typed-array-byte-offset": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", @@ -17896,6 +18566,11 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==" + }, "node_modules/v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", @@ -18265,26 +18940,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -18377,6 +19032,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-collection": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", @@ -18392,16 +19072,15 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.10.tgz", - "integrity": "sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dependencies": { "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.4", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" diff --git a/xinference/web/ui/package.json b/xinference/web/ui/package.json index 5bbe6599e0..86abc72cfb 100644 --- a/xinference/web/ui/package.json +++ b/xinference/web/ui/package.json @@ -36,7 +36,8 @@ "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "format": "eslint --fix . && prettier . --write" }, "eslintConfig": { "extends": [ @@ -57,6 +58,13 @@ ] }, "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "^7.21.11" + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@babel/core": "^7.21.0", + "@babel/eslint-parser": "^7.19.1", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-react": "^7.24.0", + "eslint-plugin-simple-import-sort": "^8.0.0", + "prettier": "2.8.0" } } diff --git a/xinference/web/ui/src/App.js b/xinference/web/ui/src/App.js index e5631ef021..693c872584 100644 --- a/xinference/web/ui/src/App.js +++ b/xinference/web/ui/src/App.js @@ -1,15 +1,15 @@ -import { CssBaseline, ThemeProvider } from "@mui/material"; -import { HashRouter, Route, Routes } from "react-router-dom"; -import { ApiContextProvider } from "./components/apiContext"; -import { useMode } from "./theme"; -import Layout from "./scenes/_layout"; +import { CssBaseline, ThemeProvider } from '@mui/material' +import { HashRouter, Route, Routes } from 'react-router-dom' -import RunningModels from "./scenes/running_models"; -import LaunchModel from "./scenes/launch_model"; -import RegisterModel from "./scenes/register_model"; +import { ApiContextProvider } from './components/apiContext' +import Layout from './scenes/_layout' +import LaunchModel from './scenes/launch_model' +import RegisterModel from './scenes/register_model' +import RunningModels from './scenes/running_models' +import { useMode } from './theme' function App() { - const [theme] = useMode(); + const [theme] = useMode() return (
@@ -27,7 +27,7 @@ function App() {
- ); + ) } -export default App; +export default App diff --git a/xinference/web/ui/src/components/MenuSide.js b/xinference/web/ui/src/components/MenuSide.js index 134284f584..f30db61e89 100644 --- a/xinference/web/ui/src/components/MenuSide.js +++ b/xinference/web/ui/src/components/MenuSide.js @@ -1,4 +1,10 @@ -import { useEffect, useState } from "react"; +import { + AddBoxOutlined, + ChevronRightOutlined, + GitHub, + RocketLaunchOutlined, + SmartToyOutlined, +} from '@mui/icons-material' import { Box, Drawer, @@ -9,70 +15,64 @@ import { ListItemText, Typography, useTheme, -} from "@mui/material"; -import { - ChevronRightOutlined, - RocketLaunchOutlined, - SmartToyOutlined, - AddBoxOutlined, - GitHub, - LibraryBooksOutlined, -} from "@mui/icons-material"; -import icon from "../media/icon.webp"; -import { useLocation, useNavigate } from "react-router-dom"; +} from '@mui/material' +import { useEffect, useState } from 'react' +import { useLocation, useNavigate } from 'react-router-dom' + +import icon from '../media/icon.webp' const navItems = [ { - text: "Launch Model", + text: 'Launch Model', icon: , }, { - text: "Running Models", + text: 'Running Models', icon: , }, { - text: "Register Model", + text: 'Register Model', icon: , }, { - text: "Contact Us", + text: 'Contact Us', icon: , }, -]; +] const MenuSide = () => { - const theme = useTheme(); - const { pathname } = useLocation(); - const [active, setActive] = useState(""); - const navigate = useNavigate(); + const theme = useTheme() + const { pathname } = useLocation() + const [active, setActive] = useState('') + const navigate = useNavigate() const [drawerWidth, setDrawerWidth] = useState( - `${Math.min(Math.max(window.innerWidth * 0.2, 287), 320)}px`, - ); + `${Math.min(Math.max(window.innerWidth * 0.2, 287), 320)}px` + ) useEffect(() => { - setActive(pathname.substring(1)); - }, [pathname]); + setActive(pathname.substring(1)) + }, [pathname]) useEffect(() => { - const screenWidth = window.innerWidth; - const maxDrawerWidth = Math.min(Math.max(screenWidth * 0.2, 287), 320); - setDrawerWidth(`${maxDrawerWidth}px`); + const screenWidth = window.innerWidth + const maxDrawerWidth = Math.min(Math.max(screenWidth * 0.2, 287), 320) + setDrawerWidth(`${maxDrawerWidth}px`) // Update the drawer width on window resize const handleResize = () => { - const newScreenWidth = window.innerWidth; + const newScreenWidth = window.innerWidth const newMaxDrawerWidth = Math.min( Math.max(newScreenWidth * 0.2, 287), - 320, - ); - setDrawerWidth(`${newMaxDrawerWidth}px`); - }; + 320 + ) + setDrawerWidth(`${newMaxDrawerWidth}px`) + } - window.addEventListener("resize", handleResize); + window.addEventListener('resize', handleResize) return () => { - window.removeEventListener("resize", handleResize); - }; - }, []); + window.removeEventListener('resize', handleResize) + } + }, []) return ( { flexShrink: 0, [`& .MuiDrawer-paper`]: { width: drawerWidth, - boxSizing: "border-box", + boxSizing: 'border-box', }, }} > @@ -108,11 +108,11 @@ const MenuSide = () => { height="60px" width="60px" borderRadius="50%" - sx={{ objectFit: "cover", mr: 1.5 }} + sx={{ objectFit: 'cover', mr: 1.5 }} /> - {"Xinference"} + {'Xinference'} @@ -126,54 +126,54 @@ const MenuSide = () => { {navItems.map(({ text, icon }) => { if (!icon) { return ( - + {text} - ); + ) } - const link = text.toLowerCase().replace(" ", "_"); - console.log(link); + const link = text.toLowerCase().replace(' ', '_') + console.log(link) return ( { - if (link === "contact_us") { + if (link === 'contact_us') { window.open( - "https://github.com/xorbitsai/inference", - "_blank", - "noreferrer", - ); - } else if (link === "launch_model") { - navigate(`/`); - setActive(link); - console.log(active); + 'https://github.com/xorbitsai/inference', + '_blank', + 'noreferrer' + ) + } else if (link === 'launch_model') { + navigate(`/`) + setActive(link) + console.log(active) } else { - navigate(`/${link}`); - setActive(link); - console.log(active); + navigate(`/${link}`) + setActive(link) + console.log(active) } }} > {icon} - + - ); + ) })} - ); -}; + ) +} -export default MenuSide; +export default MenuSide diff --git a/xinference/web/ui/src/components/Title.js b/xinference/web/ui/src/components/Title.js index 7144da2bd5..a28cfd5d67 100644 --- a/xinference/web/ui/src/components/Title.js +++ b/xinference/web/ui/src/components/Title.js @@ -1,4 +1,4 @@ -import { Typography, Box } from "@mui/material"; +import { Box, Typography } from '@mui/material' const Title = ({ title, subtitle }) => { return ( @@ -7,7 +7,7 @@ const Title = ({ title, subtitle }) => { variant="h2" color="#141414" fontWeight="bold" - sx={{ m: "0 0 5px 0" }} + sx={{ m: '0 0 5px 0' }} > {title} @@ -15,7 +15,7 @@ const Title = ({ title, subtitle }) => { {subtitle} - ); -}; + ) +} -export default Title; +export default Title diff --git a/xinference/web/ui/src/components/apiContext.js b/xinference/web/ui/src/components/apiContext.js index 668e0a6d4f..8b55725200 100644 --- a/xinference/web/ui/src/components/apiContext.js +++ b/xinference/web/ui/src/components/apiContext.js @@ -1,16 +1,16 @@ -import React, { createContext, useState } from "react"; +import React, { createContext, useState } from 'react' -export const ApiContext = createContext(); +export const ApiContext = createContext() export const ApiContextProvider = ({ children }) => { - const [isCallingApi, setIsCallingApi] = useState(false); - const [isUpdatingModel, setIsUpdatingModel] = useState(false); - let endPoint = ""; - if (!process.env.NODE_ENV || process.env.NODE_ENV === "development") { - endPoint = "http://127.0.0.1:9997"; + const [isCallingApi, setIsCallingApi] = useState(false) + const [isUpdatingModel, setIsUpdatingModel] = useState(false) + let endPoint = '' + if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') { + endPoint = 'http://127.0.0.1:9997' } else { - const fullUrl = window.location.href; - endPoint = fullUrl.split("/ui")[0]; + const fullUrl = window.location.href + endPoint = fullUrl.split('/ui')[0] } return ( @@ -25,5 +25,5 @@ export const ApiContextProvider = ({ children }) => { > {children} - ); -}; + ) +} diff --git a/xinference/web/ui/src/index.css b/xinference/web/ui/src/index.css index fcf5610c29..30eb6dbfd4 100644 --- a/xinference/web/ui/src/index.css +++ b/xinference/web/ui/src/index.css @@ -1,4 +1,4 @@ -@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"); +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap'); html, body, @@ -6,7 +6,7 @@ body, .app { height: 100%; width: 100%; - font-family: "Inter", sans-serif; + font-family: 'Inter', sans-serif; } ::-webkit-scrollbar { diff --git a/xinference/web/ui/src/index.js b/xinference/web/ui/src/index.js index 1ad4ac23a1..34d5faf9cb 100644 --- a/xinference/web/ui/src/index.js +++ b/xinference/web/ui/src/index.js @@ -1,10 +1,11 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; -import App from "./App"; +import React from 'react' +import ReactDOM from 'react-dom/client' -const root = ReactDOM.createRoot(document.getElementById("root")); +import App from './App' + +const root = ReactDOM.createRoot(document.getElementById('root')) root.render( - , -); + +) diff --git a/xinference/web/ui/src/scenes/_layout/index.js b/xinference/web/ui/src/scenes/_layout/index.js index 17e064c200..47f0bb9122 100644 --- a/xinference/web/ui/src/scenes/_layout/index.js +++ b/xinference/web/ui/src/scenes/_layout/index.js @@ -1,7 +1,8 @@ -import React from "react"; -import { Box } from "@mui/material"; -import { Outlet } from "react-router-dom"; -import MenuSide from "../../components/MenuSide"; +import { Box } from '@mui/material' +import React from 'react' +import { Outlet } from 'react-router-dom' + +import MenuSide from '../../components/MenuSide' const Layout = () => { return ( @@ -11,7 +12,7 @@ const Layout = () => { - ); -}; + ) +} -export default Layout; +export default Layout diff --git a/xinference/web/ui/src/scenes/launch_model/embeddingCard.js b/xinference/web/ui/src/scenes/launch_model/embeddingCard.js index 20dfe33caa..6a207ce249 100644 --- a/xinference/web/ui/src/scenes/launch_model/embeddingCard.js +++ b/xinference/web/ui/src/scenes/launch_model/embeddingCard.js @@ -1,180 +1,180 @@ -import React, { useState, useContext, useEffect } from "react"; -import { v1 as uuidv1 } from "uuid"; -import { ApiContext } from "../../components/apiContext"; -import { Box, Chip } from "@mui/material"; -import { CircularProgress } from "@mui/material"; -import { UndoOutlined, RocketLaunchOutlined } from "@mui/icons-material"; +import { RocketLaunchOutlined, UndoOutlined } from '@mui/icons-material' +import { Box, Chip, CircularProgress } from '@mui/material' +import React, { useContext, useEffect, useState } from 'react' +import { v1 as uuidv1 } from 'uuid' -const CARD_HEIGHT = 270; -const CARD_WIDTH = 270; +import { ApiContext } from '../../components/apiContext' + +const CARD_HEIGHT = 270 +const CARD_WIDTH = 270 const EmbeddingCard = ({ url, modelData }) => { - const [hover, setHover] = useState(false); - const [selected, setSelected] = useState(false); - const { isCallingApi, setIsCallingApi } = useContext(ApiContext); - const { isUpdatingModel } = useContext(ApiContext); + const [hover, setHover] = useState(false) + const [selected, setSelected] = useState(false) + const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isUpdatingModel } = useContext(ApiContext) // UseEffects for parameter selection, change options based on previous selections useEffect(() => { - return; - }, [modelData]); + return + }, [modelData]) const launchModel = (url) => { if (isCallingApi || isUpdatingModel) { - return; + return } - setIsCallingApi(true); + setIsCallingApi(true) - const uuid = uuidv1(); + const uuid = uuidv1() const modelDataWithID = { model_uid: uuid, model_name: modelData.model_name, - model_type: "embedding", - }; + model_type: 'embedding', + } // First fetch request to initiate the model - fetch(url + "/v1/models", { - method: "POST", + fetch(url + '/v1/models', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify(modelDataWithID), }) - .then((response) => { - setIsCallingApi(false); + .then(() => { + setIsCallingApi(false) }) .catch((error) => { - console.error("Error:", error); - setIsCallingApi(false); - }); - }; + console.error('Error:', error) + setIsCallingApi(false) + }) + } const styles = { container: { - display: "block", - position: "relative", + display: 'block', + position: 'relative', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - borderRadius: "20px", - background: "white", - overflow: "hidden", + border: '1px solid #ddd', + borderRadius: '20px', + background: 'white', + overflow: 'hidden', }, containerSelected: { - display: "block", - position: "relative", + display: 'block', + position: 'relative', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - borderRadius: "20px", - background: "white", - overflow: "hidden", - boxShadow: "0 0 2px #00000099", + border: '1px solid #ddd', + borderRadius: '20px', + background: 'white', + overflow: 'hidden', + boxShadow: '0 0 2px #00000099', }, descriptionCard: { - position: "relative", - top: "-1px", - left: "-1px", + position: 'relative', + top: '-1px', + left: '-1px', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - padding: "20px", - borderRadius: "20px", - background: "white", + border: '1px solid #ddd', + padding: '20px', + borderRadius: '20px', + background: 'white', }, parameterCard: { - position: "relative", + position: 'relative', top: `-${CARD_HEIGHT + 1}px`, - left: "-1px", + left: '-1px', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - padding: "20px", - borderRadius: "20px", - background: "white", + border: '1px solid #ddd', + padding: '20px', + borderRadius: '20px', + background: 'white', }, img: { - display: "block", - margin: "0 auto", - width: "180px", - height: "180px", - objectFit: "cover", - borderRadius: "10px", + display: 'block', + margin: '0 auto', + width: '180px', + height: '180px', + objectFit: 'cover', + borderRadius: '10px', }, titleContainer: { - minHeight: "120px", + minHeight: '120px', }, h2: { - margin: "10px 10px", - fontSize: "20px", + margin: '10px 10px', + fontSize: '20px', }, buttonsContainer: { - display: "flex", - margin: "0 auto", - marginTop: "120px", - border: "none", - justifyContent: "space-between", - alignItems: "center", + display: 'flex', + margin: '0 auto', + marginTop: '120px', + border: 'none', + justifyContent: 'space-between', + alignItems: 'center', }, buttonContainer: { - width: "45%", - borderWidth: "0px", - backgroundColor: "transparent", - paddingLeft: "0px", - paddingRight: "0px", + width: '45%', + borderWidth: '0px', + backgroundColor: 'transparent', + paddingLeft: '0px', + paddingRight: '0px', }, buttonItem: { - width: "100%", - margin: "0 auto", - padding: "5px", - display: "flex", - justifyContent: "center", - borderRadius: "4px", - border: "1px solid #e5e7eb", - borderWidth: "1px", - borderColor: "#e5e7eb", + width: '100%', + margin: '0 auto', + padding: '5px', + display: 'flex', + justifyContent: 'center', + borderRadius: '4px', + border: '1px solid #e5e7eb', + borderWidth: '1px', + borderColor: '#e5e7eb', }, instructionText: { - fontSize: "12px", - color: "#666666", - fontStyle: "italic", - margin: "10px 0", - textAlign: "center", + fontSize: '12px', + color: '#666666', + fontStyle: 'italic', + margin: '10px 0', + textAlign: 'center', }, slideIn: { - transform: "translateX(0%)", - transition: "transform 0.2s ease-in-out", + transform: 'translateX(0%)', + transition: 'transform 0.2s ease-in-out', }, slideOut: { - transform: "translateX(100%)", - transition: "transform 0.2s ease-in-out", + transform: 'translateX(100%)', + transition: 'transform 0.2s ease-in-out', }, iconRow: { - display: "flex", - justifyContent: "space-between", - alignItems: "center", + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', }, iconItem: { - display: "flex", - flexDirection: "column", - alignItems: "center", - margin: "20px", + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + margin: '20px', }, boldIconText: { - fontWeight: "bold", - fontSize: "1.2em", + fontWeight: 'bold', + fontSize: '1.2em', }, muiIcon: { - fontSize: "1.5em", + fontSize: '1.5em', }, smallText: { - fontSize: "0.8em", + fontSize: '0.8em', }, langRow: { - margin: "2px 5px 40px 5px", + margin: '2px 5px 40px 5px', }, - }; + } // Set two different states based on mouse hover return ( @@ -184,7 +184,7 @@ const EmbeddingCard = ({ url, modelData }) => { onMouseLeave={() => setHover(false)} onClick={() => { if (!selected) { - setSelected(true); + setSelected(true) } }} > @@ -194,20 +194,20 @@ const EmbeddingCard = ({ url, modelData }) => {

{modelData.model_name}

{(() => { - if (modelData.language.includes("en")) { + if (modelData.language.includes('en')) { return ( - ); + ) } })()} {(() => { - if (modelData.language.includes("zh")) { - return ; + if (modelData.language.includes('zh')) { + return } })()}
@@ -250,30 +250,30 @@ const EmbeddingCard = ({ url, modelData }) => { if (isCallingApi || isUpdatingModel) { return ( - ); + ) } else if (!modelData) { return ( - ); + ) } else { return ( - ); + ) } })()} @@ -289,7 +289,7 @@ const EmbeddingCard = ({ url, modelData }) => { - ); -}; + ) +} -export default EmbeddingCard; +export default EmbeddingCard diff --git a/xinference/web/ui/src/scenes/launch_model/index.js b/xinference/web/ui/src/scenes/launch_model/index.js index fa08ab8940..d0691ca3c3 100644 --- a/xinference/web/ui/src/scenes/launch_model/index.js +++ b/xinference/web/ui/src/scenes/launch_model/index.js @@ -1,23 +1,24 @@ -import React from "react"; -import Title from "../../components/Title"; -import LaunchLLM from "./launchLLM"; -import LaunchEmbedding from "./launchEmbedding"; -import LaunchRerank from "./launchRerank"; -import { Box, Tab } from "@mui/material"; -import { TabContext, TabList, TabPanel } from "@mui/lab"; +import { TabContext, TabList, TabPanel } from '@mui/lab' +import { Box, Tab } from '@mui/material' +import React from 'react' + +import Title from '../../components/Title' +import LaunchEmbedding from './launchEmbedding' +import LaunchLLM from './launchLLM' +import LaunchRerank from './launchRerank' const LaunchModel = () => { - const [value, setValue] = React.useState("1"); + const [value, setValue] = React.useState('1') const handleTabChange = (event, newValue) => { - setValue(newValue); - }; + setValue(newValue) + } return ( <TabContext value={value}> - <Box sx={{ borderBottom: 1, borderColor: "divider" }}> + <Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <TabList value={value} onChange={handleTabChange} aria-label="tabs"> <Tab label="Language Models" value="1" /> <Tab label="Embedding Models" value="2" /> @@ -35,7 +36,7 @@ const LaunchModel = () => { </TabPanel> </TabContext> </Box> - ); -}; + ) +} -export default LaunchModel; +export default LaunchModel diff --git a/xinference/web/ui/src/scenes/launch_model/launchEmbedding.js b/xinference/web/ui/src/scenes/launch_model/launchEmbedding.js index 55aa23e2c0..47803efa77 100644 --- a/xinference/web/ui/src/scenes/launch_model/launchEmbedding.js +++ b/xinference/web/ui/src/scenes/launch_model/launchEmbedding.js @@ -1,89 +1,90 @@ -import React, { useContext, useState, useEffect } from "react"; -import EmbeddingCard from "./embeddingCard"; -import { Box, TextField, FormControl } from "@mui/material"; -import { ApiContext } from "../../components/apiContext"; +import { Box, FormControl, TextField } from '@mui/material' +import React, { useContext, useEffect, useState } from 'react' + +import { ApiContext } from '../../components/apiContext' +import EmbeddingCard from './embeddingCard' const LaunchEmbedding = () => { - let endPoint = useContext(ApiContext).endPoint; - const [registrationData, setRegistrationData] = useState([]); - const { isCallingApi, setIsCallingApi } = useContext(ApiContext); - const { isUpdatingModel } = useContext(ApiContext); + let endPoint = useContext(ApiContext).endPoint + const [registrationData, setRegistrationData] = useState([]) + const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isUpdatingModel } = useContext(ApiContext) // States used for filtering - const [searchTerm, setSearchTerm] = useState(""); + const [searchTerm, setSearchTerm] = useState('') const handleChange = (event) => { - setSearchTerm(event.target.value); - }; + setSearchTerm(event.target.value) + } const filter = (registration) => { - if (!registration || typeof searchTerm !== "string") return false; + if (!registration || typeof searchTerm !== 'string') return false const modelName = registration.model_name ? registration.model_name.toLowerCase() - : ""; + : '' if (!modelName.includes(searchTerm.toLowerCase())) { - return false; + return false } - return true; - }; + return true + } const update = async () => { - if (isCallingApi || isUpdatingModel) return; + if (isCallingApi || isUpdatingModel) return try { - setIsCallingApi(true); + setIsCallingApi(true) const response = await fetch( `${endPoint}/v1/model_registrations/embedding`, { - method: "GET", - }, - ); + method: 'GET', + } + ) - const registrations = await response.json(); + const registrations = await response.json() const newRegistrationData = await Promise.all( registrations.map(async (registration) => { const desc = await fetch( `${endPoint}/v1/model_registrations/embedding/${registration.model_name}`, { - method: "GET", - }, - ); + method: 'GET', + } + ) return { ...(await desc.json()), is_builtin: registration.is_builtin, - }; - }), - ); + } + }) + ) - setRegistrationData(newRegistrationData); + setRegistrationData(newRegistrationData) } catch (error) { - console.error("Error:", error); + console.error('Error:', error) } finally { - setIsCallingApi(false); + setIsCallingApi(false) } - }; + } useEffect(() => { - update(); + update() // eslint-disable-next-line - }, []); + }, []) const style = { - display: "grid", - gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", - paddingLeft: "2rem", - gridGap: "2rem 0rem", - }; + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', + paddingLeft: '2rem', + gridGap: '2rem 0rem', + } return ( <Box m="20px"> <div style={{ - display: "grid", - gridTemplateColumns: "1fr", - margin: "30px 2rem", + display: 'grid', + gridTemplateColumns: '1fr', + margin: '30px 2rem', }} > <FormControl variant="outlined" margin="normal"> @@ -105,7 +106,7 @@ const LaunchEmbedding = () => { ))} </div> </Box> - ); -}; + ) +} -export default LaunchEmbedding; +export default LaunchEmbedding diff --git a/xinference/web/ui/src/scenes/launch_model/launchLLM.js b/xinference/web/ui/src/scenes/launch_model/launchLLM.js index 281cf57098..6a3ac7505c 100644 --- a/xinference/web/ui/src/scenes/launch_model/launchLLM.js +++ b/xinference/web/ui/src/scenes/launch_model/launchLLM.js @@ -1,115 +1,101 @@ -import React, { useContext, useState, useEffect } from "react"; -import ModelCard from "./modelCard"; -import Title from "../../components/Title"; import { Box, - TextField, FormControl, - Select, - MenuItem, InputLabel, - Tabs, - Tab, -} from "@mui/material"; -import { ApiContext } from "../../components/apiContext"; + MenuItem, + Select, + TextField, +} from '@mui/material' +import React, { useContext, useEffect, useState } from 'react' + +import { ApiContext } from '../../components/apiContext' +import ModelCard from './modelCard' const LaunchLLM = () => { - let endPoint = useContext(ApiContext).endPoint; - const [registrationData, setRegistrationData] = useState([]); - const { isCallingApi, setIsCallingApi } = useContext(ApiContext); - const { isUpdatingModel } = useContext(ApiContext); + let endPoint = useContext(ApiContext).endPoint + const [registrationData, setRegistrationData] = useState([]) + const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isUpdatingModel } = useContext(ApiContext) // States used for filtering - const [searchTerm, setSearchTerm] = useState(""); - - const [modelAbility, setModelAbility] = useState("all"); - const [tabValue, setTabValue] = React.useState(0); + const [searchTerm, setSearchTerm] = useState('') - const handleTabChange = (event, newValue) => { - setTabValue(newValue); - }; + const [modelAbility, setModelAbility] = useState('all') const handleChange = (event) => { - setSearchTerm(event.target.value); - }; + setSearchTerm(event.target.value) + } const handleAbilityChange = (event) => { - setModelAbility(event.target.value); - }; + setModelAbility(event.target.value) + } const filter = (registration) => { - if (!registration || typeof searchTerm !== "string") return false; + if (!registration || typeof searchTerm !== 'string') return false const modelName = registration.model_name ? registration.model_name.toLowerCase() - : ""; + : '' const modelDescription = registration.model_description ? registration.model_description.toLowerCase() - : ""; + : '' if ( !modelName.includes(searchTerm.toLowerCase()) && !modelDescription.includes(searchTerm.toLowerCase()) ) { - return false; + return false } - if (modelAbility && modelAbility !== "all") { + if (modelAbility && modelAbility !== 'all') { if (registration.model_ability.indexOf(modelAbility) < 0) { - return false; + return false } } - return true; - }; + return true + } const update = async () => { - if (isCallingApi || isUpdatingModel) return; + if (isCallingApi || isUpdatingModel) return try { - setIsCallingApi(true); + setIsCallingApi(true) const response = await fetch( `${endPoint}/v1/model_registrations/LLM?detailed=true`, { - method: "GET", - }, - ); + method: 'GET', + } + ) - const registrations = await response.json(); + const registrations = await response.json() - setRegistrationData(registrations); + setRegistrationData(registrations) } catch (error) { - console.error("Error:", error); + console.error('Error:', error) } finally { - setIsCallingApi(false); + setIsCallingApi(false) } - }; + } useEffect(() => { - update(); + update() // eslint-disable-next-line - }, []); + }, []) const style = { - display: "grid", - gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", - paddingLeft: "2rem", - gridGap: "2rem 0rem", - }; - - function a11yProps(index) { - return { - id: `simple-tab-${index}`, - "aria-controls": `simple-tabpanel-${index}`, - }; + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', + paddingLeft: '2rem', + gridGap: '2rem 0rem', } return ( <Box m="20px"> <div style={{ - display: "grid", - gridTemplateColumns: "150px 1fr", - columnGap: "20px", - margin: "30px 2rem", + display: 'grid', + gridTemplateColumns: '150px 1fr', + columnGap: '20px', + margin: '30px 2rem', }} > <FormControl variant="outlined" margin="normal"> @@ -121,7 +107,7 @@ const LaunchLLM = () => { onChange={handleAbilityChange} value={modelAbility} size="small" - sx={{ width: "150px" }} + sx={{ width: '150px' }} > <MenuItem value="all">all</MenuItem> <MenuItem value="generate">generate</MenuItem> @@ -147,7 +133,7 @@ const LaunchLLM = () => { ))} </div> </Box> - ); -}; + ) +} -export default LaunchLLM; +export default LaunchLLM diff --git a/xinference/web/ui/src/scenes/launch_model/launchRerank.js b/xinference/web/ui/src/scenes/launch_model/launchRerank.js index 1cccc89b5d..51c9285b8a 100644 --- a/xinference/web/ui/src/scenes/launch_model/launchRerank.js +++ b/xinference/web/ui/src/scenes/launch_model/launchRerank.js @@ -1,86 +1,87 @@ -import React, { useContext, useState, useEffect } from "react"; -import RerankCard from "./rerankCard"; -import { Box, TextField, FormControl } from "@mui/material"; -import { ApiContext } from "../../components/apiContext"; +import { Box, FormControl, TextField } from '@mui/material' +import React, { useContext, useEffect, useState } from 'react' + +import { ApiContext } from '../../components/apiContext' +import RerankCard from './rerankCard' const LaunchRerank = () => { - let endPoint = useContext(ApiContext).endPoint; - const [registrationData, setRegistrationData] = useState([]); - const { isCallingApi, setIsCallingApi } = useContext(ApiContext); - const { isUpdatingModel } = useContext(ApiContext); + let endPoint = useContext(ApiContext).endPoint + const [registrationData, setRegistrationData] = useState([]) + const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isUpdatingModel } = useContext(ApiContext) // States used for filtering - const [searchTerm, setSearchTerm] = useState(""); + const [searchTerm, setSearchTerm] = useState('') const handleChange = (event) => { - setSearchTerm(event.target.value); - }; + setSearchTerm(event.target.value) + } const filter = (registration) => { - if (!registration || typeof searchTerm !== "string") return false; + if (!registration || typeof searchTerm !== 'string') return false const modelName = registration.model_name ? registration.model_name.toLowerCase() - : ""; - return modelName.includes(searchTerm.toLowerCase()); - }; + : '' + return modelName.includes(searchTerm.toLowerCase()) + } const update = async () => { - if (isCallingApi || isUpdatingModel) return; + if (isCallingApi || isUpdatingModel) return try { - setIsCallingApi(true); + setIsCallingApi(true) const response = await fetch( `${endPoint}/v1/model_registrations/rerank`, { - method: "GET", - }, - ); + method: 'GET', + } + ) - const registrations = await response.json(); + const registrations = await response.json() const newRegistrationData = await Promise.all( registrations.map(async (registration) => { const desc = await fetch( `${endPoint}/v1/model_registrations/rerank/${registration.model_name}`, { - method: "GET", - }, - ); + method: 'GET', + } + ) return { ...(await desc.json()), is_builtin: registration.is_builtin, - }; - }), - ); + } + }) + ) - setRegistrationData(newRegistrationData); + setRegistrationData(newRegistrationData) } catch (error) { - console.error("Error:", error); + console.error('Error:', error) } finally { - setIsCallingApi(false); + setIsCallingApi(false) } - }; + } useEffect(() => { - update(); + update() // eslint-disable-next-line - }, []); + }, []) const style = { - display: "grid", - gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", - paddingLeft: "2rem", - gridGap: "2rem 0rem", - }; + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', + paddingLeft: '2rem', + gridGap: '2rem 0rem', + } return ( <Box m="20px"> <div style={{ - display: "grid", - gridTemplateColumns: "1fr", - margin: "30px 2rem", + display: 'grid', + gridTemplateColumns: '1fr', + margin: '30px 2rem', }} > <FormControl variant="outlined" margin="normal"> @@ -102,7 +103,7 @@ const LaunchRerank = () => { ))} </div> </Box> - ); -}; + ) +} -export default LaunchRerank; +export default LaunchRerank diff --git a/xinference/web/ui/src/scenes/launch_model/modelCard.js b/xinference/web/ui/src/scenes/launch_model/modelCard.js index 42def8c0a9..cb80ea787a 100644 --- a/xinference/web/ui/src/scenes/launch_model/modelCard.js +++ b/xinference/web/ui/src/scenes/launch_model/modelCard.js @@ -1,113 +1,112 @@ -import React, { useState, useContext, useEffect } from "react"; -import { v1 as uuidv1 } from "uuid"; -import { ApiContext } from "../../components/apiContext"; -import { - FormControl, - InputLabel, - Select, - MenuItem, - Box, - Chip, -} from "@mui/material"; -import { CircularProgress } from "@mui/material"; import { ChatOutlined, EditNoteOutlined, HelpCenterOutlined, - UndoOutlined, RocketLaunchOutlined, -} from "@mui/icons-material"; + UndoOutlined, +} from '@mui/icons-material' +import { + Box, + Chip, + CircularProgress, + FormControl, + InputLabel, + MenuItem, + Select, +} from '@mui/material' +import React, { useContext, useEffect, useState } from 'react' +import { v1 as uuidv1 } from 'uuid' -const CARD_HEIGHT = 350; -const CARD_WIDTH = 270; +import { ApiContext } from '../../components/apiContext' + +const CARD_HEIGHT = 350 +const CARD_WIDTH = 270 const ModelCard = ({ url, modelData }) => { - const [hover, setHover] = useState(false); - const [selected, setSelected] = useState(false); - const { isCallingApi, setIsCallingApi } = useContext(ApiContext); - const { isUpdatingModel } = useContext(ApiContext); + const [hover, setHover] = useState(false) + const [selected, setSelected] = useState(false) + const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isUpdatingModel } = useContext(ApiContext) // Model parameter selections - const [modelFormat, setModelFormat] = useState(""); - const [modelSize, setModelSize] = useState(""); - const [quantization, setQuantization] = useState(""); + const [modelFormat, setModelFormat] = useState('') + const [modelSize, setModelSize] = useState('') + const [quantization, setQuantization] = useState('') - const [formatOptions, setFormatOptions] = useState([]); - const [sizeOptions, setSizeOptions] = useState([]); - const [quantizationOptions, setQuantizationOptions] = useState([]); + const [formatOptions, setFormatOptions] = useState([]) + const [sizeOptions, setSizeOptions] = useState([]) + const [quantizationOptions, setQuantizationOptions] = useState([]) const isCached = (spec) => { - if (spec.model_format === "pytorch") { - return spec.cache_status && spec.cache_status === true; + if (spec.model_format === 'pytorch') { + return spec.cache_status && spec.cache_status === true } else { - return spec.cache_status && spec.cache_status.some((cs) => cs); + return spec.cache_status && spec.cache_status.some((cs) => cs) } - }; + } // UseEffects for parameter selection, change options based on previous selections useEffect(() => { if (modelData) { - const modelFamily = modelData.model_specs; - const formats = [ - ...new Set(modelFamily.map((spec) => spec.model_format)), - ]; - setFormatOptions(formats); + const modelFamily = modelData.model_specs + const formats = [...new Set(modelFamily.map((spec) => spec.model_format))] + setFormatOptions(formats) } - }, [modelData]); + }, [modelData]) useEffect(() => { if (modelFormat && modelData) { - const modelFamily = modelData.model_specs; + const modelFamily = modelData.model_specs const sizes = [ ...new Set( modelFamily .filter((spec) => spec.model_format === modelFormat) - .map((spec) => spec.model_size_in_billions), + .map((spec) => spec.model_size_in_billions) ), - ]; - setSizeOptions(sizes); + ] + setSizeOptions(sizes) } - }, [modelFormat, modelData]); + }, [modelFormat, modelData]) useEffect(() => { if (modelFormat && modelSize && modelData) { - const modelFamily = modelData.model_specs; + const modelFamily = modelData.model_specs const quants = [ ...new Set( modelFamily .filter( (spec) => spec.model_format === modelFormat && - spec.model_size_in_billions === parseFloat(modelSize), + spec.model_size_in_billions === parseFloat(modelSize) ) - .flatMap((spec) => spec.quantizations), + .flatMap((spec) => spec.quantizations) ), - ]; - setQuantizationOptions(quants); + ] + setQuantizationOptions(quants) } - }, [modelFormat, modelSize, modelData]); + }, [modelFormat, modelSize, modelData]) const launchModel = (url) => { if (isCallingApi || isUpdatingModel) { - return; + return } - setIsCallingApi(true); + setIsCallingApi(true) - const uuid = uuidv1(); + const uuid = uuidv1() const modelDataWithID = { model_uid: uuid, model_name: modelData.model_name, model_format: modelFormat, model_size_in_billions: modelSize, quantization: quantization, - }; + } // First fetch request to initiate the model - fetch(url + "/v1/models", { - method: "POST", + fetch(url + '/v1/models', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify(modelDataWithID), }) @@ -117,150 +116,150 @@ const ModelCard = ({ url, modelData }) => { return response.json().then((errorData) => { throw new Error( `Server error: ${response.status} - ${ - errorData.detail || "Unknown error" - }`, - ); - }); + errorData.detail || 'Unknown error' + }` + ) + }) } - return response.json(); // Also return the promise from response.json() for successful responses + return response.json() // Also return the promise from response.json() for successful responses }) .then(() => { - window.open(url + "/ui/#/running_models", "_blank", "noreferrer"); - setIsCallingApi(false); + window.open(url + '/ui/#/running_models', '_blank', 'noreferrer') + setIsCallingApi(false) }) .catch((error) => { - console.error("Error:", error); - setIsCallingApi(false); - }); - }; + console.error('Error:', error) + setIsCallingApi(false) + }) + } const styles = { container: { - display: "block", - position: "relative", + display: 'block', + position: 'relative', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - borderRadius: "20px", - background: "white", - overflow: "hidden", + border: '1px solid #ddd', + borderRadius: '20px', + background: 'white', + overflow: 'hidden', }, containerSelected: { - display: "block", - position: "relative", + display: 'block', + position: 'relative', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - borderRadius: "20px", - background: "white", - overflow: "hidden", - boxShadow: "0 0 2px #00000099", + border: '1px solid #ddd', + borderRadius: '20px', + background: 'white', + overflow: 'hidden', + boxShadow: '0 0 2px #00000099', }, descriptionCard: { - position: "relative", - top: "-1px", - left: "-1px", + position: 'relative', + top: '-1px', + left: '-1px', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - padding: "20px", - borderRadius: "20px", - background: "white", + border: '1px solid #ddd', + padding: '20px', + borderRadius: '20px', + background: 'white', }, parameterCard: { - position: "relative", + position: 'relative', top: `-${CARD_HEIGHT + 1}px`, - left: "-1px", + left: '-1px', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - padding: "20px", - borderRadius: "20px", - background: "white", + border: '1px solid #ddd', + padding: '20px', + borderRadius: '20px', + background: 'white', }, img: { - display: "block", - margin: "0 auto", - width: "180px", - height: "180px", - objectFit: "cover", - borderRadius: "10px", + display: 'block', + margin: '0 auto', + width: '180px', + height: '180px', + objectFit: 'cover', + borderRadius: '10px', }, h2: { - margin: "10px 10px", - fontSize: "20px", + margin: '10px 10px', + fontSize: '20px', }, p: { - minHeight: "140px", - fontSize: "14px", - padding: "0px 10px 15px 10px", + minHeight: '140px', + fontSize: '14px', + padding: '0px 10px 15px 10px', }, buttonsContainer: { - display: "flex", - margin: "0 auto", - marginTop: "30px", - border: "none", - justifyContent: "space-between", - alignItems: "center", + display: 'flex', + margin: '0 auto', + marginTop: '30px', + border: 'none', + justifyContent: 'space-between', + alignItems: 'center', }, buttonContainer: { - width: "45%", - borderWidth: "0px", - backgroundColor: "transparent", - paddingLeft: "0px", - paddingRight: "0px", + width: '45%', + borderWidth: '0px', + backgroundColor: 'transparent', + paddingLeft: '0px', + paddingRight: '0px', }, buttonItem: { - width: "100%", - margin: "0 auto", - padding: "5px", - display: "flex", - justifyContent: "center", - borderRadius: "4px", - border: "1px solid #e5e7eb", - borderWidth: "1px", - borderColor: "#e5e7eb", + width: '100%', + margin: '0 auto', + padding: '5px', + display: 'flex', + justifyContent: 'center', + borderRadius: '4px', + border: '1px solid #e5e7eb', + borderWidth: '1px', + borderColor: '#e5e7eb', }, instructionText: { - fontSize: "12px", - color: "#666666", - fontStyle: "italic", - margin: "10px 0", - textAlign: "center", + fontSize: '12px', + color: '#666666', + fontStyle: 'italic', + margin: '10px 0', + textAlign: 'center', }, slideIn: { - transform: "translateX(0%)", - transition: "transform 0.2s ease-in-out", + transform: 'translateX(0%)', + transition: 'transform 0.2s ease-in-out', }, slideOut: { - transform: "translateX(100%)", - transition: "transform 0.2s ease-in-out", + transform: 'translateX(100%)', + transition: 'transform 0.2s ease-in-out', }, iconRow: { - display: "flex", - justifyContent: "space-between", - alignItems: "center", + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', }, iconItem: { - display: "flex", - flexDirection: "column", - alignItems: "center", - margin: "20px", + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + margin: '20px', }, boldIconText: { - fontWeight: "bold", - fontSize: "1.2em", + fontWeight: 'bold', + fontSize: '1.2em', }, muiIcon: { - fontSize: "1.5em", + fontSize: '1.5em', }, smallText: { - fontSize: "0.8em", + fontSize: '0.8em', }, tagRow: { - margin: "2px 5px", + margin: '2px 5px', }, - }; + } // Set two different states based on mouse hover return ( @@ -270,7 +269,7 @@ const ModelCard = ({ url, modelData }) => { onMouseLeave={() => setHover(false)} onClick={() => { if (!selected) { - setSelected(true); + setSelected(true) } }} > @@ -279,20 +278,20 @@ const ModelCard = ({ url, modelData }) => { <h2 style={styles.h2}>{modelData.model_name}</h2> <div style={styles.tagRow}> {(() => { - if (modelData.model_lang.includes("en")) { - return <Chip label="EN" variant="outlined" size="small" />; + if (modelData.model_lang.includes('en')) { + return <Chip label="EN" variant="outlined" size="small" /> } })()} {(() => { - if (modelData.model_lang.includes("zh")) { + if (modelData.model_lang.includes('zh')) { return ( <Chip label="ZH" variant="outlined" size="small" - sx={{ marginLeft: "10px" }} + sx={{ marginLeft: '10px' }} /> - ); + ) } })()} {(() => { @@ -302,9 +301,9 @@ const ModelCard = ({ url, modelData }) => { label="Cached" variant="outlined" size="small" - sx={{ marginLeft: "10px" }} + sx={{ marginLeft: '10px' }} /> - ); + ) } })()} </div> @@ -318,27 +317,27 @@ const ModelCard = ({ url, modelData }) => { <small style={styles.smallText}>context length</small> </div> {(() => { - if (modelData.model_ability.includes("chat")) { + if (modelData.model_ability.includes('chat')) { return ( <div style={styles.iconItem}> <ChatOutlined style={styles.muiIcon} /> <small style={styles.smallText}>chat model</small> </div> - ); - } else if (modelData.model_ability.includes("generate")) { + ) + } else if (modelData.model_ability.includes('generate')) { return ( <div style={styles.iconItem}> <EditNoteOutlined style={styles.muiIcon} /> <small style={styles.smallText}>generate model</small> </div> - ); + ) } else { return ( <div style={styles.iconItem}> <HelpCenterOutlined style={styles.muiIcon} /> <small style={styles.smallText}>other model</small> </div> - ); + ) } })()} </div> @@ -370,16 +369,16 @@ const ModelCard = ({ url, modelData }) => { > {formatOptions.map((format) => { const specs = modelData.model_specs.filter( - (spec) => spec.model_format === format, - ); - const cached = specs.some((spec) => isCached(spec)); - const displayedFormat = cached ? format + " (cached)" : format; + (spec) => spec.model_format === format + ) + const cached = specs.some((spec) => isCached(spec)) + const displayedFormat = cached ? format + ' (cached)' : format return ( <MenuItem key={format} value={format}> {displayedFormat} </MenuItem> - ); + ) })} </Select> </FormControl> @@ -399,19 +398,19 @@ const ModelCard = ({ url, modelData }) => { {sizeOptions.map((size) => { const specs = modelData.model_specs .filter((spec) => spec.model_format === modelFormat) - .filter((spec) => spec.model_size_in_billions === size); - const cached = specs.some((spec) => isCached(spec)); - const displayedSize = cached ? size + " (cached)" : size; + .filter((spec) => spec.model_size_in_billions === size) + const cached = specs.some((spec) => isCached(spec)) + const displayedSize = cached ? size + ' (cached)' : size return ( <MenuItem key={size} value={size}> {displayedSize} </MenuItem> - ); + ) })} </Select> </FormControl> - {(modelData.is_builtin || modelFormat === "pytorch") && ( + {(modelData.is_builtin || modelFormat === 'pytorch') && ( <FormControl variant="outlined" margin="normal" @@ -428,22 +427,20 @@ const ModelCard = ({ url, modelData }) => { {quantizationOptions.map((quant, index) => { const specs = modelData.model_specs .filter((spec) => spec.model_format === modelFormat) - .filter( - (spec) => spec.model_size_in_billions === modelSize, - ); + .filter((spec) => spec.model_size_in_billions === modelSize) const cached = - modelFormat === "pytorch" + modelFormat === 'pytorch' ? specs[0].cache_status && specs[0].cache_status === true : specs[0].cache_status && - specs[0].cache_status[index] === true; - const displayedQuant = cached ? quant + " (cached)" : quant; + specs[0].cache_status[index] === true + const displayedQuant = cached ? quant + ' (cached)' : quant return ( <MenuItem key={quant} value={quant}> {displayedQuant} </MenuItem> - ); + ) })} </Select> </FormControl> @@ -462,7 +459,7 @@ const ModelCard = ({ url, modelData }) => { modelSize && modelData && (quantization || - (!modelData.is_builtin && modelFormat !== "pytorch")) + (!modelData.is_builtin && modelFormat !== 'pytorch')) ) } > @@ -470,38 +467,38 @@ const ModelCard = ({ url, modelData }) => { if (isCallingApi || isUpdatingModel) { return ( <Box - style={{ ...styles.buttonItem, backgroundColor: "#f2f2f2" }} + style={{ ...styles.buttonItem, backgroundColor: '#f2f2f2' }} > <CircularProgress size="20px" sx={{ - color: "#000000", + color: '#000000', }} /> </Box> - ); + ) } else if ( !( modelFormat && modelSize && modelData && (quantization || - (!modelData.is_builtin && modelFormat !== "pytorch")) + (!modelData.is_builtin && modelFormat !== 'pytorch')) ) ) { return ( <Box - style={{ ...styles.buttonItem, backgroundColor: "#f2f2f2" }} + style={{ ...styles.buttonItem, backgroundColor: '#f2f2f2' }} > <RocketLaunchOutlined size="20px" /> </Box> - ); + ) } else { return ( <Box style={styles.buttonItem}> <RocketLaunchOutlined color="#000000" size="20px" /> </Box> - ); + ) } })()} </button> @@ -517,7 +514,7 @@ const ModelCard = ({ url, modelData }) => { </Box> </Box> </Box> - ); -}; + ) +} -export default ModelCard; +export default ModelCard diff --git a/xinference/web/ui/src/scenes/launch_model/rerankCard.js b/xinference/web/ui/src/scenes/launch_model/rerankCard.js index 5e5b2bb86d..4986708a7e 100644 --- a/xinference/web/ui/src/scenes/launch_model/rerankCard.js +++ b/xinference/web/ui/src/scenes/launch_model/rerankCard.js @@ -1,178 +1,178 @@ -import React, { useState, useContext, useEffect } from "react"; -import { v1 as uuidv1 } from "uuid"; -import { ApiContext } from "../../components/apiContext"; -import { Box, Chip } from "@mui/material"; -import { CircularProgress } from "@mui/material"; -import { UndoOutlined, RocketLaunchOutlined } from "@mui/icons-material"; +import { RocketLaunchOutlined, UndoOutlined } from '@mui/icons-material' +import { Box, Chip, CircularProgress } from '@mui/material' +import React, { useContext, useEffect, useState } from 'react' +import { v1 as uuidv1 } from 'uuid' -const CARD_HEIGHT = 270; -const CARD_WIDTH = 270; +import { ApiContext } from '../../components/apiContext' + +const CARD_HEIGHT = 270 +const CARD_WIDTH = 270 const RerankCard = ({ url, modelData }) => { - const [hover, setHover] = useState(false); - const [selected, setSelected] = useState(false); - const { isCallingApi, setIsCallingApi } = useContext(ApiContext); - const { isUpdatingModel } = useContext(ApiContext); + const [hover, setHover] = useState(false) + const [selected, setSelected] = useState(false) + const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isUpdatingModel } = useContext(ApiContext) // UseEffects for parameter selection, change options based on previous selections - useEffect(() => {}, [modelData]); + useEffect(() => {}, [modelData]) const launchModel = (url) => { if (isCallingApi || isUpdatingModel) { - return; + return } - setIsCallingApi(true); + setIsCallingApi(true) - const uuid = uuidv1(); + const uuid = uuidv1() const modelDataWithID = { model_uid: uuid, model_name: modelData.model_name, - model_type: "rerank", - }; + model_type: 'rerank', + } // First fetch request to initiate the model - fetch(url + "/v1/models", { - method: "POST", + fetch(url + '/v1/models', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify(modelDataWithID), }) - .then((response) => { - setIsCallingApi(false); + .then(() => { + setIsCallingApi(false) }) .catch((error) => { - console.error("Error:", error); - setIsCallingApi(false); - }); - }; + console.error('Error:', error) + setIsCallingApi(false) + }) + } const styles = { container: { - display: "block", - position: "relative", + display: 'block', + position: 'relative', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - borderRadius: "20px", - background: "white", - overflow: "hidden", + border: '1px solid #ddd', + borderRadius: '20px', + background: 'white', + overflow: 'hidden', }, containerSelected: { - display: "block", - position: "relative", + display: 'block', + position: 'relative', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - borderRadius: "20px", - background: "white", - overflow: "hidden", - boxShadow: "0 0 2px #00000099", + border: '1px solid #ddd', + borderRadius: '20px', + background: 'white', + overflow: 'hidden', + boxShadow: '0 0 2px #00000099', }, descriptionCard: { - position: "relative", - top: "-1px", - left: "-1px", + position: 'relative', + top: '-1px', + left: '-1px', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - padding: "20px", - borderRadius: "20px", - background: "white", + border: '1px solid #ddd', + padding: '20px', + borderRadius: '20px', + background: 'white', }, parameterCard: { - position: "relative", + position: 'relative', top: `-${CARD_HEIGHT + 1}px`, - left: "-1px", + left: '-1px', width: `${CARD_WIDTH}px`, height: `${CARD_HEIGHT}px`, - border: "1px solid #ddd", - padding: "20px", - borderRadius: "20px", - background: "white", + border: '1px solid #ddd', + padding: '20px', + borderRadius: '20px', + background: 'white', }, img: { - display: "block", - margin: "0 auto", - width: "180px", - height: "180px", - objectFit: "cover", - borderRadius: "10px", + display: 'block', + margin: '0 auto', + width: '180px', + height: '180px', + objectFit: 'cover', + borderRadius: '10px', }, titleContainer: { - minHeight: "120px", + minHeight: '120px', }, h2: { - margin: "10px 10px", - fontSize: "20px", + margin: '10px 10px', + fontSize: '20px', }, buttonsContainer: { - display: "flex", - margin: "0 auto", - marginTop: "120px", - border: "none", - justifyContent: "space-between", - alignItems: "center", + display: 'flex', + margin: '0 auto', + marginTop: '120px', + border: 'none', + justifyContent: 'space-between', + alignItems: 'center', }, buttonContainer: { - width: "45%", - borderWidth: "0px", - backgroundColor: "transparent", - paddingLeft: "0px", - paddingRight: "0px", + width: '45%', + borderWidth: '0px', + backgroundColor: 'transparent', + paddingLeft: '0px', + paddingRight: '0px', }, buttonItem: { - width: "100%", - margin: "0 auto", - padding: "5px", - display: "flex", - justifyContent: "center", - borderRadius: "4px", - border: "1px solid #e5e7eb", - borderWidth: "1px", - borderColor: "#e5e7eb", + width: '100%', + margin: '0 auto', + padding: '5px', + display: 'flex', + justifyContent: 'center', + borderRadius: '4px', + border: '1px solid #e5e7eb', + borderWidth: '1px', + borderColor: '#e5e7eb', }, instructionText: { - fontSize: "12px", - color: "#666666", - fontStyle: "italic", - margin: "10px 0", - textAlign: "center", + fontSize: '12px', + color: '#666666', + fontStyle: 'italic', + margin: '10px 0', + textAlign: 'center', }, slideIn: { - transform: "translateX(0%)", - transition: "transform 0.2s ease-in-out", + transform: 'translateX(0%)', + transition: 'transform 0.2s ease-in-out', }, slideOut: { - transform: "translateX(100%)", - transition: "transform 0.2s ease-in-out", + transform: 'translateX(100%)', + transition: 'transform 0.2s ease-in-out', }, iconRow: { - display: "flex", - justifyContent: "space-between", - alignItems: "center", + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', }, iconItem: { - display: "flex", - flexDirection: "column", - alignItems: "center", - margin: "20px", + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + margin: '20px', }, boldIconText: { - fontWeight: "bold", - fontSize: "1.2em", + fontWeight: 'bold', + fontSize: '1.2em', }, muiIcon: { - fontSize: "1.5em", + fontSize: '1.5em', }, smallText: { - fontSize: "0.8em", + fontSize: '0.8em', }, langRow: { - margin: "2px 5px 40px 5px", + margin: '2px 5px 40px 5px', }, - }; + } // Set two different states based on mouse hover return ( @@ -182,7 +182,7 @@ const RerankCard = ({ url, modelData }) => { onMouseLeave={() => setHover(false)} onClick={() => { if (!selected) { - setSelected(true); + setSelected(true) } }} > @@ -192,20 +192,20 @@ const RerankCard = ({ url, modelData }) => { <h2 style={styles.h2}>{modelData.model_name}</h2> <div style={styles.langRow}> {(() => { - if (modelData.language.includes("en")) { + if (modelData.language.includes('en')) { return ( <Chip label="EN" variant="outlined" size="small" - sx={{ marginRight: "10px" }} + sx={{ marginRight: '10px' }} /> - ); + ) } })()} {(() => { - if (modelData.language.includes("zh")) { - return <Chip label="ZH" variant="outlined" size="small" />; + if (modelData.language.includes('zh')) { + return <Chip label="ZH" variant="outlined" size="small" /> } })()} </div> @@ -238,30 +238,30 @@ const RerankCard = ({ url, modelData }) => { if (isCallingApi || isUpdatingModel) { return ( <Box - style={{ ...styles.buttonItem, backgroundColor: "#f2f2f2" }} + style={{ ...styles.buttonItem, backgroundColor: '#f2f2f2' }} > <CircularProgress size="20px" sx={{ - color: "#000000", + color: '#000000', }} /> </Box> - ); + ) } else if (!modelData) { return ( <Box - style={{ ...styles.buttonItem, backgroundColor: "#f2f2f2" }} + style={{ ...styles.buttonItem, backgroundColor: '#f2f2f2' }} > <RocketLaunchOutlined size="20px" /> </Box> - ); + ) } else { return ( <Box style={styles.buttonItem}> <RocketLaunchOutlined color="#000000" size="20px" /> </Box> - ); + ) } })()} </button> @@ -277,7 +277,7 @@ const RerankCard = ({ url, modelData }) => { </Box> </Box> </Box> - ); -}; + ) +} -export default RerankCard; +export default RerankCard diff --git a/xinference/web/ui/src/scenes/register_model/index.js b/xinference/web/ui/src/scenes/register_model/index.js index e68ec9cab6..c186b1d6ed 100644 --- a/xinference/web/ui/src/scenes/register_model/index.js +++ b/xinference/web/ui/src/scenes/register_model/index.js @@ -1,216 +1,214 @@ -import React, {useState, useContext, useEffect} from "react"; -import TextField from "@mui/material/TextField"; -import Button from "@mui/material/Button"; -import { ApiContext } from "../../components/apiContext"; import { Box, Checkbox, - FormHelperText, + FormControl, FormControlLabel, + FormHelperText, Radio, RadioGroup, - FormControl, -} from "@mui/material"; -import { useMode } from "../../theme"; -import Title from "../../components/Title"; +} from '@mui/material' +import Button from '@mui/material/Button' +import TextField from '@mui/material/TextField' +import React, { useContext, useEffect, useState } from 'react' + +import { ApiContext } from '../../components/apiContext' +import Title from '../../components/Title' +import { useMode } from '../../theme' -const SUPPORTED_LANGUAGES_DICT = { en: "English", zh: "Chinese" }; -const SUPPORTED_FEATURES = ["Generate", "Chat"]; +const SUPPORTED_LANGUAGES_DICT = { en: 'English', zh: 'Chinese' } +const SUPPORTED_FEATURES = ['Generate', 'Chat'] // Convert dictionary of supported languages into list -const SUPPORTED_LANGUAGES = Object.keys(SUPPORTED_LANGUAGES_DICT); +const SUPPORTED_LANGUAGES = Object.keys(SUPPORTED_LANGUAGES_DICT) const RegisterModel = () => { - const ERROR_COLOR = useMode(); - const endPoint = useContext(ApiContext).endPoint; - const [errorMessage, setErrorMessage] = useState(""); - const [modelFormat, setModelFormat] = useState("pytorch"); - const [modelSize, setModelSize] = useState(7); - const [modelUri, setModelUri] = useState("/path/to/llama-2"); + const ERROR_COLOR = useMode() + const endPoint = useContext(ApiContext).endPoint + const [errorMessage, setErrorMessage] = useState('') + const [modelFormat, setModelFormat] = useState('pytorch') + const [modelSize, setModelSize] = useState(7) + const [modelUri, setModelUri] = useState('/path/to/llama-2') const [formData, setFormData] = useState({ version: 1, context_length: 2048, - model_name: "custom-llama-2", - model_lang: ["en"], - model_ability: ["generate"], - model_description: "This is a custom model description.", + model_name: 'custom-llama-2', + model_lang: ['en'], + model_ability: ['generate'], + model_description: 'This is a custom model description.', model_specs: [], prompt_style: undefined, - }); - const [promptStyleLabel, setPromptStyleLabel] = useState("vicuna"); - const [promptStyles, setPromptStyles] = useState([]); + }) + const [promptStyleLabel, setPromptStyleLabel] = useState('vicuna') + const [promptStyles, setPromptStyles] = useState([]) // model name must be // 1. Starts with an alphanumeric character (a letter or a digit). // 2. Followed by any number of alphanumeric characters, underscores (_), or hyphens (-). const errorModelName = !/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test( - formData.model_name, - ); + formData.model_name + ) const errorModelDescription = !/^[A-Za-z0-9\s!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]{0,500}$/.test( - formData.model_description, - ); - const errorContextLength = formData.context_length === 0; + formData.model_description + ) + const errorContextLength = formData.context_length === 0 const errorLanguage = - formData.model_lang === undefined || formData.model_lang.length === 0; + formData.model_lang === undefined || formData.model_lang.length === 0 const errorAbility = - formData.model_ability === undefined || formData.model_ability.length === 0; + formData.model_ability === undefined || formData.model_ability.length === 0 const errorModelSize = formData.model_specs && formData.model_specs.some((spec) => { return ( spec.model_size_in_billions === undefined || spec.model_size_in_billions === 0 - ); - }); + ) + }) const errorAny = errorModelName || errorModelDescription || errorContextLength || errorLanguage || errorAbility || - errorModelSize; + errorModelSize - useEffect( () => { + useEffect(() => { const getBuiltInPromptStyles = async () => { - const response = await fetch(endPoint + "/v1/models/prompts", { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); + const response = await fetch(endPoint + '/v1/models/prompts', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) if (!response.ok) { - const errorData = await response.json(); // Assuming the server returns error details in JSON format - throw new Error( - `Server error: ${response.status} - ${ - errorData.detail || "Unknown error" - }`, - ); + const errorData = await response.json() // Assuming the server returns error details in JSON format + throw new Error( + `Server error: ${response.status} - ${ + errorData.detail || 'Unknown error' + }` + ) } else { - const data = await response.json() - let res = [] - for (const key in data) { - let v = data[key] - v["name"] = key - res.push(v) - } - setPromptStyles(res) + const data = await response.json() + let res = [] + for (const key in data) { + let v = data[key] + v['name'] = key + res.push(v) + } + setPromptStyles(res) } - }; - getBuiltInPromptStyles().catch(console.error); - }); + } + getBuiltInPromptStyles().catch(console.error) + }) const isModelFormatPytorch = () => { - return modelFormat === "pytorch"; - }; + return modelFormat === 'pytorch' + } const getPathComponents = (path) => { - const normalizedPath = path.replace(/\\/g, "/"); - const baseDir = normalizedPath.substring( - 0, - normalizedPath.lastIndexOf("/"), - ); + const normalizedPath = path.replace(/\\/g, '/') + const baseDir = normalizedPath.substring(0, normalizedPath.lastIndexOf('/')) const filename = normalizedPath.substring( - normalizedPath.lastIndexOf("/") + 1, - ); - return { baseDir, filename }; - }; + normalizedPath.lastIndexOf('/') + 1 + ) + return { baseDir, filename } + } const handleClick = async () => { if (!isModelFormatPytorch()) { - const { baseDir, filename } = getPathComponents(modelUri); + const { baseDir, filename } = getPathComponents(modelUri) formData.model_specs = [ { model_format: modelFormat, model_size_in_billions: modelSize, - quantizations: [""], - model_id: "", + quantizations: [''], + model_id: '', model_file_name_template: filename, model_uri: baseDir, }, - ]; + ] } else { formData.model_specs = [ { model_format: modelFormat, model_size_in_billions: modelSize, - quantizations: ["4-bit", "8-bit", "none"], - model_id: "", + quantizations: ['4-bit', '8-bit', 'none'], + model_id: '', model_uri: modelUri, }, - ]; + ] } - const ps = promptStyles.find((item) => item.name === promptStyleLabel); + const ps = promptStyles.find((item) => item.name === promptStyleLabel) formData.prompt_style = { style_name: ps.style_name, system_prompt: ps.system_prompt, roles: ps.roles, intra_message_sep: ps.intra_message_sep, inter_message_sep: ps.inter_message_sep, - }; + } if (errorAny) { - setErrorMessage("Please fill in valid value for all fields"); - return; + setErrorMessage('Please fill in valid value for all fields') + return } try { - const response = await fetch(endPoint + "/v1/model_registrations/LLM", { - method: "POST", + const response = await fetch(endPoint + '/v1/model_registrations/LLM', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify({ model: JSON.stringify(formData), persist: true, }), - }); + }) if (!response.ok) { - const errorData = await response.json(); // Assuming the server returns error details in JSON format + const errorData = await response.json() // Assuming the server returns error details in JSON format throw new Error( `Server error: ${response.status} - ${ - errorData.detail || "Unknown error" - }`, - ); + errorData.detail || 'Unknown error' + }` + ) } setErrorMessage( - "Model has been registered successfully! Navigate to launch model page to proceed.", - ); + 'Model has been registered successfully! Navigate to launch model page to proceed.' + ) } catch (error) { - console.error("There was a problem with the fetch operation:", error); - setErrorMessage(error.message || "An unexpected error occurred."); + console.error('There was a problem with the fetch operation:', error) + setErrorMessage(error.message || 'An unexpected error occurred.') } - }; + } const toggleLanguage = (lang) => { if (formData.model_lang.includes(lang)) { setFormData({ ...formData, model_lang: formData.model_lang.filter((l) => l !== lang), - }); + }) } else { setFormData({ ...formData, model_lang: [...formData.model_lang, lang], - }); + }) } - }; + } const toggleAbility = (ability) => { if (formData.model_ability.includes(ability)) { setFormData({ ...formData, model_ability: formData.model_ability.filter((a) => a !== ability), - }); + }) } else { setFormData({ ...formData, model_ability: [...formData.model_ability, ability], - }); + }) } - }; + } return ( <Box m="20px"> @@ -242,25 +240,25 @@ const RegisterModel = () => { <RadioGroup value={modelFormat} onChange={(e) => { - setModelFormat(e.target.value); + setModelFormat(e.target.value) }} > <Box sx={styles.checkboxWrapper}> - <Box sx={{ marginLeft: "10px" }}> + <Box sx={{ marginLeft: '10px' }}> <FormControlLabel value="pytorch" control={<Radio />} label="PyTorch" /> </Box> - <Box sx={{ marginLeft: "10px" }}> + <Box sx={{ marginLeft: '10px' }}> <FormControlLabel value="ggmlv3" control={<Radio />} label="GGML" /> </Box> - <Box sx={{ marginLeft: "10px" }}> + <Box sx={{ marginLeft: '10px' }}> <FormControlLabel value="ggufv2" control={<Radio />} @@ -277,20 +275,20 @@ const RegisterModel = () => { value={formData.context_length} size="small" onChange={(event) => { - let value = event.target.value; + let value = event.target.value // Remove leading zeros if (/^0+/.test(value)) { - value = value.replace(/^0+/, "") || "0"; + value = value.replace(/^0+/, '') || '0' } // Ensure it's a positive integer, if not set it to the minimum if (!/^\d+$/.test(value) || parseInt(value) < 0) { - value = "0"; + value = '0' } // Update with the processed value setFormData({ ...formData, context_length: Number(value), - }); + }) }} /> <Box padding="15px"></Box> @@ -301,16 +299,16 @@ const RegisterModel = () => { error={errorModelSize} value={modelSize} onChange={(e) => { - let value = e.target.value; + let value = e.target.value // Remove leading zeros if (/^0+/.test(value)) { - value = value.replace(/^0+/, "") || "0"; + value = value.replace(/^0+/, '') || '0' } // Ensure it's a positive integer, if not set it to the minimum if (!/^\d+$/.test(value) || parseInt(value) < 0) { - value = "0"; + value = '0' } - setModelSize(Number(value)); + setModelSize(Number(value)) }} /> <Box padding="15px"></Box> @@ -320,7 +318,7 @@ const RegisterModel = () => { size="small" value={modelUri} onChange={(e) => { - setModelUri(e.target.value); + setModelUri(e.target.value) }} helperText="For PyTorch, provide the model directory. For GGML/GGUF, provide the model file path." /> @@ -340,14 +338,14 @@ const RegisterModel = () => { <label style={{ paddingLeft: 5, - color: errorLanguage ? ERROR_COLOR : "inherit", + color: errorLanguage ? ERROR_COLOR : 'inherit', }} > Model Languages </label> <Box sx={styles.checkboxWrapper}> {SUPPORTED_LANGUAGES.map((lang) => ( - <Box key={lang} sx={{ marginRight: "10px" }}> + <Box key={lang} sx={{ marginRight: '10px' }}> <FormControlLabel control={ <Checkbox @@ -357,8 +355,8 @@ const RegisterModel = () => { sx={ errorLanguage ? { - color: ERROR_COLOR, - "&.Mui-checked": { + 'color': ERROR_COLOR, + '&.Mui-checked': { color: ERROR_COLOR, }, } @@ -369,7 +367,7 @@ const RegisterModel = () => { label={SUPPORTED_LANGUAGES_DICT[lang]} style={{ paddingLeft: 10, - color: errorLanguage ? ERROR_COLOR : "inherit", + color: errorLanguage ? ERROR_COLOR : 'inherit', }} /> </Box> @@ -380,27 +378,27 @@ const RegisterModel = () => { <label style={{ paddingLeft: 5, - color: errorAbility ? ERROR_COLOR : "inherit", + color: errorAbility ? ERROR_COLOR : 'inherit', }} > Model Abilities </label> <Box sx={styles.checkboxWrapper}> {SUPPORTED_FEATURES.map((ability) => ( - <Box key={ability} sx={{ marginRight: "10px" }}> + <Box key={ability} sx={{ marginRight: '10px' }}> <FormControlLabel control={ <Checkbox checked={formData.model_ability.includes( - ability.toLowerCase(), + ability.toLowerCase() )} onChange={() => toggleAbility(ability.toLowerCase())} name={ability} sx={ errorAbility ? { - color: ERROR_COLOR, - "&.Mui-checked": { + 'color': ERROR_COLOR, + '&.Mui-checked': { color: ERROR_COLOR, }, } @@ -411,7 +409,7 @@ const RegisterModel = () => { label={ability} style={{ paddingLeft: 10, - color: errorAbility ? ERROR_COLOR : "inherit", + color: errorAbility ? ERROR_COLOR : 'inherit', }} /> </Box> @@ -420,12 +418,12 @@ const RegisterModel = () => { <Box padding="15px"></Box> </FormControl> - {formData.model_ability.includes("chat") && ( + {formData.model_ability.includes('chat') && ( <FormControl sx={styles.baseFormControl}> <label style={{ paddingLeft: 5, - color: errorAbility ? ERROR_COLOR : "inherit", + color: errorAbility ? ERROR_COLOR : 'inherit', }} > Prompt styles @@ -437,12 +435,12 @@ const RegisterModel = () => { <RadioGroup value={promptStyleLabel} onChange={(e) => { - setPromptStyleLabel(e.target.value); + setPromptStyleLabel(e.target.value) }} > <Box sx={styles.checkboxWrapper}> {promptStyles.map((p) => ( - <Box sx={{ marginLeft: "10px" }}> + <Box sx={{ marginLeft: '10px' }}> <FormControlLabel value={p.name} control={<Radio />} @@ -455,7 +453,7 @@ const RegisterModel = () => { </FormControl> )} - <Box width={"100%"}> + <Box width={'100%'}> <div style={{ ...styles.error, color: ERROR_COLOR }}> {errorMessage} </div> @@ -469,21 +467,21 @@ const RegisterModel = () => { </Button> </Box> </Box> - ); -}; + ) +} -export default RegisterModel; +export default RegisterModel const styles = { baseFormControl: { - width: "100%", - margin: "normal", - size: "small", + width: '100%', + margin: 'normal', + size: 'small', }, checkboxWrapper: { - display: "flex", - flexWrap: "wrap", - maxWidth: "80%", + display: 'flex', + flexWrap: 'wrap', + maxWidth: '80%', }, labelPaddingLeft: { paddingLeft: 5, @@ -492,13 +490,13 @@ const styles = { paddingLeft: 10, }, buttonBox: { - width: "100%", - margin: "20px", + width: '100%', + margin: '20px', }, error: { - fontWeight: "bold", - margin: "5px 0", - padding: "1px", - borderRadius: "5px", + fontWeight: 'bold', + margin: '5px 0', + padding: '1px', + borderRadius: '5px', }, -}; +} diff --git a/xinference/web/ui/src/scenes/running_models/index.js b/xinference/web/ui/src/scenes/running_models/index.js index 8d23dd9f99..b37a6feb36 100644 --- a/xinference/web/ui/src/scenes/running_models/index.js +++ b/xinference/web/ui/src/scenes/running_models/index.js @@ -1,171 +1,170 @@ -import React, {useContext, useEffect, useState} from "react"; -import {Box, Stack, Tab} from "@mui/material"; -import {TabContext, TabList, TabPanel} from "@mui/lab"; -import {ApiContext} from "../../components/apiContext"; -import {DataGrid} from "@mui/x-data-grid"; -import Title from "../../components/Title"; -import OpenInBrowserOutlinedIcon from "@mui/icons-material/OpenInBrowserOutlined"; -import DeleteOutlineOutlinedIcon from "@mui/icons-material/DeleteOutlineOutlined"; +import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined' +import OpenInBrowserOutlinedIcon from '@mui/icons-material/OpenInBrowserOutlined' +import { TabContext, TabList, TabPanel } from '@mui/lab' +import { Box, Stack, Tab } from '@mui/material' +import { DataGrid } from '@mui/x-data-grid' +import React, { useContext, useEffect, useState } from 'react' + +import { ApiContext } from '../../components/apiContext' +import Title from '../../components/Title' const RunningModels = () => { - const [tabValue, setTabValue] = React.useState("1"); - const [llmData, setLlmData] = useState([]); - const [embeddingModelData, setEmbeddingModelData] = useState([]); - const [imageModelData, setImageModelData] = useState([]); - const [rerankModelData, setRerankModelData] = useState([]); - const {isCallingApi, setIsCallingApi} = useContext(ApiContext); - const {isUpdatingModel, setIsUpdatingModel} = useContext(ApiContext); - const endPoint = useContext(ApiContext).endPoint; + const [tabValue, setTabValue] = React.useState('1') + const [llmData, setLlmData] = useState([]) + const [embeddingModelData, setEmbeddingModelData] = useState([]) + const [imageModelData, setImageModelData] = useState([]) + const [rerankModelData, setRerankModelData] = useState([]) + const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isUpdatingModel, setIsUpdatingModel } = useContext(ApiContext) + const endPoint = useContext(ApiContext).endPoint const handleTabChange = (event, newValue) => { - setTabValue(newValue); - }; + setTabValue(newValue) + } const update = (isCallingApi) => { if (isCallingApi) { - setLlmData([ - {id: "Loading, do not refresh page...", url: "IS_LOADING"}, - ]); + setLlmData([{ id: 'Loading, do not refresh page...', url: 'IS_LOADING' }]) setEmbeddingModelData([ - {id: "Loading, do not refresh page...", url: "IS_LOADING"}, - ]); + { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, + ]) setImageModelData([ - {id: "Loading, do not refresh page...", url: "IS_LOADING"}, - ]); + { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, + ]) setRerankModelData([ - {id: "Loading, do not refresh page...", url: "IS_LOADING"}, - ]); + { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, + ]) } else { - setIsUpdatingModel(true); + setIsUpdatingModel(true) fetch(`${endPoint}/v1/models/`, { - method: "GET", + method: 'GET', }) .then((response) => response.json()) .then((data) => { - const newLlmData = []; - const newEmbeddingModelData = []; - const newImageModelData = []; - const newRerankModelData = []; + const newLlmData = [] + const newEmbeddingModelData = [] + const newImageModelData = [] + const newRerankModelData = [] Object.entries(data).forEach(([key, value]) => { let newValue = { ...value, id: key, url: key, - }; - if (newValue.model_type === "LLM") { - newLlmData.push(newValue); - } else if (newValue.model_type === "embedding") { - newEmbeddingModelData.push(newValue); - } else if (newValue.model_type === "image") { - newImageModelData.push(newValue); - } else if (newValue.model_type === "rerank") { - newRerankModelData.push(newValue); } - }); - setLlmData(newLlmData); - setEmbeddingModelData(newEmbeddingModelData); - setImageModelData(newImageModelData); - setRerankModelData(newRerankModelData); - setIsUpdatingModel(false); + if (newValue.model_type === 'LLM') { + newLlmData.push(newValue) + } else if (newValue.model_type === 'embedding') { + newEmbeddingModelData.push(newValue) + } else if (newValue.model_type === 'image') { + newImageModelData.push(newValue) + } else if (newValue.model_type === 'rerank') { + newRerankModelData.push(newValue) + } + }) + setLlmData(newLlmData) + setEmbeddingModelData(newEmbeddingModelData) + setImageModelData(newImageModelData) + setRerankModelData(newRerankModelData) + setIsUpdatingModel(false) }) .catch((error) => { - console.error("Error:", error); - setIsUpdatingModel(false); - }); + console.error('Error:', error) + setIsUpdatingModel(false) + }) } - }; + } useEffect(() => { - update(isCallingApi); + update(isCallingApi) // eslint-disable-next-line - }, [isCallingApi]); + }, [isCallingApi]) const llmColumns = [ { - field: "id", - headerName: "ID", + field: 'id', + headerName: 'ID', flex: 1, minWidth: 250, }, { - field: "model_name", - headerName: "Name", + field: 'model_name', + headerName: 'Name', flex: 1, }, { - field: "address", - headerName: "Address", + field: 'address', + headerName: 'Address', flex: 1, }, { - field: "accelerators", - headerName: "GPU Indexes", + field: 'accelerators', + headerName: 'GPU Indexes', flex: 1, }, { - field: "model_size_in_billions", - headerName: "Size", + field: 'model_size_in_billions', + headerName: 'Size', flex: 1, }, { - field: "quantization", - headerName: "Quantization", + field: 'quantization', + headerName: 'Quantization', flex: 1, }, { - field: "url", - headerName: "Actions", + field: 'url', + headerName: 'Actions', flex: 1, minWidth: 200, sortable: false, filterable: false, disableColumnMenu: true, - renderCell: ({row}) => { - const url = row.url; - const openUrl = `${endPoint}/` + url; - const closeUrl = `${endPoint}/v1/models/` + url; - const gradioUrl = `${endPoint}/v1/ui/` + url; + renderCell: ({ row }) => { + const url = row.url + const openUrl = `${endPoint}/` + url + const closeUrl = `${endPoint}/v1/models/` + url + const gradioUrl = `${endPoint}/v1/ui/` + url - if (url === "IS_LOADING") { - return <div></div>; + if (url === 'IS_LOADING') { + return <div></div> } return ( <Box style={{ - width: "100%", - display: "flex", - justifyContent: "left", - alignItems: "left", + width: '100%', + display: 'flex', + justifyContent: 'left', + alignItems: 'left', }} > <button title="Launch Web UI" style={{ - borderWidth: "0px", - backgroundColor: "transparent", - paddingLeft: "0px", - paddingRight: "10px", + borderWidth: '0px', + backgroundColor: 'transparent', + paddingLeft: '0px', + paddingRight: '10px', }} onClick={() => { if (isCallingApi || isUpdatingModel) { // Make sure no ongoing call - return; + return } - setIsCallingApi(true); + setIsCallingApi(true) fetch(openUrl, { - method: "HEAD", + method: 'HEAD', }) .then((response) => { if (response.status === 404) { // If web UI doesn't exist (404 Not Found) - console.log("UI does not exist, creating new..."); + console.log('UI does not exist, creating new...') return fetch(gradioUrl, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify({ model_type: row.model_type, @@ -181,26 +180,26 @@ const RunningModels = () => { }) .then((response) => response.json()) .then(() => - window.open(openUrl, "_blank", "noopener noreferrer"), + window.open(openUrl, '_blank', 'noopener noreferrer') ) - .finally(() => setIsCallingApi(false)); + .finally(() => setIsCallingApi(false)) } else if (response.ok) { // If web UI does exist - console.log("UI exists, opening..."); - window.open(openUrl, "_blank", "noopener noreferrer"); - setIsCallingApi(false); + console.log('UI exists, opening...') + window.open(openUrl, '_blank', 'noopener noreferrer') + setIsCallingApi(false) } else { // Other HTTP errors console.error( - `Unexpected response status: ${response.status}`, - ); - setIsCallingApi(false); + `Unexpected response status: ${response.status}` + ) + setIsCallingApi(false) } }) .catch((error) => { - console.error("Error:", error); - setIsCallingApi(false); - }); + console.error('Error:', error) + setIsCallingApi(false) + }) }} > <Box @@ -211,40 +210,40 @@ const RunningModels = () => { justifyContent="center" borderRadius="4px" style={{ - border: "1px solid #e5e7eb", - borderWidth: "1px", - borderColor: "#e5e7eb", + border: '1px solid #e5e7eb', + borderWidth: '1px', + borderColor: '#e5e7eb', }} > - <OpenInBrowserOutlinedIcon/> + <OpenInBrowserOutlinedIcon /> </Box> </button> <button title="Terminate Model" style={{ - borderWidth: "0px", - backgroundColor: "transparent", - paddingLeft: "0px", - paddingRight: "10px", + borderWidth: '0px', + backgroundColor: 'transparent', + paddingLeft: '0px', + paddingRight: '10px', }} onClick={() => { if (isCallingApi || isUpdatingModel) { - return; + return } - setIsCallingApi(true); + setIsCallingApi(true) fetch(closeUrl, { - method: "DELETE", + method: 'DELETE', }) .then((response) => { - response.json(); + response.json() }) - .then((data) => { - setIsCallingApi(false); + .then(() => { + setIsCallingApi(false) }) .catch((error) => { - console.error("Error:", error); - setIsCallingApi(false); - }); + console.error('Error:', error) + setIsCallingApi(false) + }) }} > <Box @@ -255,93 +254,93 @@ const RunningModels = () => { justifyContent="center" borderRadius="4px" style={{ - border: "1px solid #e5e7eb", - borderWidth: "1px", - borderColor: "#e5e7eb", + border: '1px solid #e5e7eb', + borderWidth: '1px', + borderColor: '#e5e7eb', }} > - <DeleteOutlineOutlinedIcon/> + <DeleteOutlineOutlinedIcon /> </Box> </button> </Box> - ); + ) }, }, - ]; + ] const embeddingModelColumns = [ { - field: "id", - headerName: "ID", + field: 'id', + headerName: 'ID', flex: 1, minWidth: 250, }, { - field: "model_name", - headerName: "Name", + field: 'model_name', + headerName: 'Name', flex: 1, }, { - field: "address", - headerName: "Address", + field: 'address', + headerName: 'Address', flex: 1, }, { - field: "accelerators", - headerName: "GPU Indexes", + field: 'accelerators', + headerName: 'GPU Indexes', flex: 1, }, { - field: "url", - headerName: "Actions", + field: 'url', + headerName: 'Actions', flex: 1, minWidth: 200, sortable: false, filterable: false, disableColumnMenu: true, - renderCell: ({row}) => { - const url = row.url; - const closeUrl = `${endPoint}/v1/models/` + url; + renderCell: ({ row }) => { + const url = row.url + const closeUrl = `${endPoint}/v1/models/` + url - if (url === "IS_LOADING") { - return <div></div>; + if (url === 'IS_LOADING') { + return <div></div> } return ( <Box style={{ - width: "100%", - display: "flex", - justifyContent: "left", - alignItems: "left", + width: '100%', + display: 'flex', + justifyContent: 'left', + alignItems: 'left', }} > <button title="Terminate Model" style={{ - borderWidth: "0px", - backgroundColor: "transparent", - paddingLeft: "0px", - paddingRight: "10px", + borderWidth: '0px', + backgroundColor: 'transparent', + paddingLeft: '0px', + paddingRight: '10px', }} onClick={() => { if (isCallingApi || isUpdatingModel) { - return; + return } - setIsCallingApi(true); + setIsCallingApi(true) fetch(closeUrl, { - method: "DELETE", + method: 'DELETE', }) .then((response) => { - response.json(); + response.json() }) - .then((data) => { - setIsCallingApi(false); + .then(() => { + setIsCallingApi(false) }) .catch((error) => { - console.error("Error:", error); - setIsCallingApi(false); - }); + console.error('Error:', error) + setIsCallingApi(false) + }) }} > <Box @@ -352,78 +351,90 @@ const RunningModels = () => { justifyContent="center" borderRadius="4px" style={{ - border: "1px solid #e5e7eb", - borderWidth: "1px", - borderColor: "#e5e7eb", + border: '1px solid #e5e7eb', + borderWidth: '1px', + borderColor: '#e5e7eb', }} > - <DeleteOutlineOutlinedIcon/> + <DeleteOutlineOutlinedIcon /> </Box> </button> </Box> - ); + ) }, }, - ]; + ] - const imageModelColumns = embeddingModelColumns; - const rerankModelColumns = embeddingModelColumns; + const imageModelColumns = embeddingModelColumns + const rerankModelColumns = embeddingModelColumns return ( <Box m="20px"> - <Title title="Running Models"/> + <Title title="Running Models" /> <TabContext value={tabValue}> - <Box sx={{borderBottom: 1, borderColor: "divider"}}> - <TabList value={tabValue} onChange={handleTabChange} aria-label="tabs"> - <Tab label="Language Models" value="1"/> - <Tab label="Embedding Models" value="2"/> - <Tab label="Image models" value="3"/> - <Tab label="Rerank models" value="4"/> + <Box sx={{ borderBottom: 1, borderColor: 'divider' }}> + <TabList + value={tabValue} + onChange={handleTabChange} + aria-label="tabs" + > + <Tab label="Language Models" value="1" /> + <Tab label="Embedding Models" value="2" /> + <Tab label="Image models" value="3" /> + <Tab label="Rerank models" value="4" /> </TabList> </Box> - <TabPanel value="1" sx={{padding: 0}}> + <TabPanel value="1" sx={{ padding: 0 }}> <Box m="40px 0 0 0" height="30vh"> <DataGrid rows={llmData} columns={llmColumns} sx={{ - "& .MuiDataGrid-main": { - width: "95% !important", - overflow: "visible", + '& .MuiDataGrid-main': { + width: '95% !important', + overflow: 'visible', }, - "& .MuiDataGrid-row": { - background: "white", - margin: "10px 0px", + '& .MuiDataGrid-row': { + background: 'white', + margin: '10px 0px', }, - "& .MuiDataGrid-cell": { - borderBottom: "none", + '& .MuiDataGrid-cell': { + borderBottom: 'none', }, - "& .CustomWide-cell": { - minWidth: "250px !important", + '& .CustomWide-cell': { + minWidth: '250px !important', }, - "& .MuiDataGrid-columnHeaders": { - borderBottom: "none", + '& .MuiDataGrid-columnHeaders': { + borderBottom: 'none', }, - "& .MuiDataGrid-columnHeaderTitle": { - fontWeight: "bold", + '& .MuiDataGrid-columnHeaderTitle': { + fontWeight: 'bold', }, - "& .MuiDataGrid-virtualScroller": { - overflowX: "visible !important", - overflow: "visible", + '& .MuiDataGrid-virtualScroller': { + overflowX: 'visible !important', + overflow: 'visible', }, - "& .MuiDataGrid-footerContainer": { - borderTop: "none", + '& .MuiDataGrid-footerContainer': { + borderTop: 'none', }, - "border-width": "0px", + 'border-width': '0px', }} slots={{ noRowsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models </Stack> ), noResultsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models Matches </Stack> ), @@ -431,49 +442,57 @@ const RunningModels = () => { /> </Box> </TabPanel> - <TabPanel value="2" sx={{padding: 0}}> + <TabPanel value="2" sx={{ padding: 0 }}> <Box m="40px 0 0 0" height="30vh"> <DataGrid rows={embeddingModelData} columns={embeddingModelColumns} sx={{ - "& .MuiDataGrid-main": { - width: "95% !important", - overflow: "visible", + '& .MuiDataGrid-main': { + width: '95% !important', + overflow: 'visible', }, - "& .MuiDataGrid-row": { - background: "white", - margin: "10px 0px", + '& .MuiDataGrid-row': { + background: 'white', + margin: '10px 0px', }, - "& .MuiDataGrid-cell": { - borderBottom: "none", + '& .MuiDataGrid-cell': { + borderBottom: 'none', }, - "& .CustomWide-cell": { - minWidth: "250px !important", + '& .CustomWide-cell': { + minWidth: '250px !important', }, - "& .MuiDataGrid-columnHeaders": { - borderBottom: "none", + '& .MuiDataGrid-columnHeaders': { + borderBottom: 'none', }, - "& .MuiDataGrid-columnHeaderTitle": { - fontWeight: "bold", + '& .MuiDataGrid-columnHeaderTitle': { + fontWeight: 'bold', }, - "& .MuiDataGrid-virtualScroller": { - overflowX: "visible !important", - overflow: "visible", + '& .MuiDataGrid-virtualScroller': { + overflowX: 'visible !important', + overflow: 'visible', }, - "& .MuiDataGrid-footerContainer": { - borderTop: "none", + '& .MuiDataGrid-footerContainer': { + borderTop: 'none', }, - "border-width": "0px", + 'border-width': '0px', }} slots={{ noRowsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models </Stack> ), noResultsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models Matches </Stack> ), @@ -481,49 +500,57 @@ const RunningModels = () => { /> </Box> </TabPanel> - <TabPanel value="3" sx={{padding: 0}}> + <TabPanel value="3" sx={{ padding: 0 }}> <Box m="40px 0 0 0" height="30vh"> <DataGrid rows={imageModelData} columns={imageModelColumns} sx={{ - "& .MuiDataGrid-main": { - width: "95% !important", - overflow: "visible", + '& .MuiDataGrid-main': { + width: '95% !important', + overflow: 'visible', }, - "& .MuiDataGrid-row": { - background: "white", - margin: "10px 0px", + '& .MuiDataGrid-row': { + background: 'white', + margin: '10px 0px', }, - "& .MuiDataGrid-cell": { - borderBottom: "none", + '& .MuiDataGrid-cell': { + borderBottom: 'none', }, - "& .CustomWide-cell": { - minWidth: "250px !important", + '& .CustomWide-cell': { + minWidth: '250px !important', }, - "& .MuiDataGrid-columnHeaders": { - borderBottom: "none", + '& .MuiDataGrid-columnHeaders': { + borderBottom: 'none', }, - "& .MuiDataGrid-columnHeaderTitle": { - fontWeight: "bold", + '& .MuiDataGrid-columnHeaderTitle': { + fontWeight: 'bold', }, - "& .MuiDataGrid-virtualScroller": { - overflowX: "visible !important", - overflow: "visible", + '& .MuiDataGrid-virtualScroller': { + overflowX: 'visible !important', + overflow: 'visible', }, - "& .MuiDataGrid-footerContainer": { - borderTop: "none", + '& .MuiDataGrid-footerContainer': { + borderTop: 'none', }, - "border-width": "0px", + 'border-width': '0px', }} slots={{ noRowsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models </Stack> ), noResultsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models Matches </Stack> ), @@ -531,49 +558,57 @@ const RunningModels = () => { /> </Box> </TabPanel> - <TabPanel value="4" sx={{padding: 0}}> + <TabPanel value="4" sx={{ padding: 0 }}> <Box m="40px 0 0 0" height="30vh"> <DataGrid rows={rerankModelData} columns={rerankModelColumns} sx={{ - "& .MuiDataGrid-main": { - width: "95% !important", - overflow: "visible", + '& .MuiDataGrid-main': { + width: '95% !important', + overflow: 'visible', }, - "& .MuiDataGrid-row": { - background: "white", - margin: "10px 0px", + '& .MuiDataGrid-row': { + background: 'white', + margin: '10px 0px', }, - "& .MuiDataGrid-cell": { - borderBottom: "none", + '& .MuiDataGrid-cell': { + borderBottom: 'none', }, - "& .CustomWide-cell": { - minWidth: "250px !important", + '& .CustomWide-cell': { + minWidth: '250px !important', }, - "& .MuiDataGrid-columnHeaders": { - borderBottom: "none", + '& .MuiDataGrid-columnHeaders': { + borderBottom: 'none', }, - "& .MuiDataGrid-columnHeaderTitle": { - fontWeight: "bold", + '& .MuiDataGrid-columnHeaderTitle': { + fontWeight: 'bold', }, - "& .MuiDataGrid-virtualScroller": { - overflowX: "visible !important", - overflow: "visible", + '& .MuiDataGrid-virtualScroller': { + overflowX: 'visible !important', + overflow: 'visible', }, - "& .MuiDataGrid-footerContainer": { - borderTop: "none", + '& .MuiDataGrid-footerContainer': { + borderTop: 'none', }, - "border-width": "0px", + 'border-width': '0px', }} slots={{ noRowsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models </Stack> ), noResultsOverlay: () => ( - <Stack height="100%" alignItems="center" justifyContent="center"> + <Stack + height="100%" + alignItems="center" + justifyContent="center" + > No Running Models Matches </Stack> ), @@ -583,7 +618,7 @@ const RunningModels = () => { </TabPanel> </TabContext> </Box> - ); -}; + ) +} -export default RunningModels; +export default RunningModels diff --git a/xinference/web/ui/src/theme.js b/xinference/web/ui/src/theme.js index 4d186e6fb9..4f4e175620 100644 --- a/xinference/web/ui/src/theme.js +++ b/xinference/web/ui/src/theme.js @@ -1,41 +1,41 @@ -import { createTheme } from "@mui/material/styles"; +import { createTheme } from '@mui/material/styles' // mui theme settings export const themeSettings = () => { return { - ERROR_COLOR: "#d8342c", + ERROR_COLOR: '#d8342c', typography: { - fontFamily: ["Source Sans Pro", "sans-serif"].join(","), + fontFamily: ['Source Sans Pro', 'sans-serif'].join(','), fontSize: 12, h1: { - fontFamily: ["Source Sans Pro", "sans-serif"].join(","), + fontFamily: ['Source Sans Pro', 'sans-serif'].join(','), fontSize: 40, }, h2: { - fontFamily: ["Source Sans Pro", "sans-serif"].join(","), + fontFamily: ['Source Sans Pro', 'sans-serif'].join(','), fontSize: 32, }, h3: { - fontFamily: ["Source Sans Pro", "sans-serif"].join(","), + fontFamily: ['Source Sans Pro', 'sans-serif'].join(','), fontSize: 24, }, h4: { - fontFamily: ["Source Sans Pro", "sans-serif"].join(","), + fontFamily: ['Source Sans Pro', 'sans-serif'].join(','), fontSize: 20, }, h5: { - fontFamily: ["Source Sans Pro", "sans-serif"].join(","), + fontFamily: ['Source Sans Pro', 'sans-serif'].join(','), fontSize: 16, }, h6: { - fontFamily: ["Source Sans Pro", "sans-serif"].join(","), + fontFamily: ['Source Sans Pro', 'sans-serif'].join(','), fontSize: 14, }, }, - }; -}; + } +} export const useMode = () => { - const theme = createTheme(themeSettings()); - return [theme]; -}; + const theme = createTheme(themeSettings()) + return [theme] +}