Compare commits

..

1 Commits

Author SHA1 Message Date
Michael S. Molina
c85661f4fd feat: Chat prototype 2026-05-15 15:15:42 -03:00
77 changed files with 646 additions and 916 deletions

View File

@@ -71,7 +71,7 @@
"@storybook/theming": "^8.6.15",
"@superset-ui/core": "^0.20.4",
"@swc/core": "^1.15.33",
"antd": "^6.4.2",
"antd": "^6.3.7",
"baseline-browser-mapping": "^2.10.29",
"caniuse-lite": "^1.0.30001792",
"docusaurus-plugin-openapi-docs": "^5.0.2",

View File

@@ -212,7 +212,7 @@
resolved "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz"
integrity sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==
"@ant-design/icons@^6.2.3":
"@ant-design/icons@^6.1.1", "@ant-design/icons@^6.2.3":
version "6.2.3"
resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-6.2.3.tgz#66e1c7fdea009b9c3fab6964062bedc76f308ad8"
integrity sha512-Pl3aoAtxQeKryYnt6VvDJtOxMOtA8wrRSACe/pTjOAIG3fdHrWm6Ivb4ku9tsFjYroSXBKirvuxG4QkwBXD9gg==
@@ -1158,10 +1158,10 @@
dependencies:
core-js-pure "^3.43.0"
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.25.6", "@babel/runtime@^7.25.9", "@babel/runtime@^7.28.4", "@babel/runtime@^7.29.2":
version "7.29.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.2.tgz#9a6e2d05f4b6692e1801cd4fb176ad823930ed5e"
integrity sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.25.6", "@babel/runtime@^7.25.9", "@babel/runtime@^7.28.4":
version "7.28.4"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz"
integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==
"@babel/template@^7.27.1", "@babel/template@^7.27.2", "@babel/template@^7.28.6":
version "7.28.6"
@@ -2924,13 +2924,13 @@
dependencies:
"@babel/runtime" "^7.24.4"
"@rc-component/cascader@~1.15.0":
version "1.15.0"
resolved "https://registry.yarnpkg.com/@rc-component/cascader/-/cascader-1.15.0.tgz#554cba8e01e94a1288547cec96422b2cfc73ff40"
integrity sha512-ZzpMtwFCRo3fbXHuDnncARJMZQjdqA2w7aDuPofNQt+aDx39st1hgfIpEwTBLhe2Hqsvs/zOr8RTtgxTkCPySw==
"@rc-component/cascader@~1.14.0":
version "1.14.0"
resolved "https://registry.yarnpkg.com/@rc-component/cascader/-/cascader-1.14.0.tgz#74e1fca58cb14f8f75f6e4bf1debd90534aaea7c"
integrity sha512-Ip9356xwZUR2nbW5PRVGif4B/bDve4pLa/N+PGbvBaTnjbvmN4PFMBGQSmlDlzKP1ovxaYMvwF/dI9lXNLT4iQ==
dependencies:
"@rc-component/select" "~1.6.0"
"@rc-component/tree" "~1.3.0"
"@rc-component/tree" "~1.2.0"
"@rc-component/util" "^1.4.0"
clsx "^2.1.1"
@@ -2968,10 +2968,10 @@
dependencies:
"@rc-component/util" "^1.3.0"
"@rc-component/dialog@~1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@rc-component/dialog/-/dialog-1.9.0.tgz#3134f8fa8644d9bc228c862668b90de048c7ea1a"
integrity sha512-zbAAogkg4kkKum79sLE6M+vq1jSAW25zdkafrahgcTP9t9S//SD634Znd1A4c8F2Gc12ZKnehGLsVaaOvZzD2A==
"@rc-component/dialog@~1.8.4":
version "1.8.4"
resolved "https://registry.yarnpkg.com/@rc-component/dialog/-/dialog-1.8.4.tgz#e1f05f311539852f40a5717bc3874ce0af64c6ff"
integrity sha512-Ay6PM7phkTkquplG8fWfUGFZ2GTLx9diTl4f0d8Eqxd7W1u1KjE9AQooFQHOHnhZf0Ya3z51+5EKCWHmt/dNEw==
dependencies:
"@rc-component/motion" "^1.1.3"
"@rc-component/portal" "^2.1.0"
@@ -3025,30 +3025,30 @@
"@rc-component/util" "^1.4.0"
clsx "^2.1.1"
"@rc-component/input@~1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@rc-component/input/-/input-1.3.0.tgz#a8c113000bbc39089cf75337bec68120115b9e05"
integrity sha512-IUUNOdAuWuEvDEFFgfmwQl818tiDbvXwLgon4HL1q2hJeYkqrRrYwYhJN0zfPHGTDxs3gvyVC/C02D4hWFoIcA==
"@rc-component/input@~1.1.0", "@rc-component/input@~1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@rc-component/input/-/input-1.1.2.tgz"
integrity sha512-Q61IMR47piUBudgixJ30CciKIy9b1H95qe7GgEKOmSJVJXvFRWJllJfQry9tif+MX2cWFXWJf/RXz4kaCeq/Fg==
dependencies:
"@rc-component/resize-observer" "^1.1.1"
"@rc-component/util" "^1.4.0"
clsx "^2.1.1"
"@rc-component/mentions@~1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@rc-component/mentions/-/mentions-1.9.0.tgz#1e133d607835854430e264b681b7b32c4b49daa7"
integrity sha512-WUwfFKDSOF5S9UPsNsXcLYtzjTxBGsftTXWRbZuxX6BYrsySISTnujfJNgaaQ6qVzaCDJ35QUkZKvsYxip1C5g==
"@rc-component/mentions@~1.6.0":
version "1.6.0"
resolved "https://registry.npmjs.org/@rc-component/mentions/-/mentions-1.6.0.tgz"
integrity sha512-KIkQNP6habNuTsLhUv0UGEOwG67tlmE7KNIJoQZZNggEZl5lQJTytFDb69sl5CK3TDdISCTjKP3nGEBKgT61CQ==
dependencies:
"@rc-component/input" "~1.3.0"
"@rc-component/menu" "~1.3.0"
"@rc-component/input" "~1.1.0"
"@rc-component/menu" "~1.2.0"
"@rc-component/textarea" "~1.1.0"
"@rc-component/trigger" "^3.0.0"
"@rc-component/util" "^1.3.0"
clsx "^2.1.1"
"@rc-component/menu@~1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@rc-component/menu/-/menu-1.3.0.tgz#fc70d81ca76ae6013b0d7955f20a2393adef04b3"
integrity sha512-u3NfiwpiEgT177qa5Yxm5QsI8i/93EBGpWj8HYZQDnh2pCZ2xtQCe/+w3pSR2NlwKOZDTCKzEhEyD09mGphssA==
"@rc-component/menu@~1.2.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@rc-component/menu/-/menu-1.2.0.tgz"
integrity sha512-VWwDuhvYHSnTGj4n6bV3ISrLACcPAzdPOq3d0BzkeiM5cve8BEYfvkEhNoM0PLzv51jpcejeyrLXeMVIJ+QJlg==
dependencies:
"@rc-component/motion" "^1.1.4"
"@rc-component/overflow" "^1.0.0"
@@ -3078,13 +3078,13 @@
dependencies:
"@rc-component/util" "^1.2.0"
"@rc-component/notification@~2.0.6":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@rc-component/notification/-/notification-2.0.7.tgz#f2450a482f87e4698285833c4a8efcac169acabb"
integrity sha512-nqZzpf6BPdaj+3ILx7si79LLmqPKyUmQoXa+/9gg0SkH0v1DbD66oJgRMSBEVnd/zUT3D4gwxWIHUKebYf2ZXQ==
"@rc-component/notification@~1.2.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@rc-component/notification/-/notification-1.2.0.tgz"
integrity sha512-OX3J+zVU7rvoJCikjrfW7qOUp7zlDeFBK2eA3SFbGSkDqo63Sl4Ss8A04kFP+fxHSxMDIS9jYVEZtU1FNCFuBA==
dependencies:
"@rc-component/motion" "^1.1.4"
"@rc-component/util" "^1.11.0"
"@rc-component/util" "^1.2.1"
clsx "^2.1.1"
"@rc-component/overflow@^1.0.0":
@@ -3105,10 +3105,10 @@
"@rc-component/util" "^1.3.0"
clsx "^2.1.1"
"@rc-component/picker@~1.10.0":
version "1.10.0"
resolved "https://registry.yarnpkg.com/@rc-component/picker/-/picker-1.10.0.tgz#6989f0ae67fca8db00e31f81a8217c8bc370cd34"
integrity sha512-vVOXP2RVWozwpERGUFAehVH1Jz6o/uRrAb9qSZm1LC+iJs8rvEwFo1bzz2jlOYV+uWwu0dIuG86tnDui14Ea0w==
"@rc-component/picker@~1.9.1":
version "1.9.1"
resolved "https://registry.yarnpkg.com/@rc-component/picker/-/picker-1.9.1.tgz#7ffcb1e4d4655fe2f3d712773e1d3ab9cd5c2a5c"
integrity sha512-9FBYYsvH3HMLICaPDA/1Th5FLaDkFa7qAtangIdlhKb3ZALaR745e9PsOhheJb6asS4QXc12ffiAcjdkZ4C5/g==
dependencies:
"@rc-component/overflow" "^1.0.0"
"@rc-component/resize-observer" "^1.0.0"
@@ -3199,10 +3199,10 @@
"@rc-component/util" "^1.3.0"
clsx "^2.1.1"
"@rc-component/table@~1.10.0":
version "1.10.0"
resolved "https://registry.yarnpkg.com/@rc-component/table/-/table-1.10.0.tgz#7a98d68176f23f50a762df464f4c9142e7db3942"
integrity sha512-SjtpcCf+rL7dDc62GKT3rXTdERjVuJvRiqjpU7g0Jc/ewCifXynHc7Nm3Em1XsD+WhGrgQtxNDScI/0+Lpfr0w==
"@rc-component/table@~1.9.1":
version "1.9.1"
resolved "https://registry.npmjs.org/@rc-component/table/-/table-1.9.1.tgz"
integrity sha512-FVI5ZS/GdB3BcgexfCYKi3iHhZS3Fr59EtsxORszYGrfpH1eWr33eDNSYkVfLI6tfJ7vftJDd9D5apfFWqkdJg==
dependencies:
"@rc-component/context" "^2.0.1"
"@rc-component/resize-observer" "^1.0.0"
@@ -3210,18 +3210,28 @@
"@rc-component/virtual-list" "^1.0.1"
clsx "^2.1.1"
"@rc-component/tabs@~1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@rc-component/tabs/-/tabs-1.9.0.tgz#8f3e3755450e5a90d240d1ed3dc140d520b1fbef"
integrity sha512-tn1slmbbaTyt8mgwyWJcT8jo/qNiYUs6u1H7OgGQt9faYO06BJIkU5cTmMqORzIrNmSEeeUY6pD5i+JlqSHYhg==
"@rc-component/tabs@~1.7.0":
version "1.7.0"
resolved "https://registry.npmjs.org/@rc-component/tabs/-/tabs-1.7.0.tgz"
integrity sha512-J48cs2iBi7Ho3nptBxxIqizEliUC+ExE23faspUQKGQ550vaBlv3aGF8Epv/UB1vFWeoJDTW/dNzgIU0Qj5i/w==
dependencies:
"@rc-component/dropdown" "~1.0.0"
"@rc-component/menu" "~1.3.0"
"@rc-component/menu" "~1.2.0"
"@rc-component/motion" "^1.1.3"
"@rc-component/resize-observer" "^1.0.0"
"@rc-component/util" "^1.3.0"
clsx "^2.1.1"
"@rc-component/textarea@~1.1.0", "@rc-component/textarea@~1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@rc-component/textarea/-/textarea-1.1.2.tgz"
integrity sha512-9rMUEODWZDMovfScIEHXWlVZuPljZ2pd1LKNjslJVitn4SldEzq5vO1CL3yy3Dnib6zZal2r2DPtjy84VVpF6A==
dependencies:
"@rc-component/input" "~1.1.0"
"@rc-component/resize-observer" "^1.0.0"
"@rc-component/util" "^1.3.0"
clsx "^2.1.1"
"@rc-component/tooltip@~1.4.0":
version "1.4.0"
resolved "https://registry.npmjs.org/@rc-component/tooltip/-/tooltip-1.4.0.tgz"
@@ -3231,30 +3241,30 @@
"@rc-component/util" "^1.3.0"
clsx "^2.1.1"
"@rc-component/tour@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@rc-component/tour/-/tour-2.4.0.tgz#caf89cf8f2f9fb68f1fb0e0c867610015d01f432"
integrity sha512-aui4r4TqmTzwaBgcQxHYep8kM8PTjZFufjokObpy35KfFeZ0k9ArquWFZqegQlH24P14t+F0qO0mGTgzlav1yg==
"@rc-component/tour@~2.3.0":
version "2.3.0"
resolved "https://registry.npmjs.org/@rc-component/tour/-/tour-2.3.0.tgz"
integrity sha512-K04K9r32kUC+auBSQfr+Fss4SpSIS9JGe56oq/ALAX0p+i2ylYOI1MgR83yBY7v96eO6ZFXcM/igCQmubps0Ow==
dependencies:
"@rc-component/portal" "^2.2.0"
"@rc-component/trigger" "^3.0.0"
"@rc-component/util" "^1.7.0"
clsx "^2.1.1"
"@rc-component/tree-select@~1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@rc-component/tree-select/-/tree-select-1.9.0.tgz#13ea516478b6cb558e04181abb0a01ae6fbdd31f"
integrity sha512-GXcFe15a+trUl1/J3OHWQhsVWFpwFpGFK2cqYWZ1sK22Zs3KZTvMwDpzr75PIo1s6QVioVxpE/pRwRopkeDQ6w==
"@rc-component/tree-select@~1.8.0":
version "1.8.0"
resolved "https://registry.yarnpkg.com/@rc-component/tree-select/-/tree-select-1.8.0.tgz#480e84221befbd1fa93ab2034423e2b064e41981"
integrity sha512-iYsPq3nuLYvGqdvFAW+l+I9ASRIOVbMXyA8FGZg2lGym/GwkaWeJGzI4eJ7c9IOEhRj0oyfIN4S92Fl3J05mjQ==
dependencies:
"@rc-component/select" "~1.6.0"
"@rc-component/tree" "~1.3.0"
"@rc-component/tree" "~1.2.0"
"@rc-component/util" "^1.4.0"
clsx "^2.1.1"
"@rc-component/tree@~1.3.0", "@rc-component/tree@~1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@rc-component/tree/-/tree-1.3.1.tgz#6983ca6bd9d5f6d04dd7258d00cb0fe71cdfe661"
integrity sha512-zlL0PW0bTFlveTtLcA01VD/yMWKK73EywItFMgIZUY5sb6tMOAw7zV6qGzqldufqrV93ZWQB4H3NBNoTMCueJA==
"@rc-component/tree@~1.2.0", "@rc-component/tree@~1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@rc-component/tree/-/tree-1.2.4.tgz#cb4f7d818118b3447763e74d3a82fba6454c7317"
integrity sha512-5Gli43+m4R7NhpYYz3Z61I6LOw9yI6CNChxgVtvrO6xB1qML7iE6QMLVMB3+FTjo2yF6uFdAHtqWPECz/zbX5w==
dependencies:
"@rc-component/motion" "^1.0.0"
"@rc-component/util" "^1.8.1"
@@ -3280,10 +3290,10 @@
"@rc-component/util" "^1.3.0"
clsx "^2.1.1"
"@rc-component/util@^1.1.0", "@rc-component/util@^1.10.1", "@rc-component/util@^1.11.0", "@rc-component/util@^1.2.0", "@rc-component/util@^1.2.1", "@rc-component/util@^1.3.0", "@rc-component/util@^1.4.0", "@rc-component/util@^1.6.2", "@rc-component/util@^1.7.0", "@rc-component/util@^1.8.1", "@rc-component/util@^1.9.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@rc-component/util/-/util-1.11.0.tgz#965c8b44a3f57fc96dc14e5072afbe32e422fd4d"
integrity sha512-jHG3/BYgUWiP5c7RZHiaUNToyw1L3nlPSKG2RPu+YoiD9b3ajiJwBWhsjO+ZELmCsKFAjNR5DelbKdlF0e2BDA==
"@rc-component/util@^1.1.0", "@rc-component/util@^1.10.1", "@rc-component/util@^1.2.0", "@rc-component/util@^1.2.1", "@rc-component/util@^1.3.0", "@rc-component/util@^1.4.0", "@rc-component/util@^1.6.2", "@rc-component/util@^1.7.0", "@rc-component/util@^1.8.1", "@rc-component/util@^1.9.0":
version "1.10.1"
resolved "https://registry.yarnpkg.com/@rc-component/util/-/util-1.10.1.tgz#213c84c77e8b2001095530d3b0dc47c49c34ffe3"
integrity sha512-q++9S6rUa5Idb/xIBNz6jtvumw5+O5YV5V0g4iK9mn9jWs4oGJheE3ZN1kAnE723AXyaD8v95yeOASmdk8Jnng==
dependencies:
is-mobile "^5.0.0"
react-is "^18.2.0"
@@ -5491,36 +5501,36 @@ ansis@^3.2.0:
resolved "https://registry.yarnpkg.com/ansis/-/ansis-3.17.0.tgz#fa8d9c2a93fe7d1177e0c17f9eeb562a58a832d7"
integrity sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==
antd@^6.4.2:
version "6.4.2"
resolved "https://registry.yarnpkg.com/antd/-/antd-6.4.2.tgz#9fc0fee455a5c56e7ec27855495eefadc8df636a"
integrity sha512-PNJz8Vxc/mC3EsOg/h3e2YuaZduJ1RDp4RmySDuDmKPCxVgyp4Da4kB36o87p9hbLbOWdAWCKQlnyopsN8utKQ==
antd@^6.3.7:
version "6.3.7"
resolved "https://registry.yarnpkg.com/antd/-/antd-6.3.7.tgz#620354ec04135356cbc5ce0a666871ddc73e4117"
integrity sha512-WTHi4bHVNKpYXLHESzU0Tts7rRNQeL84Bph9dfI3Qw7mHbTulExDcYKNHny5CTXcrBBOpraXbU9miBAwUR5vaw==
dependencies:
"@ant-design/colors" "^8.0.1"
"@ant-design/cssinjs" "^2.1.2"
"@ant-design/cssinjs-utils" "^2.1.2"
"@ant-design/fast-color" "^3.0.1"
"@ant-design/icons" "^6.2.3"
"@ant-design/icons" "^6.1.1"
"@ant-design/react-slick" "~2.0.0"
"@babel/runtime" "^7.29.2"
"@rc-component/cascader" "~1.15.0"
"@babel/runtime" "^7.28.4"
"@rc-component/cascader" "~1.14.0"
"@rc-component/checkbox" "~2.0.0"
"@rc-component/collapse" "~1.2.0"
"@rc-component/color-picker" "~3.1.1"
"@rc-component/dialog" "~1.9.0"
"@rc-component/dialog" "~1.8.4"
"@rc-component/drawer" "~1.4.2"
"@rc-component/dropdown" "~1.0.2"
"@rc-component/form" "~1.8.1"
"@rc-component/image" "~1.9.0"
"@rc-component/input" "~1.3.0"
"@rc-component/input" "~1.1.2"
"@rc-component/input-number" "~1.6.2"
"@rc-component/mentions" "~1.9.0"
"@rc-component/menu" "~1.3.0"
"@rc-component/mentions" "~1.6.0"
"@rc-component/menu" "~1.2.0"
"@rc-component/motion" "^1.3.2"
"@rc-component/mutate-observer" "^2.0.1"
"@rc-component/notification" "~2.0.6"
"@rc-component/notification" "~1.2.0"
"@rc-component/pagination" "~1.2.0"
"@rc-component/picker" "~1.10.0"
"@rc-component/picker" "~1.9.1"
"@rc-component/progress" "~1.0.2"
"@rc-component/qrcode" "~1.1.1"
"@rc-component/rate" "~1.0.1"
@@ -5530,12 +5540,13 @@ antd@^6.4.2:
"@rc-component/slider" "~1.0.1"
"@rc-component/steps" "~1.2.2"
"@rc-component/switch" "~1.0.3"
"@rc-component/table" "~1.10.0"
"@rc-component/tabs" "~1.9.0"
"@rc-component/table" "~1.9.1"
"@rc-component/tabs" "~1.7.0"
"@rc-component/textarea" "~1.1.2"
"@rc-component/tooltip" "~1.4.0"
"@rc-component/tour" "~2.4.0"
"@rc-component/tree" "~1.3.1"
"@rc-component/tree-select" "~1.9.0"
"@rc-component/tour" "~2.3.0"
"@rc-component/tree" "~1.2.4"
"@rc-component/tree-select" "~1.8.0"
"@rc-component/trigger" "^3.9.0"
"@rc-component/upload" "~1.1.0"
"@rc-component/util" "^1.10.1"
@@ -7090,7 +7101,12 @@ data-view-byte-offset@^1.0.1:
es-errors "^1.3.0"
is-data-view "^1.0.1"
dayjs@^1.11.11, dayjs@^1.11.19:
dayjs@^1.11.11:
version "1.11.13"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz"
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
dayjs@^1.11.19:
version "1.11.20"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.20.tgz#88d919fd639dc991415da5f4cb6f1b6650811938"
integrity sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==

