diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 8056514d..4d1a5bb6 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1110,6 +1110,8 @@ ui: installed_plugins: Installed Plugins website_welcome: Welcome to {{site_name}} plugins: + login: Login + qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. oauth: connect: Connect with {{ auth_name }} remove: Remove {{ auth_name }} diff --git a/ui/package.json b/ui/package.json index 57c2e634..22c97cbe 100644 --- a/ui/package.json +++ b/ui/package.json @@ -22,7 +22,6 @@ "copy-to-clipboard": "^3.3.2", "dayjs": "^1.11.5", "diff": "^5.1.0", - "emoji-regex": "^10.2.1", "i18next": "^21.9.0", "katex": "^0.16.2", "lodash": "^4.17.21", @@ -30,6 +29,7 @@ "md5": "^2.3.0", "mermaid": "^9.1.7", "next-share": "^0.18.1", + "qrcode": "^1.5.1", "qs": "^6.11.0", "react": "^18.2.0", "react-bootstrap": "^2.5.0", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index 743e1f6e..13cf786b 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -29,7 +29,6 @@ specifiers: customize-cra: ^1.0.0 dayjs: ^1.11.5 diff: ^5.1.0 - emoji-regex: ^10.2.1 eslint: ^8.0.1 eslint-config-airbnb: ^19.0.4 eslint-config-airbnb-typescript: ^17.0.0 @@ -54,6 +53,7 @@ specifiers: postcss: ^8.0.0 prettier: ^2.7.1 purgecss-webpack-plugin: ^4.1.3 + qrcode: ^1.5.1 qs: ^6.11.0 react: ^18.2.0 react-app-rewired: ^2.2.1 @@ -81,7 +81,6 @@ dependencies: copy-to-clipboard: 3.3.2 dayjs: 1.11.5 diff: 5.1.0 - emoji-regex: 10.2.1 i18next: 21.9.2 katex: 0.16.2 lodash: 4.17.21 @@ -89,6 +88,7 @@ dependencies: md5: 2.3.0 mermaid: 9.1.7 next-share: 0.18.1_lbqamd2wfmenkveygahn4wdfcq + qrcode: 1.5.1 qs: 6.11.0 react: 18.2.0 react-bootstrap: 2.5.0_7ey2zzynotv32rpkwno45fsx4e @@ -109,8 +109,8 @@ devDependencies: '@testing-library/jest-dom': 4.2.4 '@testing-library/react': 13.4.0_biqbaboplfbrettd7655fr4n2y '@testing-library/user-event': 13.5.0_znccgeejomvff3jrsk3ljovfpu - '@types/color': registry.npmjs.org/@types/color/3.0.3 - '@types/dompurify': registry.npmjs.org/@types/dompurify/2.4.0 + '@types/color': 3.0.3 + '@types/dompurify': 2.4.0 '@types/jest': 27.5.2 '@types/lodash': 4.14.185 '@types/marked': 4.0.7 @@ -1682,7 +1682,7 @@ packages: cosmiconfig-typescript-loader: 4.1.0_2uclxasecupgvdn72amnhmyg7y lodash: 4.17.21 resolve-from: 5.0.0 - ts-node: 10.9.1_5bkdw6noa5sa7givrguqy7ejvm + ts-node: 10.9.1_yxpazyh7n5pql7jdaglasgwqki typescript: 4.9.5 transitivePeerDependencies: - '@swc/core' @@ -2077,7 +2077,7 @@ packages: collect-v8-coverage: 1.0.1 exit: 0.1.2 glob: 7.2.3 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.0 istanbul-lib-instrument: 5.2.0 istanbul-lib-report: 3.0.0 @@ -2106,7 +2106,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: callsites: 3.1.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 source-map: 0.6.1 /@jest/test-result/27.5.1: @@ -2132,7 +2132,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/test-result': 27.5.1 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jest-haste-map: 27.5.1 jest-runtime: 27.5.1 transitivePeerDependencies: @@ -2203,7 +2203,7 @@ packages: dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.17 /@jridgewell/resolve-uri/3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} @@ -2217,7 +2217,7 @@ packages: resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} dependencies: '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.17 /@jridgewell/sourcemap-codec/1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} @@ -2637,6 +2637,22 @@ packages: dependencies: '@types/node': 16.11.59 + /@types/color-convert/2.0.0: + resolution: {integrity: sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==} + dependencies: + '@types/color-name': 1.1.1 + dev: true + + /@types/color-name/1.1.1: + resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==} + dev: true + + /@types/color/3.0.3: + resolution: {integrity: sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.yarnpkg.com/@types/color/-/color-3.0.3.tgz} + dependencies: + '@types/color-convert': 2.0.0 + dev: true + /@types/connect-history-api-fallback/1.3.5: resolution: {integrity: sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==} dependencies: @@ -2648,6 +2664,12 @@ packages: dependencies: '@types/node': 16.11.59 + /@types/dompurify/2.4.0: + resolution: {integrity: sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.4.0.tgz} + dependencies: + '@types/trusted-types': 2.0.2 + dev: true + /@types/eslint-scope/3.7.4: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: @@ -2823,6 +2845,9 @@ packages: /@types/stack-utils/2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + /@types/trusted-types/2.0.2: + resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==} + /@types/warning/3.0.0: resolution: {integrity: sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==} dev: false @@ -3857,6 +3882,14 @@ packages: string-width: 5.1.2 dev: true + /cliui/6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: false + /cliui/7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: @@ -4078,7 +4111,7 @@ packages: dependencies: '@types/node': 14.18.29 cosmiconfig: 7.0.1 - ts-node: 10.9.1_5bkdw6noa5sa7givrguqy7ejvm + ts-node: 10.9.1_yxpazyh7n5pql7jdaglasgwqki typescript: 4.9.5 dev: true @@ -4209,7 +4242,7 @@ packages: dependencies: boolbase: 1.0.0 css-what: 3.4.2 - domutils: registry.npmjs.org/domutils/1.7.0 + domutils: 1.7.0 nth-check: 1.0.2 /css-select/4.3.0: @@ -4217,8 +4250,8 @@ packages: dependencies: boolbase: 1.0.0 css-what: 6.1.0 - domhandler: registry.npmjs.org/domhandler/4.3.1 - domutils: registry.npmjs.org/domutils/2.8.0 + domhandler: 4.3.1 + domutils: 2.8.0 nth-check: 2.1.1 /css-tree/1.0.0-alpha.37: @@ -4890,7 +4923,6 @@ packages: /decamelize/1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - dev: true /decimal.js/10.4.1: resolution: {integrity: sha512-F29o+vci4DodHYT9UrR5IEbfBw9pE5eSapIJdTqXK5+6hq+t8VRxwQyKlW2i+KDKFkkJQRvFyI/QXD83h8LyQw==} @@ -5004,6 +5036,10 @@ packages: engines: {node: '>=0.3.1'} dev: false + /dijkstrajs/1.0.2: + resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==} + dev: false + /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -5050,12 +5086,54 @@ packages: csstype: 3.1.1 dev: false + /dom-serializer/0.2.2: + resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==, registry: https://registry.yarnpkg.com/} + dependencies: + domelementtype: 2.3.0 + entities: 2.2.0 + + /dom-serializer/1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==, registry: https://registry.yarnpkg.com/} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + + /domelementtype/1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==, registry: https://registry.yarnpkg.com/} + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, registry: https://registry.yarnpkg.com/} + /domexception/2.0.1: resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} engines: {node: '>=8'} dependencies: webidl-conversions: 5.0.0 + /domhandler/4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==, registry: https://registry.yarnpkg.com/} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + + /dompurify/2.4.0: + resolution: {integrity: sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==, registry: https://registry.yarnpkg.com/} + dev: false + + /domutils/1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==, registry: https://registry.yarnpkg.com/} + dependencies: + dom-serializer: 0.2.2 + domelementtype: 1.3.1 + + /domutils/2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==, registry: https://registry.yarnpkg.com/} + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + /dot-case/3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: @@ -5107,10 +5185,6 @@ packages: resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} engines: {node: '>=10'} - /emoji-regex/10.2.1: - resolution: {integrity: sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==} - dev: false - /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5121,6 +5195,10 @@ packages: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} + /encode-utf8/1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + dev: false + /encodeurl/1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -5129,7 +5207,7 @@ packages: resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==} engines: {node: '>=10.13.0'} dependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 tapable: 2.2.1 /enhanced-resolve/5.12.0: @@ -5140,6 +5218,9 @@ packages: tapable: 2.2.1 dev: true + /entities/2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==, registry: https://registry.yarnpkg.com/} + /error-ex/1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -6014,7 +6095,7 @@ packages: engines: {node: '>=10'} dependencies: at-least-node: 1.0.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 @@ -6163,7 +6244,6 @@ packages: /graceful-fs/4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true /grapheme-splitter/1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} @@ -6294,6 +6374,14 @@ packages: tapable: 2.2.1 webpack: 5.74.0 + /htmlparser2/6.1.0: + resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==, registry: https://registry.yarnpkg.com/} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + domutils: 2.8.0 + entities: 2.2.0 + /http-deceiver/1.2.7: resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} @@ -6805,7 +6893,7 @@ packages: ci-info: 3.4.0 deepmerge: 4.2.2 glob: 7.2.3 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jest-circus: 27.5.1 jest-environment-jsdom: 27.5.1 jest-environment-node: 27.5.1 @@ -6977,7 +7065,7 @@ packages: '@jest/types': 27.5.1 '@types/stack-utils': 2.0.1 chalk: 4.1.2 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 micromatch: 4.0.5 pretty-format: 27.5.1 slash: 3.0.0 @@ -6991,7 +7079,7 @@ packages: '@jest/types': 28.1.3 '@types/stack-utils': 2.0.1 chalk: 4.1.2 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 micromatch: 4.0.5 pretty-format: 28.1.3 slash: 3.0.0 @@ -7060,7 +7148,7 @@ packages: '@types/node': 16.11.59 chalk: 4.1.2 emittery: 0.8.1 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jest-docblock: 27.5.1 jest-environment-jsdom: 27.5.1 jest-environment-node: 27.5.1 @@ -7095,7 +7183,7 @@ packages: collect-v8-coverage: 1.0.1 execa: 5.1.1 glob: 7.2.3 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jest-haste-map: 27.5.1 jest-message-util: 27.5.1 jest-mock: 27.5.1 @@ -7113,7 +7201,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@types/node': 16.11.59 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 /jest-snapshot/27.5.1: resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} @@ -7131,7 +7219,7 @@ packages: babel-preset-current-node-syntax: 1.0.1_@babel+core@7.19.1 chalk: 4.1.2 expect: 27.5.1 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jest-diff: 27.5.1 jest-get-type: 27.5.1 jest-haste-map: 27.5.1 @@ -7163,7 +7251,7 @@ packages: '@types/node': 16.11.59 chalk: 4.1.2 ci-info: 3.4.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 picomatch: 2.3.1 /jest-validate/27.5.1: @@ -7366,7 +7454,7 @@ packages: dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 /jsonp/0.2.1: resolution: {integrity: sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==} @@ -7682,7 +7770,7 @@ packages: d3: 7.6.1 dagre: 0.8.5 dagre-d3: 0.6.4 - dompurify: registry.npmjs.org/dompurify/2.4.0 + dompurify: 2.4.0 graphlib: 2.1.8 khroma: 2.0.0 moment-mini: 2.24.0 @@ -8178,6 +8266,11 @@ packages: dependencies: find-up: 3.0.0 + /pngjs/5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + dev: false + /postcss-attribute-case-insensitive/5.0.2_postcss@8.4.16: resolution: {integrity: sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==} engines: {node: ^12 || ^14 || >=16} @@ -9008,6 +9101,17 @@ packages: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + /qrcode/1.5.1: + resolution: {integrity: sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + dijkstrajs: 1.0.2 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + dev: false + /qs/6.10.3: resolution: {integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==} engines: {node: '>=0.6'} @@ -9479,7 +9583,7 @@ packages: dependencies: css-select: 4.3.0 dom-converter: 0.2.0 - htmlparser2: registry.npmjs.org/htmlparser2/6.1.0 + htmlparser2: 6.1.0 lodash: 4.17.21 strip-ansi: 6.0.1 @@ -9491,6 +9595,10 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + /require-main-filename/2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: false + /requires-port/1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -9807,6 +9915,10 @@ packages: transitivePeerDependencies: - supports-color + /set-blocking/2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: false + /setprototypeof/1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} @@ -10487,6 +10599,37 @@ packages: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + /ts-node/10.9.1_yxpazyh7n5pql7jdaglasgwqki: + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 14.18.29 + acorn: 8.8.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: @@ -10760,7 +10903,7 @@ packages: engines: {node: '>=10.13.0'} dependencies: glob-to-regexp: 0.4.1 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 /wbuf/1.7.3: resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} @@ -10991,6 +11134,10 @@ packages: is-string: 1.0.7 is-symbol: 1.0.4 + /which-module/2.0.0: + resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} + dev: false + /which/1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -11151,7 +11298,7 @@ packages: /workbox-window/6.5.4: resolution: {integrity: sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==} dependencies: - '@types/trusted-types': registry.npmjs.org/@types/trusted-types/2.0.2 + '@types/trusted-types': 2.0.2 workbox-core: 6.5.4 /wrap-ansi/6.2.0: @@ -11161,7 +11308,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-ansi/7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} @@ -11216,6 +11362,10 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + /y18n/4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: false + /y18n/5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -11244,6 +11394,14 @@ packages: engines: {node: '>= 14'} dev: true + /yargs-parser/18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: false + /yargs-parser/20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -11253,6 +11411,23 @@ packages: engines: {node: '>=12'} dev: true + /yargs/15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.0 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: false + /yargs/16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -11301,111 +11476,3 @@ packages: react: 18.2.0 use-sync-external-store: 1.2.0_react@18.2.0 dev: false - - registry.npmjs.org/@types/color-convert/2.0.0: - resolution: {integrity: sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.0.tgz} - name: '@types/color-convert' - version: 2.0.0 - dependencies: - '@types/color-name': registry.npmjs.org/@types/color-name/1.1.1 - dev: true - - registry.npmjs.org/@types/color-name/1.1.1: - resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz} - name: '@types/color-name' - version: 1.1.1 - dev: true - - registry.npmjs.org/@types/color/3.0.3: - resolution: {integrity: sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/color/-/color-3.0.3.tgz} - name: '@types/color' - version: 3.0.3 - dependencies: - '@types/color-convert': registry.npmjs.org/@types/color-convert/2.0.0 - dev: true - - registry.npmjs.org/@types/dompurify/2.4.0: - resolution: {integrity: sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz} - name: '@types/dompurify' - version: 2.4.0 - dependencies: - '@types/trusted-types': registry.npmjs.org/@types/trusted-types/2.0.2 - dev: true - - registry.npmjs.org/@types/trusted-types/2.0.2: - resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz} - name: '@types/trusted-types' - version: 2.0.2 - - registry.npmjs.org/dom-serializer/0.2.2: - resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz} - name: dom-serializer - version: 0.2.2 - dependencies: - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - entities: registry.npmjs.org/entities/2.2.0 - - registry.npmjs.org/dom-serializer/1.4.1: - resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz} - name: dom-serializer - version: 1.4.1 - dependencies: - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - domhandler: registry.npmjs.org/domhandler/4.3.1 - entities: registry.npmjs.org/entities/2.2.0 - - registry.npmjs.org/domelementtype/1.3.1: - resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz} - name: domelementtype - version: 1.3.1 - - registry.npmjs.org/domelementtype/2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz} - name: domelementtype - version: 2.3.0 - - registry.npmjs.org/domhandler/4.3.1: - resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz} - name: domhandler - version: 4.3.1 - engines: {node: '>= 4'} - dependencies: - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - - registry.npmjs.org/dompurify/2.4.0: - resolution: {integrity: sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz} - name: dompurify - version: 2.4.0 - dev: false - - registry.npmjs.org/domutils/1.7.0: - resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz} - name: domutils - version: 1.7.0 - dependencies: - dom-serializer: registry.npmjs.org/dom-serializer/0.2.2 - domelementtype: registry.npmjs.org/domelementtype/1.3.1 - - registry.npmjs.org/domutils/2.8.0: - resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz} - name: domutils - version: 2.8.0 - dependencies: - dom-serializer: registry.npmjs.org/dom-serializer/1.4.1 - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - domhandler: registry.npmjs.org/domhandler/4.3.1 - - registry.npmjs.org/entities/2.2.0: - resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/entities/-/entities-2.2.0.tgz} - name: entities - version: 2.2.0 - - registry.npmjs.org/htmlparser2/6.1.0: - resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz} - name: htmlparser2 - version: 6.1.0 - dependencies: - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - domhandler: registry.npmjs.org/domhandler/4.3.1 - domutils: registry.npmjs.org/domutils/2.8.0 - entities: registry.npmjs.org/entities/2.2.0 diff --git a/ui/src/common/pattern.ts b/ui/src/common/pattern.ts index 72086a68..406e5e3e 100644 --- a/ui/src/common/pattern.ts +++ b/ui/src/common/pattern.ts @@ -1,7 +1,4 @@ -import emojiRegex from 'emoji-regex'; - const pattern = { - emoji: emojiRegex(), email: /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+\.)+[a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}))$/, }; diff --git a/ui/src/components/Header/components/NavItems/index.tsx b/ui/src/components/Header/components/NavItems/index.tsx index be7b6f34..346055ff 100644 --- a/ui/src/components/Header/components/NavItems/index.tsx +++ b/ui/src/components/Header/components/NavItems/index.tsx @@ -93,7 +93,9 @@ const Index: FC = ({ redDot, userInfo, logOut }) => { {/* Dropdown for user center agent info */} - {ucAgent?.enabled && ucAgent?.agent_info ? ( + {ucAgent?.enabled && + (ucAgent?.agent_info?.url || + ucAgent?.agent_info?.control_center?.length) ? ( = ({ redDot, userInfo, logOut }) => { - - {ucAgent.agent_info.name} - - + {ucAgent.agent_info.url ? ( + + {ucAgent.agent_info.name} + + ) : null} + {ucAgent.agent_info.url && + ucAgent.agent_info.control_center?.length ? ( + + ) : null} {ucAgent.agent_info.control_center?.map((ctrl) => { return ( diff --git a/ui/src/components/Icon/svg.tsx b/ui/src/components/Icon/svg.tsx index 86102ee9..4629c0be 100644 --- a/ui/src/components/Icon/svg.tsx +++ b/ui/src/components/Icon/svg.tsx @@ -3,7 +3,7 @@ import { FC } from 'react'; import { base64ToSvg } from '@/utils'; interface IProps { - base64: string; + base64: string | undefined; } const Icon: FC = ({ base64 = '' }) => { return base64 ? ( diff --git a/ui/src/pages/Users/Login/index.tsx b/ui/src/pages/Users/Login/index.tsx index 68f1ea59..19cafeef 100644 --- a/ui/src/pages/Users/Login/index.tsx +++ b/ui/src/pages/Users/Login/index.tsx @@ -3,25 +3,22 @@ import { Container, Form, Button, Col } from 'react-bootstrap'; import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { Trans, useTranslation } from 'react-i18next'; -import { RouteAlias } from '@/router/alias'; -import { REDIRECT_PATH_STORAGE_KEY } from '@/common/constants'; import { usePageTags } from '@/hooks'; import type { LoginReqParams, ImgCodeRes, FormDataType, } from '@/common/interface'; -import { SvgIcon, Unactivate, WelcomeTitle } from '@/components'; -import { PluginOauth } from '@/plugins'; +import { Unactivate, WelcomeTitle } from '@/components'; +import { PluginOauth, PluginUcLogin } from '@/plugins'; import { loggedUserInfoStore, loginSettingStore, userCenterStore, } from '@/stores'; -import { guard, floppyNavigation, handleFormError } from '@/utils'; +import { guard, handleFormError } from '@/utils'; import { login, checkImgCode } from '@/services'; import { PicAuthCodeModal } from '@/components/Modal'; -import Storage from '@/utils/storage'; const Index: React.FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'login' }); @@ -102,15 +99,6 @@ const Index: React.FC = () => { return bol; }; - const handleLoginRedirect = () => { - const redirect = Storage.get(REDIRECT_PATH_STORAGE_KEY) || RouteAlias.home; - Storage.remove(REDIRECT_PATH_STORAGE_KEY); - floppyNavigation.navigate(redirect, { - handler: navigate, - options: { replace: true }, - }); - }; - const handleLogin = (event?: any) => { if (event) { event.preventDefault(); @@ -133,7 +121,7 @@ const Index: React.FC = () => { setStep(2); setRefresh((pre) => pre + 1); } else { - handleLoginRedirect(); + guard.handleLoginRedirect(navigate); } setModalState(false); @@ -184,19 +172,8 @@ const Index: React.FC = () => { {ucLoginRedirect && step === 1 && ( - - + + )} {step === 1 && !ucLoginRedirect && ( diff --git a/ui/src/pages/Users/OauthCallback/index.tsx b/ui/src/pages/Users/OauthCallback/index.tsx index 2008ec45..957a85c0 100644 --- a/ui/src/pages/Users/OauthCallback/index.tsx +++ b/ui/src/pages/Users/OauthCallback/index.tsx @@ -2,40 +2,16 @@ import { FC, memo, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useSearchParams, useNavigate } from 'react-router-dom'; -import { usePageTags, useLoginRedirect } from '@/hooks'; -import { loggedUserInfoStore } from '@/stores'; -import { getLoggedUserInfo } from '@/services'; -import Storage from '@/utils/storage'; -import { LOGGED_TOKEN_STORAGE_KEY } from '@/common/constants'; +import { usePageTags } from '@/hooks'; import { guard } from '@/utils'; const Index: FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'page_title' }); const [searchParams] = useSearchParams(); - const { loginRedirect } = useLoginRedirect(); - const updateUser = loggedUserInfoStore((state) => state.update); const navigate = useNavigate(); - useEffect(() => { const token = searchParams.get('access_token'); - - if (token) { - Storage.set(LOGGED_TOKEN_STORAGE_KEY, token); - getLoggedUserInfo().then((res) => { - updateUser(res); - const userStat = guard.deriveLoginState(); - if (userStat.isNotActivated) { - // inactive - navigate('/users/login?status=inactive', { replace: true }); - } else { - setTimeout(() => { - loginRedirect(); - }, 0); - } - }); - } else { - navigate('/', { replace: true }); - } + guard.handleLoginWithToken(token, navigate); }, []); usePageTags({ title: t('oauth_callback'), diff --git a/ui/src/plugins/PluginUcLogin/WeCom.tsx b/ui/src/plugins/PluginUcLogin/WeCom.tsx new file mode 100644 index 00000000..7e0af23c --- /dev/null +++ b/ui/src/plugins/PluginUcLogin/WeCom.tsx @@ -0,0 +1,81 @@ +import React, { memo, FC, useState, useEffect } from 'react'; +import { Card } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import QrCode from 'qrcode'; + +import { userCenterStore } from '@/stores'; +import { guard } from '@/utils'; + +import { getLoginConf, checkLoginResult } from './wecom.service'; + +let checkTimer: NodeJS.Timeout; +const Index: FC = () => { + const { t } = useTranslation('translation', { keyPrefix: 'plugins' }); + const ucAgent = userCenterStore().agent; + const agentName = ucAgent?.agent_info?.name || ''; + const [qrcodeDataUrl, setQrCodeDataUrl] = useState(''); + const handleLoginResult = (key: string) => { + if (!key) { + return; + } + checkLoginResult(key).then((res) => { + if (res.is_login) { + guard.handleLoginWithToken(res.token); + return; + } + clearTimeout(checkTimer); + checkTimer = setTimeout(() => { + handleLoginResult(key); + }, 2000); + }); + }; + const handleQrCode = (targetUrl: string) => { + if (!targetUrl) { + return; + } + QrCode.toDataURL(targetUrl, { width: 240 }, (err, url) => { + if (err) { + return; + } + setQrCodeDataUrl(url); + }); + }; + + useEffect(() => { + if (!agentName) { + return; + } + getLoginConf().then((res) => { + handleQrCode(res?.redirect_url); + handleLoginResult(res?.key); + }); + }, [agentName]); + useEffect(() => { + return () => { + clearTimeout(checkTimer); + }; + }, []); + if (/WeCom/i.test(agentName)) { + return ( + + + + {agentName} {t('login')} + + {qrcodeDataUrl ? ( + <> + +
+ {t('qrcode_login_tip', { agentName })} +
+ + ) : null} +
+
+ ); + } + return null; +}; + +export default memo(Index); diff --git a/ui/src/plugins/PluginUcLogin/index.tsx b/ui/src/plugins/PluginUcLogin/index.tsx new file mode 100644 index 00000000..e7d78add --- /dev/null +++ b/ui/src/plugins/PluginUcLogin/index.tsx @@ -0,0 +1,33 @@ +import React, { memo, FC } from 'react'; +import { Button } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import { SvgIcon } from '@/components'; +import { userCenterStore } from '@/stores'; + +import WeComLogin from './WeCom'; + +const Index: FC = () => { + const { t } = useTranslation('translation', { keyPrefix: 'plugins.oauth' }); + const ucAgent = userCenterStore().agent; + const agentName = ucAgent?.agent_info?.name || ''; + const ucLoginRedirect = + ucAgent?.enabled && ucAgent?.agent_info?.login_redirect_url; + if (/WeCom/i.test(agentName)) { + return ; + } + if (ucLoginRedirect) { + return ( + + ); + } + return null; +}; + +export default memo(Index); diff --git a/ui/src/plugins/PluginUcLogin/wecom.service.ts b/ui/src/plugins/PluginUcLogin/wecom.service.ts new file mode 100644 index 00000000..1b183559 --- /dev/null +++ b/ui/src/plugins/PluginUcLogin/wecom.service.ts @@ -0,0 +1,21 @@ +import request from '@/utils/request'; + +type loginConf = { + key: string; + redirect_url: string; +}; + +type loginResult = { + is_login: boolean; + token: string; +}; + +export const getLoginConf = () => { + const apiUrl = `/answer/api/v1/wecom/login/url`; + return request.get(apiUrl); +}; + +export const checkLoginResult = (key: loginConf['key']) => { + const apiUrl = `/answer/api/v1/wecom/login/check?key=${key}`; + return request.get(apiUrl); +}; diff --git a/ui/src/plugins/index.ts b/ui/src/plugins/index.ts index b38e66fd..09d25445 100644 --- a/ui/src/plugins/index.ts +++ b/ui/src/plugins/index.ts @@ -1,3 +1,4 @@ import PluginOauth from './PluginOauth'; +import PluginUcLogin from './PluginUcLogin'; -export { PluginOauth }; +export { PluginOauth, PluginUcLogin }; diff --git a/ui/src/utils/floppyNavigation.ts b/ui/src/utils/floppyNavigation.ts index 415ef724..a7fa9970 100644 --- a/ui/src/utils/floppyNavigation.ts +++ b/ui/src/utils/floppyNavigation.ts @@ -47,15 +47,12 @@ const isRoutableLink = (url = '') => { * only navigate if not same as current url */ type NavigateHandler = 'href' | 'replace' | NavigateFunction; -interface NavigateConfig { - handler: NavigateHandler; +export interface NavigateConfig { + handler?: NavigateHandler; options?: any; } -const navigate = ( - to: string | number, - config: NavigateConfig = { handler: 'href' }, -) => { - let { handler } = config; +const navigate = (to: string | number, config: NavigateConfig = {}) => { + let { handler = 'href' } = config; if (to && typeof to === 'string') { if (!differentCurrent(to)) { return; @@ -130,7 +127,6 @@ const handleRouteLinkClick = (evt) => { }; export const floppyNavigation = { - differentCurrent, navigate, navigateToLogin, shouldProcessLinkClick, diff --git a/ui/src/utils/guard.ts b/ui/src/utils/guard.ts index 86039e2c..84511e62 100644 --- a/ui/src/utils/guard.ts +++ b/ui/src/utils/guard.ts @@ -11,9 +11,14 @@ import { loginToContinueStore, } from '@/stores'; import { RouteAlias } from '@/router/alias'; +import { + LOGGED_TOKEN_STORAGE_KEY, + REDIRECT_PATH_STORAGE_KEY, +} from '@/common/constants'; +import Storage from '@/utils/storage'; import { setupAppLanguage, setupAppTimeZone } from './localize'; -import { floppyNavigation } from './floppyNavigation'; +import { floppyNavigation, NavigateConfig } from './floppyNavigation'; import { pullUcAgent, getLoginUrl, getSignUpUrl } from './userCenter'; type TLoginState = { @@ -310,6 +315,51 @@ export const tryLoggedAndActivated = () => { return gr; }; +/** + * Auto handling of page redirect logic after a successful login + */ +export const handleLoginRedirect = (handler?: NavigateConfig['handler']) => { + const redirectUrl = Storage.get(REDIRECT_PATH_STORAGE_KEY) || RouteAlias.home; + Storage.remove(REDIRECT_PATH_STORAGE_KEY); + floppyNavigation.navigate(redirectUrl, { + handler, + options: { replace: true }, + }); +}; + +/** + * Unified processing of login logic after getting `access_token` + */ +export const handleLoginWithToken = ( + token: string | null, + handler?: NavigateConfig['handler'], +) => { + if (token) { + Storage.set(LOGGED_TOKEN_STORAGE_KEY, token); + getLoggedUserInfo().then((res) => { + loggedUserInfoStore.getState().update(res); + const userStat = deriveLoginState(); + if (userStat.isNotActivated) { + floppyNavigation.navigate(RouteAlias.activation, { + handler, + options: { + replace: true, + }, + }); + } else { + handleLoginRedirect(handler); + } + }); + } else { + floppyNavigation.navigate(RouteAlias.home, { + handler, + options: { + replace: true, + }, + }); + } +}; + /** * Initialize app configuration */ @@ -339,7 +389,6 @@ export const setupApp = async () => { * 1. must pre init logged user info for router guard * 2. must pre init app settings for app render */ - // TODO: optimize `initAppSettingsStore` by server render await Promise.allSettled([ pullLoggedUser(), pullUcAgent(),