View File

View File

@@ -120,13 +120,13 @@
"pretty-ms": "^9.3.0",
"query-string": "9.3.1",
"re-resizable": "^6.11.2",
"react": "^18.3.0",
"react": "^18.2.0",
"react-arborist": "^3.5.0",
"react-checkbox-tree": "^1.8.0",
"react-diff-viewer-continued": "^4.2.2",
"react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3",
"react-dom": "^18.3.0",
"react-dom": "^18.2.0",
"react-google-recaptcha": "^3.1.0",
"react-intersection-observer": "^10.0.3",
"react-json-tree": "^0.20.0",
@@ -209,8 +209,8 @@
"@types/json-bigint": "^1.0.4",
"@types/mousetrap": "^1.6.15",
"@types/node": "^25.6.0",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/react-loadable": "^5.5.11",
"@types/react-redux": "^7.1.10",
"@types/react-resizable": "^3.0.8",
@@ -274,7 +274,6 @@
"prettier": "3.8.3",
"prettier-plugin-packagejson": "^3.0.2",
"process": "^0.11.10",
"react-dnd-test-backend": "^11.1.3",
"react-refresh": "^0.18.0",
"react-resizable": "^3.1.3",
"redux-mock-store": "^1.5.4",
@@ -287,7 +286,7 @@
"terser-webpack-plugin": "^5.6.0",
"ts-jest": "^29.4.9",
"tscw-config": "^1.1.2",
"tsx": "^4.22.0",
"tsx": "^4.21.0",
"typescript": "5.4.5",
"unzipper": "^0.12.3",
"vm-browserify": "^1.1.2",
@@ -295,7 +294,7 @@
"webpack": "^5.106.2",
"webpack-bundle-analyzer": "^5.3.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.4",
"webpack-dev-server": "^5.2.3",
"webpack-manifest-plugin": "^5.0.1",
"webpack-sources": "^3.4.1",
"webpack-visualizer-plugin2": "^2.0.0"
@@ -3631,9 +3630,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
"integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
"integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
"cpu": [
"arm64"
],
@@ -3665,9 +3664,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
"integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
"integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
"cpu": [
"arm64"
],
@@ -3699,9 +3698,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
"integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
"integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
"cpu": [
"arm64"
],
@@ -41562,16 +41561,6 @@
"dnd-core": "^11.1.3"
}
},
"node_modules/react-dnd-test-backend": {
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/react-dnd-test-backend/-/react-dnd-test-backend-11.1.3.tgz",
"integrity": "sha512-5qFm+NI2GdWIUfiYun0A8Gv0xjbq0NGOPS+f6z3x/3nTuliApjmqcM1lfTgePoz1FDG47ZofF58N8y96If62+Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"dnd-core": "^11.1.3"
}
},
"node_modules/react-docgen": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.1.1.tgz",
@@ -46503,13 +46492,14 @@
"license": "0BSD"
},
"node_modules/tsx": {
"version": "4.22.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.0.tgz",
"integrity": "sha512-8ccZMPD69s1AbKXx0C5ddTNZfNjwV04iIKgjZmKfKxMynEtSYcK0Lh7iQFh53fI5Yu4pb9usgAiqyPmEONaALg==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.28.0"
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
},
"bin": {
"tsx": "dist/cli.mjs"
@@ -46522,9 +46512,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
"integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
"integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
"cpu": [
"ppc64"
],
@@ -46539,9 +46529,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/android-arm": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
"integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
"integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
"cpu": [
"arm"
],
@@ -46556,9 +46546,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/android-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
"integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
"integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
"cpu": [
"arm64"
],
@@ -46573,9 +46563,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/android-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
"integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
"integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
"cpu": [
"x64"
],
@@ -46590,9 +46580,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
"integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
"integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
"cpu": [
"arm64"
],
@@ -46607,9 +46597,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/darwin-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
"integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
"integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
"cpu": [
"x64"
],
@@ -46624,9 +46614,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
"integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
"integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
"cpu": [
"arm64"
],
@@ -46641,9 +46631,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
"integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
"integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
"cpu": [
"x64"
],
@@ -46658,9 +46648,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-arm": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
"integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
"integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
"cpu": [
"arm"
],
@@ -46675,9 +46665,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
"integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
"integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
"cpu": [
"arm64"
],
@@ -46692,9 +46682,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-ia32": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
"integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
"integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
"cpu": [
"ia32"
],
@@ -46709,9 +46699,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-loong64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
"integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
"integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
"cpu": [
"loong64"
],
@@ -46726,9 +46716,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
"integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
"integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
"cpu": [
"mips64el"
],
@@ -46743,9 +46733,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
"integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
"integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
"cpu": [
"ppc64"
],
@@ -46760,9 +46750,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
"integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
"integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
"cpu": [
"riscv64"
],
@@ -46777,9 +46767,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-s390x": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
"integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
"integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
"cpu": [
"s390x"
],
@@ -46794,9 +46784,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/linux-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
"integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
"integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
"cpu": [
"x64"
],
@@ -46811,9 +46801,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
"integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
"integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
"cpu": [
"x64"
],
@@ -46828,9 +46818,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
"integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
"integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
"cpu": [
"x64"
],
@@ -46845,9 +46835,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/sunos-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
"integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
"integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
"cpu": [
"x64"
],
@@ -46862,9 +46852,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/win32-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
"integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
"integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
"cpu": [
"arm64"
],
@@ -46879,9 +46869,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/win32-ia32": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
"integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
"integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
"cpu": [
"ia32"
],
@@ -46896,9 +46886,9 @@
}
},
"node_modules/tsx/node_modules/@esbuild/win32-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
"integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
"integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
"cpu": [
"x64"
],
@@ -46913,9 +46903,9 @@
}
},
"node_modules/tsx/node_modules/esbuild": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
"integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
"integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -46926,32 +46916,32 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.0",
"@esbuild/android-arm": "0.28.0",
"@esbuild/android-arm64": "0.28.0",
"@esbuild/android-x64": "0.28.0",
"@esbuild/darwin-arm64": "0.28.0",
"@esbuild/darwin-x64": "0.28.0",
"@esbuild/freebsd-arm64": "0.28.0",
"@esbuild/freebsd-x64": "0.28.0",
"@esbuild/linux-arm": "0.28.0",
"@esbuild/linux-arm64": "0.28.0",
"@esbuild/linux-ia32": "0.28.0",
"@esbuild/linux-loong64": "0.28.0",
"@esbuild/linux-mips64el": "0.28.0",
"@esbuild/linux-ppc64": "0.28.0",
"@esbuild/linux-riscv64": "0.28.0",
"@esbuild/linux-s390x": "0.28.0",
"@esbuild/linux-x64": "0.28.0",
"@esbuild/netbsd-arm64": "0.28.0",
"@esbuild/netbsd-x64": "0.28.0",
"@esbuild/openbsd-arm64": "0.28.0",
"@esbuild/openbsd-x64": "0.28.0",
"@esbuild/openharmony-arm64": "0.28.0",
"@esbuild/sunos-x64": "0.28.0",
"@esbuild/win32-arm64": "0.28.0",
"@esbuild/win32-ia32": "0.28.0",
"@esbuild/win32-x64": "0.28.0"
"@esbuild/aix-ppc64": "0.27.7",
"@esbuild/android-arm": "0.27.7",
"@esbuild/android-arm64": "0.27.7",
"@esbuild/android-x64": "0.27.7",
"@esbuild/darwin-arm64": "0.27.7",
"@esbuild/darwin-x64": "0.27.7",
"@esbuild/freebsd-arm64": "0.27.7",
"@esbuild/freebsd-x64": "0.27.7",
"@esbuild/linux-arm": "0.27.7",
"@esbuild/linux-arm64": "0.27.7",
"@esbuild/linux-ia32": "0.27.7",
"@esbuild/linux-loong64": "0.27.7",
"@esbuild/linux-mips64el": "0.27.7",
"@esbuild/linux-ppc64": "0.27.7",
"@esbuild/linux-riscv64": "0.27.7",
"@esbuild/linux-s390x": "0.27.7",
"@esbuild/linux-x64": "0.27.7",
"@esbuild/netbsd-arm64": "0.27.7",
"@esbuild/netbsd-x64": "0.27.7",
"@esbuild/openbsd-arm64": "0.27.7",
"@esbuild/openbsd-x64": "0.27.7",
"@esbuild/openharmony-arm64": "0.27.7",
"@esbuild/sunos-x64": "0.27.7",
"@esbuild/win32-arm64": "0.27.7",
"@esbuild/win32-ia32": "0.27.7",
"@esbuild/win32-x64": "0.27.7"
}
},
"node_modules/tsyringe": {
@@ -48655,9 +48645,9 @@
}
},
"node_modules/webpack-dev-server": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.4.tgz",
"integrity": "sha512-GqDPGZN9bRqKBTkp4aWkobDDHMsrXKoGSdOH56smIri8qR0JG8gfL8/v/f/OZR3/OKXjG8uwJbFVhKm/FNU/UA==",
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.3.tgz",
"integrity": "sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -50377,8 +50367,8 @@
"jed": "^1.1.1",
"lodash": "^4.18.1",
"nanoid": "^5.0.9",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-loadable": "^5.5.0",
"tinycolor2": "*"
}
@@ -50404,9 +50394,9 @@
"ace-builds": "^1.4.14",
"brace": "^0.11.1",
"memoize-one": "^5.1.1",
"react": "^18.3.0",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "^18.3.0"
"react-dom": "^18.2.0"
}
},
"packages/superset-ui-core": {
@@ -50490,8 +50480,8 @@
"@types/tinycolor2": "*",
"antd": "^5.26.0",
"nanoid": "^5.0.9",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-loadable": "^5.5.0",
"tinycolor2": "*"
}
@@ -50656,7 +50646,7 @@
"@emotion/react": "^11.4.1",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-calendar/node_modules/d3-array": {
@@ -50717,7 +50707,7 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-country-map/node_modules/d3-array": {
@@ -50745,7 +50735,7 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-horizon/node_modules/d3-array": {
@@ -50779,7 +50769,7 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-parallel-coordinates": {
@@ -50794,7 +50784,7 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-partition": {
@@ -50812,8 +50802,8 @@
"@superset-ui/core": "*",
"@testing-library/jest-dom": "*",
"@testing-library/react": "^14.0.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-rose": {
@@ -50830,7 +50820,7 @@
"@emotion/react": "^11.4.1",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-world-map": {
@@ -50848,7 +50838,7 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/legacy-plugin-chart-world-map/node_modules/d3-array": {
@@ -50935,7 +50925,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"dayjs": "^1.11.19",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/plugin-chart-ag-grid-table": {
@@ -50963,8 +50953,8 @@
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "*",
"@types/react": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"plugins/plugin-chart-ag-grid-table/node_modules/d3-array": {
@@ -51008,8 +50998,8 @@
"geostyler-wfs-parser": "^3.0.1",
"ol": "^10.8.0",
"polished": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"plugins/plugin-chart-echarts": {
@@ -51031,7 +51021,7 @@
"dayjs": "^1.11.19",
"echarts": "*",
"memoize-one": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/plugin-chart-echarts/node_modules/acorn": {
@@ -51089,9 +51079,9 @@
"dayjs": "^1.11.19",
"handlebars": "^4.7.8",
"lodash": "^4.18.1",
"react": "^18.3.0",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "^18.3.0"
"react-dom": "^18.2.0"
}
},
"plugins/plugin-chart-handlebars/node_modules/just-handlebars-helpers": {
@@ -51122,8 +51112,8 @@
"@superset-ui/core": "*",
"lodash": "^4.18.1",
"prop-types": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"plugins/plugin-chart-point-cluster-map": {
@@ -51141,8 +51131,8 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"plugins/plugin-chart-point-cluster-map/node_modules/react-map-gl": {
@@ -51195,8 +51185,8 @@
"@testing-library/user-event": "*",
"@types/react": "*",
"match-sorter": "^8.2.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"plugins/plugin-chart-table/node_modules/d3-array": {
@@ -51235,7 +51225,7 @@
"@superset-ui/core": "*",
"@types/lodash": "*",
"@types/react": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
},
"plugins/plugin-chart-word-cloud/node_modules/@types/d3-scale": {
@@ -51304,8 +51294,8 @@
"@superset-ui/core": "*",
"dayjs": "^1.11.19",
"mapbox-gl": ">=1.0.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"peerDependenciesMeta": {
"mapbox-gl": {

View File

@@ -109,20 +109,20 @@
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@fontsource/fira-code": "^5.2.7",
"@fontsource/ibm-plex-mono": "^5.2.7",
"@fontsource/inter": "^5.2.8",
"@googleapis/sheets": "^13.0.1",
"@great-expectations/jsonforms-antd-renderers": "^2.2.10",
"@jsonforms/core": "^3.7.0",
"@jsonforms/react": "^3.7.0",
"@jsonforms/vanilla-renderers": "^3.7.0",
"@luma.gl/constants": "~9.2.5",
"@luma.gl/core": "~9.2.5",
"@luma.gl/engine": "~9.2.5",
"@luma.gl/gltf": "~9.2.5",
"@luma.gl/shadertools": "~9.2.5",
"@luma.gl/webgl": "~9.2.5",
"@fontsource/fira-code": "^5.2.7",
"@fontsource/inter": "^5.2.8",
"@great-expectations/jsonforms-antd-renderers": "^2.2.10",
"@jsonforms/core": "^3.7.0",
"@jsonforms/react": "^3.7.0",
"@jsonforms/vanilla-renderers": "^3.7.0",
"@reduxjs/toolkit": "^1.9.3",
"@rjsf/antd": "^5.24.13",
"@rjsf/core": "^5.24.13",
@@ -140,16 +140,16 @@
"@superset-ui/legacy-plugin-chart-partition": "file:./plugins/legacy-plugin-chart-partition",
"@superset-ui/legacy-plugin-chart-rose": "file:./plugins/legacy-plugin-chart-rose",
"@superset-ui/legacy-plugin-chart-world-map": "file:./plugins/legacy-plugin-chart-world-map",
"@superset-ui/preset-chart-deckgl": "file:./plugins/preset-chart-deckgl",
"@superset-ui/legacy-preset-chart-nvd3": "file:./plugins/legacy-preset-chart-nvd3",
"@superset-ui/plugin-chart-ag-grid-table": "file:./plugins/plugin-chart-ag-grid-table",
"@superset-ui/plugin-chart-cartodiagram": "file:./plugins/plugin-chart-cartodiagram",
"@superset-ui/plugin-chart-echarts": "file:./plugins/plugin-chart-echarts",
"@superset-ui/plugin-chart-point-cluster-map": "file:./plugins/plugin-chart-point-cluster-map",
"@superset-ui/plugin-chart-handlebars": "file:./plugins/plugin-chart-handlebars",
"@superset-ui/plugin-chart-pivot-table": "file:./plugins/plugin-chart-pivot-table",
"@superset-ui/plugin-chart-point-cluster-map": "file:./plugins/plugin-chart-point-cluster-map",
"@superset-ui/plugin-chart-table": "file:./plugins/plugin-chart-table",
"@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud",
"@superset-ui/preset-chart-deckgl": "file:./plugins/preset-chart-deckgl",
"@superset-ui/switchboard": "file:./packages/superset-ui-switchboard",
"@types/d3-format": "^3.0.1",
"@types/d3-selection": "^3.0.11",
@@ -201,13 +201,13 @@
"pretty-ms": "^9.3.0",
"query-string": "9.3.1",
"re-resizable": "^6.11.2",
"react": "^18.3.0",
"react": "^18.2.0",
"react-arborist": "^3.5.0",
"react-checkbox-tree": "^1.8.0",
"react-diff-viewer-continued": "^4.2.2",
"react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3",
"react-dom": "^18.3.0",
"react-dom": "^18.2.0",
"react-google-recaptcha": "^3.1.0",
"react-intersection-observer": "^10.0.3",
"react-json-tree": "^0.20.0",
@@ -290,8 +290,8 @@
"@types/json-bigint": "^1.0.4",
"@types/mousetrap": "^1.6.15",
"@types/node": "^25.6.0",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/react-loadable": "^5.5.11",
"@types/react-redux": "^7.1.10",
"@types/react-resizable": "^3.0.8",
@@ -355,7 +355,6 @@
"prettier": "3.8.3",
"prettier-plugin-packagejson": "^3.0.2",
"process": "^0.11.10",
"react-dnd-test-backend": "^11.1.3",
"react-refresh": "^0.18.0",
"react-resizable": "^3.1.3",
"redux-mock-store": "^1.5.4",
@@ -368,7 +367,7 @@
"terser-webpack-plugin": "^5.6.0",
"ts-jest": "^29.4.9",
"tscw-config": "^1.1.2",
"tsx": "^4.22.0",
"tsx": "^4.21.0",
"typescript": "5.4.5",
"unzipper": "^0.12.3",
"vm-browserify": "^1.1.2",
@@ -376,7 +375,7 @@
"webpack": "^5.106.2",
"webpack-bundle-analyzer": "^5.3.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.4",
"webpack-dev-server": "^5.2.3",
"webpack-manifest-plugin": "^5.0.1",
"webpack-sources": "^3.4.1",
"webpack-visualizer-plugin2": "^2.0.0"

View File

@@ -97,8 +97,8 @@
"@fontsource/ibm-plex-mono": "^5.2.7",
"@fontsource/inter": "^5.2.6",
"nanoid": "^5.0.9",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-loadable": "^5.5.0",
"tinycolor2": "*",
"lodash": "^4.18.1",

View File

@@ -50,24 +50,20 @@ test('should pipe to `console` methods', () => {
});
test('should use noop functions when console unavailable', () => {
const originalConsole = window.console;
Object.assign(window, { console: undefined });
try {
const { logging } = require('@apache-superset/core/utils');
const { logging } = require('@apache-superset/core/utils');
expect(() => {
logging.debug();
logging.log();
logging.info();
logging.warn('warn');
logging.error('error');
logging.trace();
logging.table([
[1, 2],
[3, 4],
]);
}).not.toThrow();
} finally {
Object.assign(window, { console: originalConsole });
}
expect(() => {
logging.debug();
logging.log();
logging.info();
logging.warn('warn');
logging.error('error');
logging.trace();
logging.table([
[1, 2],
[3, 4],
]);
}).not.toThrow();
Object.assign(window, { console });
});

View File

@@ -40,9 +40,9 @@
"ace-builds": "^1.4.14",
"brace": "^0.11.1",
"memoize-one": "^5.1.1",
"react": "^18.3.0",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "^18.3.0"
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -100,8 +100,8 @@
"@types/tinycolor2": "*",
"antd": "^5.26.0",
"nanoid": "^5.0.9",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-loadable": "^5.5.0",
"tinycolor2": "*"
},

View File

@@ -17,16 +17,15 @@
* under the License.
*/
import { forwardRef } from 'react';
import { Avatar as AntdAvatar } from 'antd';
import type { AvatarProps, GroupProps as AvatarGroupProps } from './types';
export const Avatar = forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => (
<AntdAvatar ref={ref} {...props} />
));
export function Avatar(props: AvatarProps) {
return <AntdAvatar {...props} />;
}
export const AvatarGroup = (props: AvatarGroupProps) => (
<AntdAvatar.Group {...props} />
);
export function AvatarGroup(props: AvatarGroupProps) {
return <AntdAvatar.Group {...props} />;
}
export type { AvatarProps, AvatarGroupProps };

View File

@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { Children, ReactElement, Fragment, forwardRef, Ref } from 'react';
import { Children, ReactElement, Fragment } from 'react';
import cx from 'classnames';
import { Button as AntdButton } from 'antd';
import { useTheme } from '@apache-superset/core/theme';
@@ -100,7 +100,7 @@ const BUTTON_STYLE_MAP: Record<
link: { type: 'link' },
};
function ButtonInner(props: ButtonProps, ref: Ref<HTMLElement>) {
export function Button(props: ButtonProps) {
const {
tooltip,
placement,
@@ -160,7 +160,6 @@ function ButtonInner(props: ButtonProps, ref: Ref<HTMLElement>) {
const button = (
<AntdButton
ref={ref as Ref<HTMLButtonElement & HTMLAnchorElement>}
href={disabled ? undefined : href}
disabled={disabled}
type={antdType}
@@ -236,6 +235,4 @@ function ButtonInner(props: ButtonProps, ref: Ref<HTMLElement>) {
return button;
}
export const Button = forwardRef<HTMLElement, ButtonProps>(ButtonInner);
export type { ButtonProps, OnClickHandler };

View File

@@ -75,10 +75,7 @@ export const DropdownButton = ({
id={`${kebabCase(tooltip)}-tooltip`}
title={tooltip}
>
{/* antd Dropdown.Button is a plain function component without
forwardRef; wrap in a span so the Tooltip can attach a ref to a
real DOM node and skip the findDOMNode fallback. */}
<span>{button}</span>
{button}
</Tooltip>
);
}

View File

@@ -240,10 +240,7 @@ export function EditableTitle({
t("You don't have the rights to alter this title.")
}
>
{/* Wrap in span so the Tooltip can attach a ref to a DOM element.
antd's Input.TextArea forwards a non-DOM imperative handle, which
triggers a React 18 findDOMNode deprecation warning. */}
<span>{titleComponent}</span>
{titleComponent}
</Tooltip>
);
}

View File

@@ -16,54 +16,47 @@
* specific language governing permissions and limitations
* under the License.
*/
import { forwardRef } from 'react';
import { Tooltip } from '../Tooltip';
import { Button } from '../Button';
import type { IconTooltipProps } from './types';
export const IconTooltip = forwardRef<HTMLElement, IconTooltipProps>(
(
{
children = null,
className = '',
onClick = () => undefined,
placement = 'top',
style = {},
tooltip = null,
mouseEnterDelay = 0.3,
mouseLeaveDelay = 0.15,
},
ref,
) => {
const iconTooltip = (
<Button
ref={ref}
onClick={onClick}
style={{
padding: 0,
...style,
}}
buttonStyle="link"
className={`IconTooltip ${className}`}
export const IconTooltip = ({
children = null,
className = '',
onClick = () => undefined,
placement = 'top',
style = {},
tooltip = null,
mouseEnterDelay = 0.3,
mouseLeaveDelay = 0.15,
}: IconTooltipProps) => {
const iconTooltip = (
<Button
onClick={onClick}
style={{
padding: 0,
...style,
}}
buttonStyle="link"
className={`IconTooltip ${className}`}
>
{children}
</Button>
);
if (tooltip) {
return (
<Tooltip
id="tooltip"
title={tooltip}
placement={placement}
mouseEnterDelay={mouseEnterDelay}
mouseLeaveDelay={mouseLeaveDelay}
>
{children}
</Button>
{iconTooltip}
</Tooltip>
);
if (tooltip) {
return (
<Tooltip
id="tooltip"
title={tooltip}
placement={placement}
mouseEnterDelay={mouseEnterDelay}
mouseLeaveDelay={mouseLeaveDelay}
>
{iconTooltip}
</Tooltip>
);
}
return iconTooltip;
},
);
}
return iconTooltip;
};
export type { IconTooltipProps };

View File

@@ -165,7 +165,7 @@ import {
SlackOutlined,
ApiOutlined,
} from '@ant-design/icons';
import { ForwardRefExoticComponent, RefAttributes, forwardRef } from 'react';
import { FC } from 'react';
import { IconType } from './types';
import { BaseIconComponent } from './BaseIcon';
@@ -323,25 +323,19 @@ type AntdIconNames = keyof typeof AntdIcons;
export const antdEnhancedIcons: Record<
AntdIconNames,
ForwardRefExoticComponent<IconType & RefAttributes<HTMLSpanElement>>
FC<IconType>
> = Object.keys(AntdIcons)
.filter(key => !EXCLUDED_ICONS.some(excluded => key.includes(excluded)))
.reduce(
(acc, key) => {
acc[key as AntdIconNames] = forwardRef<HTMLSpanElement, IconType>(
(props, ref) => (
<BaseIconComponent
ref={ref}
component={AntdIcons[key as AntdIconNames]}
fileName={key}
{...props}
/>
),
acc[key as AntdIconNames] = (props: IconType) => (
<BaseIconComponent
component={AntdIcons[key as AntdIconNames]}
fileName={key}
{...props}
/>
);
return acc;
},
{} as Record<
AntdIconNames,
ForwardRefExoticComponent<IconType & RefAttributes<HTMLSpanElement>>
>,
{} as Record<AntdIconNames, FC<IconType>>,
);

View File

@@ -17,12 +17,12 @@
* under the License.
*/
import { FC, SVGProps, forwardRef, useEffect, useRef, useState } from 'react';
import { FC, SVGProps, useEffect, useRef, useState } from 'react';
import TransparentIcon from './svgs/transparent.svg';
import { IconType } from './types';
import { BaseIconComponent } from './BaseIcon';
const AsyncIcon = forwardRef<HTMLSpanElement, IconType>((props, ref) => {
const AsyncIcon = (props: IconType) => {
const [, setLoaded] = useState(false);
const ImportedSVG = useRef<FC<SVGProps<SVGSVGElement>>>();
const { fileName, customIcons, iconSize, iconColor, viewBox, ...restProps } =
@@ -46,7 +46,6 @@ const AsyncIcon = forwardRef<HTMLSpanElement, IconType>((props, ref) => {
return (
<BaseIconComponent
ref={ref}
component={ImportedSVG.current || TransparentIcon}
fileName={fileName}
customIcons={customIcons}
@@ -56,6 +55,6 @@ const AsyncIcon = forwardRef<HTMLSpanElement, IconType>((props, ref) => {
{...restProps}
/>
);
});
};
export default AsyncIcon;

View File

@@ -17,7 +17,6 @@
* under the License.
*/
import { forwardRef, type ComponentType } from 'react';
import { css, useTheme, getFontSize } from '@apache-superset/core/theme';
import { AntdIconType, BaseIconProps, CustomIconType, IconType } from './types';
@@ -36,78 +35,65 @@ const genAriaLabel = (fileName: string) => {
return name.toLowerCase();
};
export const BaseIconComponent = forwardRef<
HTMLSpanElement | SVGSVGElement,
export const BaseIconComponent: React.FC<
BaseIconProps & Omit<IconType, 'component'>
>(
(
{
component: Component,
iconColor,
iconSize,
viewBox,
customIcons,
fileName,
...rest
},
ref,
) => {
const theme = useTheme();
const whatRole = rest?.onClick ? 'button' : 'img';
const ariaLabel = genAriaLabel(fileName || '');
const style = {
color: iconColor,
fontSize: iconSize
? `${getFontSize(theme, iconSize)}px`
: `${theme.fontSize}px`,
cursor: rest?.onClick ? 'pointer' : undefined,
};
> = ({
component: Component,
iconColor,
iconSize,
viewBox,
customIcons,
fileName,
...rest
}) => {
const theme = useTheme();
const whatRole = rest?.onClick ? 'button' : 'img';
const ariaLabel = genAriaLabel(fileName || '');
const style = {
color: iconColor,
fontSize: iconSize
? `${getFontSize(theme, iconSize)}px`
: `${theme.fontSize}px`,
cursor: rest?.onClick ? 'pointer' : undefined,
};
const AntdComponent = Component as ComponentType<
Record<string, unknown> & {
ref?: React.Ref<HTMLSpanElement | SVGSVGElement>;
}
>;
return customIcons ? (
<span
ref={ref as React.Ref<HTMLSpanElement>}
role={whatRole}
aria-label={ariaLabel}
data-test={ariaLabel}
css={[
css`
display: inline-flex;
align-items: center;
line-height: 0;
vertical-align: middle;
`,
]}
>
<Component
viewBox={viewBox || '0 0 24 24'}
style={style}
width={
iconSize
? `${getFontSize(theme, iconSize) || theme.fontSize}px`
: `${theme.fontSize}px`
}
height={
iconSize
? `${getFontSize(theme, iconSize) || theme.fontSize}px`
: `${theme.fontSize}px`
}
{...(rest as CustomIconType)}
/>
</span>
) : (
<AntdComponent
ref={ref}
role={whatRole}
return customIcons ? (
<span
role={whatRole}
aria-label={ariaLabel}
data-test={ariaLabel}
css={[
css`
display: inline-flex;
align-items: center;
line-height: 0;
vertical-align: middle;
`,
]}
>
<Component
viewBox={viewBox || '0 0 24 24'}
style={style}
aria-label={ariaLabel}
data-test={ariaLabel}
{...(rest as AntdIconType)}
width={
iconSize
? `${getFontSize(theme, iconSize) || theme.fontSize}px`
: `${theme.fontSize}px`
}
height={
iconSize
? `${getFontSize(theme, iconSize) || theme.fontSize}px`
: `${theme.fontSize}px`
}
{...(rest as CustomIconType)}
/>
);
},
);
</span>
) : (
<Component
role={whatRole}
style={style}
aria-label={ariaLabel}
data-test={ariaLabel}
{...(rest as AntdIconType)}
/>
);
};

View File

@@ -17,16 +17,12 @@
* under the License.
*/
import { ForwardRefExoticComponent, RefAttributes, forwardRef } from 'react';
import { FC } from 'react';
import { antdEnhancedIcons } from './AntdEnhanced';
import AsyncIcon from './AsyncIcon';
import type { IconType } from './types';
type IconComponent = ForwardRefExoticComponent<
IconType & RefAttributes<HTMLSpanElement>
>;
/**
* Filename is going to be inferred from the icon name.
* i.e. BigNumberChartTile => assets/images/icons/big_number_chart_tile
@@ -62,17 +58,15 @@ const customIcons = [
'Undo',
] as const;
type CustomIconType = Record<(typeof customIcons)[number], IconComponent>;
type CustomIconType = Record<(typeof customIcons)[number], FC<IconType>>;
const iconOverrides: CustomIconType = {} as CustomIconType;
customIcons.forEach(customIcon => {
const fileName = customIcon
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
.toLowerCase();
iconOverrides[customIcon] = forwardRef<HTMLSpanElement, IconType>(
(props, ref) => (
<AsyncIcon ref={ref} customIcons fileName={fileName} {...props} />
),
iconOverrides[customIcon] = (props: IconType) => (
<AsyncIcon customIcons fileName={fileName} {...props} />
);
});
@@ -80,7 +74,7 @@ export type IconNameType =
| keyof typeof antdEnhancedIcons
| keyof typeof iconOverrides;
type IconComponentType = Record<IconNameType, IconComponent>;
type IconComponentType = Record<IconNameType, FC<IconType>>;
export const Icons: IconComponentType = {
...antdEnhancedIcons,

View File

@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
import { forwardRef } from 'react';
import { Tag } from '@superset-ui/core/components/Tag';
import { css } from '@emotion/react';
import { useTheme, getColorVariants } from '@apache-superset/core/theme';
@@ -24,7 +23,7 @@ import { DatasetTypeLabel } from './reusable/DatasetTypeLabel';
import { PublishedLabel } from './reusable/PublishedLabel';
import type { LabelProps } from './types';
export const Label = forwardRef<HTMLSpanElement, LabelProps>((props, ref) => {
export function Label(props: LabelProps) {
const theme = useTheme();
// Use Ant Design's motion duration instead of deprecated transitionTiming
const {
@@ -72,7 +71,6 @@ export const Label = forwardRef<HTMLSpanElement, LabelProps>((props, ref) => {
return (
<Tag
ref={ref}
onClick={onClick}
role={onClick ? 'button' : undefined}
style={style}
@@ -83,6 +81,6 @@ export const Label = forwardRef<HTMLSpanElement, LabelProps>((props, ref) => {
{children}
</Tag>
);
});
}
export { DatasetTypeLabel, PublishedLabel };
export type { LabelType } from './types';

View File

@@ -357,9 +357,6 @@ const CustomModal = ({
disabled={!draggable || dragDisabled}
bounds={bounds}
onStart={(event, uiData) => onDragStart(event, uiData)}
// Pass nodeRef so react-draggable does not fall back to
// ReactDOM.findDOMNode (deprecated in React 18+ Strict Mode).
nodeRef={draggableRef}
{...draggableConfig}
>
{resizable ? (

View File

@@ -16,15 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
import { forwardRef } from 'react';
import { Popover as AntdPopover } from 'antd';
import { PopoverProps as AntdPopoverProps } from 'antd/es/popover';
import type { TooltipRef } from 'antd/es/tooltip';
export interface PopoverProps extends AntdPopoverProps {
forceRender?: boolean;
}
export const Popover = forwardRef<TooltipRef, PopoverProps>((props, ref) => (
<AntdPopover ref={ref} {...props} />
));
export const Popover = (props: PopoverProps) => <AntdPopover {...props} />;

View File

@@ -16,9 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
import { MouseEventHandler } from 'react';
import { MouseEventHandler, forwardRef } from 'react';
import { SupersetTheme } from '@apache-superset/core/theme';
import { Icons } from '@superset-ui/core/components/Icons';
import type { IconType } from '@superset-ui/core/components/Icons/types';
import { Tooltip } from '../Tooltip';
export interface RefreshLabelProps {
@@ -31,19 +32,25 @@ const RefreshLabel = ({
onClick,
tooltipContent,
disabled,
}: RefreshLabelProps) => (
<Tooltip title={tooltipContent}>
<Icons.SyncOutlined
iconSize="l"
role="button"
onClick={disabled ? undefined : onClick}
css={(theme: SupersetTheme) => ({
cursor: 'pointer',
color: theme.colorIcon,
'&:hover': { color: theme.colorPrimary },
})}
/>
</Tooltip>
);
}: RefreshLabelProps) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const IconWithoutRef = forwardRef((props: IconType, ref: any) => (
<Icons.SyncOutlined iconSize="l" {...props} />
));
return (
<Tooltip title={tooltipContent}>
<IconWithoutRef
role="button"
onClick={disabled ? undefined : onClick}
css={(theme: SupersetTheme) => ({
cursor: 'pointer',
color: theme.colorIcon,
'&:hover': { color: theme.colorPrimary },
})}
/>
</Tooltip>
);
};
export default RefreshLabel;

View File

@@ -16,22 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
import { forwardRef } from 'react';
import { Tooltip as AntdTooltip } from 'antd';
import type { TooltipRef } from 'antd/es/tooltip';
import type { TooltipProps, TooltipPlacement } from './types';
export const Tooltip = forwardRef<TooltipRef, TooltipProps>(
({ overlayStyle, ...props }, ref) => (
<AntdTooltip
ref={ref}
styles={{
body: { overflow: 'hidden', textOverflow: 'ellipsis' },
root: overlayStyle ?? {},
}}
{...props}
/>
),
export const Tooltip = ({ overlayStyle, ...props }: TooltipProps) => (
<AntdTooltip
styles={{
body: { overflow: 'hidden', textOverflow: 'ellipsis' },
root: overlayStyle ?? {},
}}
{...props}
/>
);
export type { TooltipProps, TooltipPlacement };

View File

@@ -33,7 +33,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -34,6 +34,6 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
}

View File

@@ -31,7 +31,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -31,7 +31,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -36,6 +36,6 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
}

View File

@@ -33,8 +33,8 @@
"@apache-superset/core": "*",
"@testing-library/jest-dom": "*",
"@testing-library/react": "^14.0.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -32,7 +32,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -39,6 +39,6 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^18.3.0"
"react": "^18.2.0"
}
}

View File

@@ -43,6 +43,6 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"dayjs": "^1.11.19",
"react": "^18.3.0"
"react": "^18.2.0"
}
}

View File

@@ -44,8 +44,8 @@
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "*",
"@types/react": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -47,7 +47,7 @@
"geostyler-wfs-parser": "^3.0.1",
"ol": "^10.8.0",
"polished": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}

View File

@@ -38,7 +38,7 @@
"dayjs": "^1.11.19",
"echarts": "*",
"memoize-one": "*",
"react": "^18.3.0"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -39,9 +39,9 @@
"handlebars": "^4.7.8",
"lodash": "^4.18.1",
"dayjs": "^1.11.19",
"react": "^18.3.0",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "^18.3.0"
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/jest": "^30.0.0",

View File

@@ -33,8 +33,8 @@
"@superset-ui/core": "*",
"lodash": "^4.18.1",
"prop-types": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/types": "^7.29.0",

View File

@@ -36,8 +36,8 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -45,8 +45,8 @@
"@testing-library/user-event": "*",
"@types/react": "*",
"match-sorter": "^8.2.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -39,7 +39,7 @@
"@superset-ui/core": "*",
"@types/lodash": "*",
"@types/react": "*",
"react": "^18.3.0"
"react": "^18.2.0"
},
"devDependencies": {
"@types/d3-cloud": "^1.2.9"

View File

@@ -67,8 +67,8 @@
"@superset-ui/core": "*",
"dayjs": "^1.11.19",
"mapbox-gl": ">=1.0.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"peerDependenciesMeta": {
"mapbox-gl": {

View File

@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { AriaAttributes, Ref } from 'react';
import { AriaAttributes } from 'react';
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import jQuery from 'jquery';
@@ -98,39 +98,31 @@ jest.mock('rehype-raw', () => () => jest.fn());
// Tests should override this when needed
jest.mock('@superset-ui/core/components/Icons/AsyncIcon', () => ({
__esModule: true,
// eslint-disable-next-line global-require
default: require('react').forwardRef(
(
{
fileName,
role,
'aria-label': ariaLabel,
onClick,
...rest
}: {
fileName: string;
role?: string;
'aria-label'?: AriaAttributes['aria-label'];
onClick?: () => void;
},
ref: Ref<HTMLSpanElement>,
) => {
// Simple mock that provides the essential attributes for testing
const label =
ariaLabel || fileName?.replace(/_/g, '-').toLowerCase() || '';
return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<span
ref={ref}
role={role || (onClick ? 'button' : 'img')}
aria-label={label}
data-test={label}
onClick={onClick}
{...rest}
/>
);
},
),
default: ({
fileName,
role,
'aria-label': ariaLabel,
onClick,
...rest
}: {
fileName: string;
role?: string;
'aria-label'?: AriaAttributes['aria-label'];
onClick?: () => void;
}) => {
// Simple mock that provides the essential attributes for testing
const label = ariaLabel || fileName?.replace(/_/g, '-').toLowerCase() || '';
return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<span
role={role || (onClick ? 'button' : 'img')}
aria-label={label}
data-test={label}
onClick={onClick}
{...rest}
/>
);
},
StyledIcon: ({
component: Component,
role,

View File

@@ -37,7 +37,6 @@ import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { TestBackend } from 'react-dnd-test-backend';
import reducerIndex from 'spec/helpers/reducerIndex';
import { QueryParamProvider } from 'use-query-params';
import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
@@ -47,11 +46,7 @@ import userEvent from '@testing-library/user-event';
type Options = Omit<RenderOptions, 'queries'> & {
useRedux?: boolean;
// `true` -> HTML5Backend (default; matches browser).
// `'test'` -> TestBackend, drive drags programmatically via
// `react-dnd-test-backend` `getInstance()` — avoids the jsdom
// HTML5-drag-event / preventDefault / zero-rect gaps.
useDnd?: boolean | 'test';
useDnd?: boolean;
useQueryParams?: boolean;
useRouter?: boolean;
useTheme?: boolean;
@@ -102,9 +97,8 @@ export function createWrapper(options?: Options) {
}
if (useDnd) {
const backend = useDnd === 'test' ? TestBackend : HTML5Backend;
// @ts-expect-error react-dnd types not updated for React 18
result = <DndProvider backend={backend}>{result}</DndProvider>;
result = <DndProvider backend={HTML5Backend}>{result}</DndProvider>;
}
if (useRedux || store) {

View File

@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { act } from 'react';
import { act } from 'react-dom/test-utils';
import { QueryState } from '@superset-ui/core';
import fetchMock from 'fetch-mock';
import configureStore from 'redux-mock-store';

View File

@@ -189,19 +189,15 @@ const SqlEditorLeftBar = ({ queryEditorId }: SqlEditorLeftBarProps) => {
placement="bottomLeft"
trigger="click"
>
{/* Wrap in a span so the Popover can attach a ref without relying
on findDOMNode (deprecated in React 18+). */}
<span>
<DatabaseSelector
key={`db-selector-${db ? db.id : 'no-db'}:${catalog ?? 'no-catalog'}:${
schema ?? 'no-schema'
}`}
{...dbSelectorProps}
emptyState={<EmptyState />}
sqlLabMode
onOpenModal={openSelectorModal}
/>
</span>
<DatabaseSelector
key={`db-selector-${db ? db.id : 'no-db'}:${catalog ?? 'no-catalog'}:${
schema ?? 'no-schema'
}`}
{...dbSelectorProps}
emptyState={<EmptyState />}
sqlLabMode
onOpenModal={openSelectorModal}
/>
</Popover>
<StyledDivider />
<TableExploreTree queryEditorId={activeQEId} />

View File

@@ -98,10 +98,7 @@ class CopyToClip extends Component<CopyToClipboardProps> {
trigger={['hover']}
arrow={{ pointAtCenter: true }}
>
{/* Wrap in a span so antd Tooltip has a real DOM ref target;
avoids findDOMNode fallback when copyNode is a function
component without forwardRef. */}
<span>{this.getDecoratedCopyNode()}</span>
{this.getDecoratedCopyNode()}
</Tooltip>
) : (
this.getDecoratedCopyNode()

View File

@@ -17,20 +17,21 @@
* under the License.
*/
import { forwardRef, PropsWithoutRef, Ref, RefAttributes } from 'react';
import { PropsWithoutRef, RefAttributes } from 'react';
import { Link, LinkProps } from 'react-router-dom';
import { isUrlExternal, parseUrl } from 'src/utils/urlUtils';
type GenericLinkProps<S> = PropsWithoutRef<LinkProps<S>> &
RefAttributes<HTMLAnchorElement>;
const GenericLinkInner = <S,>(
{ to, component, replace, innerRef, children, ...rest }: GenericLinkProps<S>,
ref: Ref<HTMLAnchorElement>,
) => {
export const GenericLink = <S,>({
to,
component,
replace,
innerRef,
children,
...rest
}: PropsWithoutRef<LinkProps<S>> & RefAttributes<HTMLAnchorElement>) => {
if (typeof to === 'string' && isUrlExternal(to)) {
return (
<a ref={ref} data-test="external-link" href={parseUrl(to)} {...rest}>
<a data-test="external-link" href={parseUrl(to)} {...rest}>
{children}
</a>
);
@@ -41,14 +42,10 @@ const GenericLinkInner = <S,>(
to={to}
component={component}
replace={replace}
innerRef={innerRef ?? ref}
innerRef={innerRef}
{...rest}
>
{children}
</Link>
);
};
export const GenericLink = forwardRef(GenericLinkInner) as <S>(
props: GenericLinkProps<S> & { ref?: Ref<HTMLAnchorElement> },
) => ReturnType<typeof GenericLinkInner>;

View File

@@ -193,57 +193,52 @@ export default function getControlItemsMap({
t('Populate "Default value" to enable this control')
}
>
{/* Wrap in span so antd Tooltip can attach a ref without
relying on findDOMNode (deprecated in React 18+). */}
<span>
<StyledRowFormItem
expanded={expanded}
key={controlItem.name}
name={['filters', filterId, 'controlValues', controlItem.name]}
initialValue={initialValue}
valuePropName="checked"
colon={false}
<StyledRowFormItem
expanded={expanded}
key={controlItem.name}
name={['filters', filterId, 'controlValues', controlItem.name]}
initialValue={initialValue}
valuePropName="checked"
colon={false}
>
<Checkbox
disabled={controlItem.config.affectsDataMask && disabled}
onChange={checked => {
if (controlItem.config.requiredFirst) {
setNativeFilterFieldValues(form, filterId, {
requiredFirst: {
...formFilter?.requiredFirst,
[controlItem.name]: checked,
},
});
}
if (controlItem.config.resetConfig) {
setNativeFilterFieldValues(form, filterId, {
defaultDataMask: null,
});
}
formChanged();
forceUpdate();
}}
>
<Checkbox
disabled={controlItem.config.affectsDataMask && disabled}
onChange={checked => {
if (controlItem.config.requiredFirst) {
setNativeFilterFieldValues(form, filterId, {
requiredFirst: {
...formFilter?.requiredFirst,
[controlItem.name]: checked,
},
});
}
if (controlItem.config.resetConfig) {
setNativeFilterFieldValues(form, filterId, {
defaultDataMask: null,
});
}
formChanged();
forceUpdate();
}}
>
<>
{typeof controlItem.config.label === 'function'
? (controlItem.config.label as Function)()
: controlItem.config.label}
&nbsp;
{controlItem.config.description && (
<InfoTooltip
placement="top"
tooltip={
typeof controlItem.config.description === 'function'
? (controlItem.config.description as Function)()
: (controlItem.config
.description as React.ReactNode)
}
/>
)}
</>
</Checkbox>
</StyledRowFormItem>
</span>
<>
{typeof controlItem.config.label === 'function'
? (controlItem.config.label as Function)()
: controlItem.config.label}
&nbsp;
{controlItem.config.description && (
<InfoTooltip
placement="top"
tooltip={
typeof controlItem.config.description === 'function'
? (controlItem.config.description as Function)()
: (controlItem.config.description as React.ReactNode)
}
/>
)}
</>
</Checkbox>
</StyledRowFormItem>
</Tooltip>
</>
);

View File

@@ -188,9 +188,7 @@ function CollectionControl({
// Two items can collide when keyAccessor returns falsy and the index
// fallback is used — breaking dnd-kit reordering and React reconciliation.
// Assign a stable nanoid per item ref when no key is available.
const generatedIdsRef = useRef<WeakMap<CollectionItem, string>>(
new WeakMap(),
);
const generatedIdsRef = useRef<WeakMap<CollectionItem, string>>(new WeakMap());
const itemIds = useMemo(
() =>
value.map(item => {

View File

@@ -54,9 +54,7 @@ const ColorBreakpointsPopoverTrigger = ({
onOpenChange={setVisibility}
destroyOnHidden
>
{/* Wrap in span so the Popover can attach a ref without relying
on findDOMNode (deprecated in React 18+). */}
<span>{props.children}</span>
{props.children}
</ControlPopover>
);
};

View File

@@ -52,9 +52,7 @@ const ContourPopoverTrigger = ({
onOpenChange={setVisibility}
destroyOnHidden
>
{/* Wrap in span so the Popover can attach a ref without relying
on findDOMNode (deprecated in React 18+). */}
<span>{props.children}</span>
{props.children}
</ControlPopover>
);
};

View File

@@ -369,21 +369,16 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
overlayClassName="time-range-popover"
>
<Tooltip placement="top" title={tooltipTitle}>
{/* Wrap in a span so the Popover gets a stable DOM ref target;
DateLabel forwards its ref to an inner span used for measuring
text truncation, which would otherwise become the popover's
positioning anchor in React 18. */}
<span data-test={DateFilterTestKey.PopoverOverlay}>
<DateLabel
name={name}
aria-labelledby={`filter-name-${props.name}`}
aria-describedby={`date-label-${props.name}`}
label={actualTimeRange}
isActive={show}
isPlaceholder={actualTimeRange === NO_TIME_RANGE}
ref={labelRef}
/>
</span>
<DateLabel
name={name}
aria-labelledby={`filter-name-${props.name}`}
aria-describedby={`date-label-${props.name}`}
label={actualTimeRange}
isActive={show}
isPlaceholder={actualTimeRange === NO_TIME_RANGE}
data-test={DateFilterTestKey.PopoverOverlay}
ref={labelRef}
/>
</Tooltip>
</ControlPopover>
);

View File

@@ -201,9 +201,7 @@ const ColumnSelectPopoverTriggerInner = ({
title={popoverTitle}
destroyOnHidden
>
{/* Wrap in span so the Popover can attach a ref without relying
on findDOMNode (deprecated in React 18+). */}
<span>{children}</span>
{children}
</ControlPopover>
</>
);

View File

@@ -16,8 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
import { act } from 'react';
import { getInstance as getTestBackend } from 'react-dnd-test-backend';
import {
fireEvent,
render,
@@ -213,9 +211,7 @@ test('can drop only selected metrics', () => {
test('can drag and reorder items', async () => {
const values = ['column_a', 'metric_a', 'column_b'];
render(<DndColumnMetricSelect {...defaultProps} value={values} multi />, {
// TestBackend bypasses the HTML5 drag-event pipeline (which jsdom
// doesn't fully implement) and lets us drive drags via simulate* calls.
useDnd: 'test',
useDnd: true,
useRedux: true,
});
@@ -228,24 +224,10 @@ test('can drag and reorder items', async () => {
expect(within(firstItem).getByText('column_a')).toBeVisible();
expect(within(lastItem).getByText('Column B')).toBeVisible();
const sourceId = firstItem
.querySelector('[data-drag-source-id]')!
.getAttribute('data-drag-source-id')!;
const targetId = lastItem
.querySelector('[data-drop-target-id]')!
.getAttribute('data-drop-target-id')!;
const backend = getTestBackend()!;
act(() => {
backend.simulateBeginDrag([sourceId]);
// Pass a clientOffset past the hover midpoint so OptionWrapper.hover /
// OptionControls.hover fire the reorder instead of bailing on the
// jsdom zero-rect.
backend.simulateHover([targetId], {
clientOffset: { x: 0, y: 100 },
} as any);
backend.simulateDrop();
backend.simulateEndDrag();
});
fireEvent.dragStart(firstItem);
fireEvent.dragEnter(lastItem);
fireEvent.dragOver(lastItem);
fireEvent.drop(lastItem);
expect(container).toBeInTheDocument();
});

View File

@@ -16,8 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
import { act } from 'react';
import { getInstance as getTestBackend } from 'react-dnd-test-backend';
import {
fireEvent,
render,
@@ -316,9 +314,7 @@ test('update adhoc metric name when column label in dataset changes', () => {
test('can drag metrics', async () => {
const metricValues = ['metric_a', 'metric_b', adhocMetricB];
render(<DndMetricSelect {...defaultProps} value={metricValues} multi />, {
// TestBackend bypasses the HTML5 drag-event pipeline (which jsdom
// doesn't fully implement) and lets us drive drags via simulate* calls.
useDnd: 'test',
useDnd: true,
useRedux: true,
});
@@ -336,23 +332,10 @@ test('can drag metrics', async () => {
fireEvent.mouseOver(within(firstMetric).getByText('metric_a'));
expect(await screen.findByText('Metric name')).toBeInTheDocument();
const sourceId = firstMetric
.querySelector('[data-drag-source-id]')!
.getAttribute('data-drag-source-id')!;
const targetId = lastMetric
.querySelector('[data-drop-target-id]')!
.getAttribute('data-drop-target-id')!;
const backend = getTestBackend()!;
act(() => {
backend.simulateBeginDrag([sourceId]);
// Pass a clientOffset past the hover midpoint so OptionControls.hover
// fires onMoveLabel instead of bailing on the jsdom zero-rect.
backend.simulateHover([targetId], {
clientOffset: { x: 0, y: 100 },
} as any);
backend.simulateDrop();
backend.simulateEndDrag();
});
fireEvent.dragStart(firstMetric);
fireEvent.dragEnter(lastMetric);
fireEvent.dragOver(lastMetric);
fireEvent.drop(lastMetric);
expect(within(firstMetric).getByText('SUM(Column B)')).toBeVisible();
expect(within(lastMetric).getByText('metric_a')).toBeVisible();

View File

@@ -67,24 +67,18 @@ export default function OptionWrapper(
const ref = useRef<HTMLDivElement>(null);
const labelRef = useRef<HTMLDivElement>(null);
const [{ isDragging, dragSourceId }, drag] = useDrag({
const [{ isDragging }, drag] = useDrag({
item: {
type,
dragIndex: index,
},
collect: (monitor: DragSourceMonitor) => ({
isDragging: monitor.isDragging(),
// Exposed via `data-drag-source-id` so tests using react-dnd-test-backend
// can drive drags programmatically without DOM-event simulation.
dragSourceId: monitor.getHandlerId(),
}),
});
const [{ dropTargetId }, drop] = useDrop({
const [, drop] = useDrop({
accept: type,
collect: (monitor: DropTargetMonitor) => ({
dropTargetId: monitor.getHandlerId(),
}),
hover: (item: OptionItemInterface, monitor: DropTargetMonitor) => {
if (!ref.current) {
@@ -188,12 +182,7 @@ export default function OptionWrapper(
drag(drop(ref));
return (
<DragContainer
ref={ref}
data-drag-source-id={dragSourceId ?? undefined}
data-drop-target-id={dropTargetId ?? undefined}
{...rest}
>
<DragContainer ref={ref} {...rest}>
<Option
index={index}
clickClose={clickClose}

View File

@@ -112,9 +112,7 @@ class AdhocFilterPopoverTrigger extends PureComponent<
onOpenChange={togglePopover}
destroyOnHidden
>
{/* Wrap in span so the Popover can attach a ref without relying
on findDOMNode (deprecated in React 18+). */}
<span>{this.props.children}</span>
{this.props.children}
</ControlPopover>
);
}

View File

@@ -274,9 +274,7 @@ class AdhocMetricPopoverTrigger extends PureComponent<
title={popoverTitle}
destroyOnHidden
>
{/* Wrap in span so the Popover can attach a ref without relying
on findDOMNode (deprecated in React 18+). */}
<span>{this.props.children}</span>
{this.props.children}
</ControlPopover>
</>
);

View File

@@ -32,6 +32,13 @@ import MetricDefinitionValue from './MetricDefinitionValue';
import AdhocMetric from './AdhocMetric';
import AdhocMetricPopoverTrigger from './AdhocMetricPopoverTrigger';
const defaultProps = {
onChange: () => {},
clearable: true,
savedMetrics: [],
columns: [],
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getOptionsForSavedMetrics(
savedMetrics: any,
@@ -115,11 +122,11 @@ export interface MetricsControlProps {
}
const MetricsControl = ({
onChange = () => {},
onChange,
multi,
value: propsValue,
columns = [],
savedMetrics = [],
columns,
savedMetrics,
datasource,
...props
}: MetricsControlProps) => {
@@ -344,4 +351,6 @@ const MetricsControl = ({
);
};
MetricsControl.defaultProps = defaultProps;
export default MetricsControl;

View File

@@ -275,11 +275,8 @@ export const OptionControlLabel = ({
const ref = useRef<HTMLDivElement>(null);
const labelRef = useRef<HTMLDivElement>(null);
const hasMetricName = savedMetric?.metric_name;
const [{ dropTargetId }, drop] = useDrop({
const [, drop] = useDrop({
accept: type,
collect: (monitor: DropTargetMonitor) => ({
dropTargetId: monitor.getHandlerId(),
}),
drop() {
if (!multi) {
return;
@@ -331,7 +328,7 @@ export const OptionControlLabel = ({
item.dragIndex = hoverIndex;
},
});
const [{ isDragging, dragSourceId }, drag] = useDrag({
const [{ isDragging }, drag] = useDrag({
item: {
type,
dragIndex: index,
@@ -339,9 +336,6 @@ export const OptionControlLabel = ({
},
collect: monitor => ({
isDragging: monitor.isDragging(),
// Exposed via `data-drag-source-id` so tests using react-dnd-test-backend
// can drive drags programmatically without DOM-event simulation.
dragSourceId: monitor.getHandlerId(),
}),
});
@@ -430,13 +424,5 @@ export const OptionControlLabel = ({
);
drag(drop(ref));
return (
<DragContainer
ref={ref}
data-drag-source-id={dragSourceId ?? undefined}
data-drop-target-id={dropTargetId ?? undefined}
>
{getOptionControlContent()}
</DragContainer>
);
return <DragContainer ref={ref}>{getOptionControlContent()}</DragContainer>;
};

View File

@@ -24,7 +24,7 @@ import {
} from 'spec/helpers/testing-library';
import { VizType } from '@superset-ui/core';
import fetchMock from 'fetch-mock';
import { act } from 'react';
import { act } from 'react-dom/test-utils';
import handleResourceExport from 'src/utils/export';
import { LocalStorageKeys } from 'src/utils/localStorageHelpers';
import ChartTable from './ChartTable';

View File

@@ -111,15 +111,12 @@ const createController = (
...options,
});
// Shared console spies — re-installed in beforeEach so each test starts
// with a fresh call count and a clean implementation.
let consoleSpy: jest.SpyInstance;
let consoleErrorSpy: jest.SpyInstance;
// Shared console spies
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
beforeEach(() => {
jest.clearAllMocks();
consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
// Setup DOM environment
Object.defineProperty(window, 'localStorage', {

View File

@@ -883,14 +883,6 @@ class BigQueryEngineSpec(BaseEngineSpec): # pylint: disable=too-many-public-met
# We will return the original exception
return exception
@staticmethod
def _information_schema_ref(schema: str, catalog: str | None) -> str:
escaped_schema = schema.replace("`", "``")
if catalog:
escaped_catalog = catalog.replace("`", "``")
return f"`{escaped_catalog}.{escaped_schema}.INFORMATION_SCHEMA.TABLES`"
return f"`{escaped_schema}.INFORMATION_SCHEMA.TABLES`"
@classmethod
def get_materialized_view_names(
cls,
@@ -907,8 +899,14 @@ class BigQueryEngineSpec(BaseEngineSpec): # pylint: disable=too-many-public-met
if not schema:
return set()
catalog = database.get_default_catalog()
information_schema = cls._information_schema_ref(schema, catalog)
# Construct the query to get materialized views from INFORMATION_SCHEMA
if catalog := database.get_default_catalog():
information_schema = f"`{catalog}.{schema}.INFORMATION_SCHEMA.TABLES`"
else:
information_schema = f"`{schema}.INFORMATION_SCHEMA.TABLES`"
# Use string formatting for the table name since it's not user input
# The catalog and schema are from trusted sources (database configuration)
query = f"""
SELECT table_name
FROM {information_schema}
@@ -947,8 +945,15 @@ class BigQueryEngineSpec(BaseEngineSpec): # pylint: disable=too-many-public-met
if not schema:
return set()
# Construct the query to get regular views from INFORMATION_SCHEMA
catalog = database.get_default_catalog()
information_schema = cls._information_schema_ref(schema, catalog)
if catalog:
information_schema = f"`{catalog}.{schema}.INFORMATION_SCHEMA.TABLES`"
else:
information_schema = f"`{schema}.INFORMATION_SCHEMA.TABLES`"
# Use string formatting for the table name since it's not user input
# The catalog and schema are from trusted sources (database configuration)
query = f"""
SELECT table_name
FROM {information_schema}

View File

@@ -569,11 +569,11 @@ class DatabricksNativeEngineSpec(DatabricksDynamicBaseEngineSpec):
) -> list[str]:
prequeries = []
if catalog:
escaped_catalog = catalog.replace("`", "``")
prequeries.append(f"USE CATALOG `{escaped_catalog}`")
catalog = f"`{catalog}`" if not catalog.startswith("`") else catalog
prequeries.append(f"USE CATALOG {catalog}")
if schema:
escaped_schema = schema.replace("`", "``")
prequeries.append(f"USE SCHEMA `{escaped_schema}`")
schema = f"`{schema}`" if not schema.startswith("`") else schema
prequeries.append(f"USE SCHEMA {schema}")
return prequeries
@classmethod

View File

@@ -162,7 +162,4 @@ class Db2EngineSpec(BaseEngineSpec):
be anything, and we would have to block users from running any queries
referencing tables without an explicit schema.
"""
if not schema:
return []
escaped = schema.replace('"', '""')
return [f'set current_schema "{escaped}"']
return [f'set current_schema "{schema}"'] if schema else []

View File

@@ -268,8 +268,7 @@ class GSheetsEngineSpec(ShillelaghEngineSpec):
schema=table.schema,
) as conn:
cursor = conn.cursor()
escaped_table = table.table.replace('"', '""')
cursor.execute(f'SELECT GET_METADATA("{escaped_table}")')
cursor.execute(f'SELECT GET_METADATA("{table.table}")')
results = cursor.fetchone()[0]
try:
metadata = json.loads(results)

View File

@@ -206,24 +206,13 @@ class HiveEngineSpec(PrestoEngineSpec):
if to_sql_kwargs["if_exists"] == "fail":
# Ensure table doesn't already exist.
escaped_table = (
table.table.replace("\\", "\\\\")
.replace("'", "\\'")
.replace("%", "\\%")
.replace("_", "\\_")
)
# Hive LIKE uses backslash as the escape character. Python needs \\\\
# to produce the two-character SQL literal \\ (a single backslash).
escape_clause = " ESCAPE '\\\\'"
if table.schema:
escaped_schema = table.schema.replace("`", "``")
table_exists = not database.get_df(
f"SHOW TABLES IN `{escaped_schema}`"
f" LIKE '{escaped_table}'{escape_clause}"
f"SHOW TABLES IN {table.schema} LIKE '{table.table}'"
).empty
else:
table_exists = not database.get_df(
f"SHOW TABLES LIKE '{escaped_table}'{escape_clause}"
f"SHOW TABLES LIKE '{table.table}'"
).empty
if table_exists:
@@ -509,12 +498,9 @@ class HiveEngineSpec(PrestoEngineSpec):
order_by: list[tuple[str, bool]] | None = None,
filters: dict[Any, Any] | None = None,
) -> str:
escaped_table = table.table.replace("`", "``")
if table.schema:
escaped_schema = table.schema.replace("`", "``")
full_table_name = f"`{escaped_schema}`.`{escaped_table}`"
else:
full_table_name = f"`{escaped_table}`"
full_table_name = (
f"{table.schema}.{table.table}" if table.schema else table.table
)
return f"SHOW PARTITIONS {full_table_name}"
@classmethod
@@ -642,8 +628,7 @@ class HiveEngineSpec(PrestoEngineSpec):
sql = "SHOW VIEWS"
if schema:
escaped_schema = schema.replace("`", "``")
sql += f" IN `{escaped_schema}`"
sql += f" IN `{schema}`"
with database.get_raw_connection(schema=schema) as conn:
cursor = conn.cursor()

View File

@@ -454,7 +454,7 @@ def print_report(reports: list[MetadataReport], verbose: bool = False) -> None:
print("=" * 60)
all_fields = {**REQUIRED_FIELDS, **RECOMMENDED_FIELDS, **OPTIONAL_FIELDS}
field_counts: dict[str, int] = dict.fromkeys(all_fields, 0)
field_counts: dict[str, int] = {f: 0 for f in all_fields}
for r in reports:
for field in r.present_fields:

View File

@@ -694,10 +694,7 @@ class PostgresEngineSpec(BasicParametersMixin, PostgresBaseEngineSpec):
be anything, and we would have to block users from running any queries
referencing tables without an explicit schema.
"""
if not schema:
return []
escaped = schema.replace('"', '""')
return [f'set search_path = "{escaped}"']
return [f'set search_path = "{schema}"'] if schema else []
@classmethod
def get_allow_cost_estimate(cls, extra: dict[str, Any]) -> bool:

View File

@@ -413,7 +413,6 @@ class StarRocksEngineSpec(MySQLEngineSpec):
username = database.get_effective_user(database.url_object)
if username:
escaped = username.replace('"', '""')
return [f'EXECUTE AS "{escaped}" WITH NO REVERT;']
return [f'EXECUTE AS "{username}" WITH NO REVERT;']
return []

View File

@@ -59,7 +59,7 @@ ALLOWED_TAGS = {
"ul",
}.union(TABLE_TAGS)
ALLOWED_TABLE_ATTRIBUTES = dict.fromkeys(TABLE_TAGS, TABLE_ATTRIBUTES)
ALLOWED_TABLE_ATTRIBUTES = {tag: TABLE_ATTRIBUTES for tag in TABLE_TAGS}
ALLOWED_ATTRIBUTES = {
"a": {"href", "title"},
"abbr": {"title"},

View File

@@ -94,7 +94,7 @@ class SlackMixin:
# need to truncate the data
for i in range(len(df) - 1):
truncated_df = df[: i + 1].fillna("")
truncated_row = pd.Series(dict.fromkeys(df.columns, "..."))
truncated_row = pd.Series({k: "..." for k in df.columns})
truncated_df = pd.concat(
[truncated_df, truncated_row.to_frame().T], ignore_index=True
)
@@ -104,7 +104,7 @@ class SlackMixin:
if len(message) > MAXIMUM_MESSAGE_SIZE:
# Decrement i and build a message that is under the limit
truncated_df = df[:i].fillna("")
truncated_row = pd.Series(dict.fromkeys(df.columns, "..."))
truncated_row = pd.Series({k: "..." for k in df.columns})
truncated_df = pd.concat(
[truncated_df, truncated_row.to_frame().T], ignore_index=True
)

View File

@@ -281,13 +281,6 @@ def test_get_prequeries(mocker: MockerFixture) -> None:
assert DatabricksNativeEngineSpec.get_prequeries(
database, catalog="`escaped-hyphen`", schema="`hyphen-escaped`"
) == [
"USE CATALOG ```escaped-hyphen```",
"USE SCHEMA ```hyphen-escaped```",
]
assert DatabricksNativeEngineSpec.get_prequeries(
database, catalog="evil` USE CATALOG bad", schema="evil` USE SCHEMA bad"
) == [
"USE CATALOG `evil`` USE CATALOG bad`",
"USE SCHEMA `evil`` USE SCHEMA bad`",
"USE CATALOG `escaped-hyphen`",
"USE SCHEMA `hyphen-escaped`",
]

View File

@@ -81,9 +81,6 @@ def test_get_prequeries(mocker: MockerFixture) -> None:
assert Db2EngineSpec.get_prequeries(database, schema="my_schema") == [
'set current_schema "my_schema"'
]
assert Db2EngineSpec.get_prequeries(database, schema='evil"; SELECT 1--') == [
'set current_schema "evil""; SELECT 1--"'
]
@pytest.mark.parametrize(

View File

@@ -99,87 +99,3 @@ SELECT * \nFROM my_schema.my_table
LIMIT :param_1
""".strip()
)
def test_get_view_names_escapes_schema(mocker: MockerFixture) -> None:
"""
Test that ``get_view_names`` correctly escapes backticks in schema names
within the SHOW VIEWS statement.
"""
from superset.db_engine_specs.hive import HiveEngineSpec
database = mocker.MagicMock()
inspector = mocker.MagicMock()
conn = mocker.MagicMock()
cursor = mocker.MagicMock()
cursor.fetchall.return_value = []
conn.__enter__ = mocker.MagicMock(return_value=conn)
conn.__exit__ = mocker.MagicMock(return_value=False)
conn.cursor.return_value = cursor
database.get_raw_connection.return_value = conn
HiveEngineSpec.get_view_names(database, inspector, schema="evil` UNION SELECT 1--")
cursor.execute.assert_called_once()
sql = cursor.execute.call_args[0][0]
assert "IN `evil`` UNION SELECT 1--`" in sql
def test_df_to_sql_escapes_like_wildcards(mocker: MockerFixture) -> None:
"""
Test that ``df_to_sql`` escapes ``%`` and ``_`` wildcard characters in the
SHOW TABLES LIKE pattern used to detect table existence.
"""
import pandas as pd
from superset.db_engine_specs.hive import HiveEngineSpec
from superset.exceptions import SupersetException
from superset.sql.parse import Table
database = mocker.MagicMock()
# Simulate an existing table so df_to_sql raises before reaching the upload path
database.get_df.return_value = pd.DataFrame({"name": ["sales_%_2024"]})
with pytest.raises(SupersetException, match="Table already exists"):
HiveEngineSpec.df_to_sql(
database=database,
table=Table("sales_%_2024", "my_schema"),
df=pd.DataFrame({"a": [1]}),
to_sql_kwargs={"if_exists": "fail"},
)
database.get_df.assert_called_once()
sql = database.get_df.call_args[0][0]
assert r"\%" in sql
assert r"\_" in sql
assert "ESCAPE" in sql
def test_partition_query_escapes_identifiers() -> None:
"""
Test that ``_partition_query`` correctly backtick-quotes table and schema names
in the SHOW PARTITIONS statement.
"""
from superset.db_engine_specs.hive import HiveEngineSpec
from superset.sql.parse import Table
result = HiveEngineSpec._partition_query(
table=Table("my_table", "my_schema"),
indexes=[],
database=None, # type: ignore
)
assert result == "SHOW PARTITIONS `my_schema`.`my_table`"
result = HiveEngineSpec._partition_query(
table=Table("evil`tbl", "evil`schema"),
indexes=[],
database=None, # type: ignore
)
assert result == "SHOW PARTITIONS `evil``schema`.`evil``tbl`"
result = HiveEngineSpec._partition_query(
table=Table("no_schema_tbl"),
indexes=[],
database=None, # type: ignore
)
assert result == "SHOW PARTITIONS `no_schema_tbl`"

View File

@@ -147,9 +147,6 @@ def test_get_prequeries(mocker: MockerFixture) -> None:
assert spec.get_prequeries(database) == []
assert spec.get_prequeries(database, schema="test") == ['set search_path = "test"']
assert spec.get_prequeries(database, schema='evil"; SELECT 1--') == [
'set search_path = "evil""; SELECT 1--"'
]
def test_get_default_schema_for_query(mocker: MockerFixture) -> None:

View File

@@ -169,11 +169,6 @@ def test_impersonation_username(mocker: MockerFixture) -> None:
'EXECUTE AS "alice" WITH NO REVERT;'
]
database.get_effective_user.return_value = 'evil" WITH NO REVERT; DROP TABLE x--'
assert StarRocksEngineSpec.get_prequeries(database) == [
'EXECUTE AS "evil"" WITH NO REVERT; DROP TABLE x--" WITH NO REVERT;'
]
def test_impersonation_disabled(mocker: MockerFixture) -> None:
"""