Compare commits

..

16 Commits

Author SHA1 Message Date
Evan Rusackas
e2a8a88d36 docs: Update documentation link for ENABLE_SUPERSET_META_DB (#40076)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-05-12 20:39:39 -07:00
dependabot[bot]
0d9ecb7664 chore(deps-dev): update @types/node requirement from ^25.6.0 to ^25.7.0 in /superset-frontend/packages/superset-ui-core (#40059)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 20:34:10 -07:00
dependabot[bot]
1d220f7172 chore(deps-dev): update fs-extra requirement from ^11.3.4 to ^11.3.5 in /superset-frontend/packages/generator-superset (#39930)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 20:33:47 -07:00
Ville Brofeldt
af4dc3a9aa fix(re-encrypt): handle non-id PKs and make command idempotent (#40079) 2026-05-12 17:59:52 -07:00
Richard Fogaca Nienkotter
fa06989ed7 fix(mcp): return requested update chart previews (#40077) 2026-05-12 21:23:49 -03:00
dependabot[bot]
4d0cc1d7a6 chore(deps): bump zod from 4.4.1 to 4.4.3 in /superset-frontend (#39904)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 17:23:14 -07:00
dependabot[bot]
d8b2c5872b chore(deps-dev): bump @swc/core from 1.15.32 to 1.15.33 in /superset-frontend (#39935)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 17:22:58 -07:00
Elizabeth Thompson
86ba63b072 fix(dashboard): prevent duplicate subdirectory prefix when toggling fullscreen (#39534)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 16:51:37 -07:00
dependabot[bot]
4c14e16e58 chore(deps): bump @babel/plugin-transform-modules-systemjs from 7.20.11 to 7.29.4 in /superset-frontend/cypress-base (#39982)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 16:25:28 -07:00
dependabot[bot]
fe22e06011 chore(deps): bump mermaid from 11.10.0 to 11.15.0 in /docs (#40038)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 16:25:09 -07:00
dependabot[bot]
9160da0d27 chore(deps-dev): bump yeoman-test from 11.3.1 to 11.5.2 in /superset-frontend (#40058)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 16:24:55 -07:00
dependabot[bot]
43a89f8710 chore(deps-dev): bump terser-webpack-plugin from 5.5.0 to 5.6.0 in /superset-frontend (#40061)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 16:24:37 -07:00
Varun Chawla
a77fec68d4 fix(drill-detail): make page-size selector functionally adjustable (#37975)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-05-12 13:39:41 -07:00
Abdul Rehman
e94465208f fix(bar-chart): cap bar width so a single data point doesn't stretch across the chart (#39588)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-12 13:24:46 -07:00
Abdul Rehman
f2eee4ef46 fix(frontend): prevent LanguagePicker crash when locale is missing from LANGUAGES config (#39585)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-12 13:22:36 -07:00
yeaight
7445105735 fix(explore): explain disabled chart overwrite option (#39796) 2026-05-12 12:53:59 -07:00
30 changed files with 1203 additions and 612 deletions

View File

@@ -174,7 +174,7 @@
"default": false,
"lifecycle": "testing",
"description": "Allows users to add a superset:// DB that can query across databases. Experimental with potential security/performance risks. See SUPERSET_META_DB_LIMIT.",
"docs": "https://superset.apache.org/docs/configuration/databases/#querying-across-databases"
"docs": "https://superset.apache.org/user-docs/databases/supported/superset-meta-database"
},
{
"name": "ESTIMATE_QUERY_COST",

View File

@@ -232,19 +232,14 @@
json2mq "^0.2.0"
throttle-debounce "^5.0.0"
"@antfu/install-pkg@^1.0.0":
"@antfu/install-pkg@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz"
resolved "https://registry.yarnpkg.com/@antfu/install-pkg/-/install-pkg-1.1.0.tgz#78fa036be1a6081b5a77a5cf59f50c7752b6ba26"
integrity sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==
dependencies:
package-manager-detector "^1.3.0"
tinyexec "^1.0.1"
"@antfu/utils@^8.1.0":
version "8.1.1"
resolved "https://registry.npmjs.org/@antfu/utils/-/utils-8.1.1.tgz"
integrity sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==
"@apidevtools/json-schema-ref-parser@^15.3.3":
version "15.3.5"
resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.3.5.tgz#503726178d8d792eea7b195566272aaee6837e2f"
@@ -1219,42 +1214,15 @@
"@babel/helper-string-parser" "^7.27.1"
"@babel/helper-validator-identifier" "^7.28.5"
"@braintree/sanitize-url@^7.0.4":
version "7.1.1"
resolved "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz"
integrity sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==
"@braintree/sanitize-url@^7.1.1":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz#ca2035b0fefe956a8676ff0c69af73e605fcd81f"
integrity sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==
"@chevrotain/cst-dts-gen@11.0.3":
version "11.0.3"
resolved "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz"
integrity sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==
dependencies:
"@chevrotain/gast" "11.0.3"
"@chevrotain/types" "11.0.3"
lodash-es "4.17.21"
"@chevrotain/gast@11.0.3":
version "11.0.3"
resolved "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz"
integrity sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==
dependencies:
"@chevrotain/types" "11.0.3"
lodash-es "4.17.21"
"@chevrotain/regexp-to-ast@11.0.3":
version "11.0.3"
resolved "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz"
integrity sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==
"@chevrotain/types@11.0.3":
version "11.0.3"
resolved "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz"
integrity sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==
"@chevrotain/utils@11.0.3":
version "11.0.3"
resolved "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz"
integrity sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==
"@chevrotain/types@~11.1.1":
version "11.1.2"
resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-11.1.2.tgz#e83a1a2704f0c5e49e7592b214031a0f4a34d7e5"
integrity sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==
"@colors/colors@1.5.0":
version "1.5.0"
@@ -2578,19 +2546,14 @@
resolved "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz"
integrity sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==
"@iconify/utils@^2.1.33":
version "2.3.0"
resolved "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz"
integrity sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==
"@iconify/utils@^3.0.2":
version "3.1.3"
resolved "https://registry.yarnpkg.com/@iconify/utils/-/utils-3.1.3.tgz#71efd68f9ed2ea3c91fd3a01c0032f70a87027b7"
integrity sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==
dependencies:
"@antfu/install-pkg" "^1.0.0"
"@antfu/utils" "^8.1.0"
"@antfu/install-pkg" "^1.1.0"
"@iconify/types" "^2.0.0"
debug "^4.4.0"
globals "^15.14.0"
kolorist "^1.8.0"
local-pkg "^1.0.0"
mlly "^1.7.4"
import-meta-resolve "^4.2.0"
"@jest/schemas@^29.6.3":
version "29.6.3"
@@ -2739,12 +2702,12 @@
dependencies:
"@types/mdx" "^2.0.0"
"@mermaid-js/parser@^0.6.2":
version "0.6.2"
resolved "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.2.tgz"
integrity sha512-+PO02uGF6L6Cs0Bw8RpGhikVvMWEysfAyl27qTlroUB8jSWr1lL0Sf6zi78ZxlSnmgSY2AMMKVgghnN9jTtwkQ==
"@mermaid-js/parser@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@mermaid-js/parser/-/parser-1.1.1.tgz#30f3ab68d816912e43f245a72a0d4081bf69d966"
integrity sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==
dependencies:
langium "3.3.1"
"@chevrotain/types" "~11.1.1"
"@module-federation/error-codes@0.22.0":
version "0.22.0"
@@ -5189,6 +5152,14 @@
resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz"
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
"@upsetjs/venn.js@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@upsetjs/venn.js/-/venn.js-2.0.0.tgz#3be192038cdda927aa4f8b22ab51af82abf47f34"
integrity sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==
optionalDependencies:
d3-selection "^3.0.0"
d3-transition "^3.0.1"
"@vx/responsive@^0.0.199":
version "0.0.199"
resolved "https://registry.npmjs.org/@vx/responsive/-/responsive-0.0.199.tgz"
@@ -6170,25 +6141,6 @@ cheerio@1.0.0-rc.12:
parse5 "^7.0.0"
parse5-htmlparser2-tree-adapter "^7.0.0"
chevrotain-allstar@~0.3.0:
version "0.3.1"
resolved "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz"
integrity sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==
dependencies:
lodash-es "^4.17.21"
chevrotain@~11.0.3:
version "11.0.3"
resolved "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz"
integrity sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==
dependencies:
"@chevrotain/cst-dts-gen" "11.0.3"
"@chevrotain/gast" "11.0.3"
"@chevrotain/regexp-to-ast" "11.0.3"
"@chevrotain/types" "11.0.3"
"@chevrotain/utils" "11.0.3"
lodash-es "4.17.21"
chokidar@^3.5.3, chokidar@^3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz"
@@ -6420,16 +6372,6 @@ concat-map@0.0.1:
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
confbox@^0.1.8:
version "0.1.8"
resolved "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz"
integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==
confbox@^0.2.2:
version "0.2.2"
resolved "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz"
integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==
config-chain@^1.1.11:
version "1.1.13"
resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz"
@@ -6801,10 +6743,10 @@ cytoscape-fcose@^2.2.0:
dependencies:
cose-base "^2.2.0"
cytoscape@^3.29.3:
version "3.33.1"
resolved "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz"
integrity sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==
cytoscape@^3.33.1:
version "3.33.3"
resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.33.3.tgz#6c885823cb088eb8c31087c35d978661dcde5eae"
integrity sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g==
"d3-array@1 - 2", d3-array@2, d3-array@^2.3.0:
version "2.12.1"
@@ -7014,7 +6956,7 @@ d3-scale@^3.0.0:
d3-time "^2.1.1"
d3-time-format "2 - 3"
"d3-selection@2 - 3", d3-selection@3:
"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz"
integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
@@ -7066,7 +7008,7 @@ d3-shape@^1.2.0:
resolved "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz"
integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
"d3-transition@2 - 3", d3-transition@3:
"d3-transition@2 - 3", d3-transition@3, d3-transition@^3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz"
integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==
@@ -7124,10 +7066,10 @@ d3@^7.9.0:
d3-transition "3"
d3-zoom "3"
dagre-d3-es@7.0.11:
version "7.0.11"
resolved "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz"
integrity sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==
dagre-d3-es@7.0.14:
version "7.0.14"
resolved "https://registry.yarnpkg.com/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz#1272276e26457cf3b97dac569f8f0531ec33c377"
integrity sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==
dependencies:
d3 "^7.9.0"
lodash-es "^4.17.21"
@@ -7159,11 +7101,16 @@ 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.13:
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==
debounce@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz"
@@ -7176,7 +7123,7 @@ debug@2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.1, debug@^4.4.3:
debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.1, debug@^4.4.3:
version "4.4.3"
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
@@ -7447,7 +7394,14 @@ domhandler@^5.0.2, domhandler@^5.0.3:
dependencies:
domelementtype "^2.3.0"
dompurify@^3.2.5, dompurify@^3.4.0:
dompurify@^3.3.1:
version "3.4.2"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.4.2.tgz#f0ff81be682c485505097ba8195a058d8f575218"
integrity sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==
optionalDependencies:
"@types/trusted-types" "^2.0.7"
dompurify@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.4.1.tgz#521d04483ac12631b2aedf434a5f5390933b8789"
integrity sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==
@@ -7716,6 +7670,11 @@ es-to-primitive@^1.3.0:
is-date-object "^1.0.5"
is-symbol "^1.0.4"
es-toolkit@^1.45.1:
version "1.46.1"
resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.46.1.tgz#38ca27191a98a867fc544b81cf1477a68947fb06"
integrity sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==
es6-promise@^3.2.1:
version "3.3.1"
resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz"
@@ -8107,11 +8066,6 @@ express@^4.21.2:
utils-merge "1.0.1"
vary "~1.1.2"
exsolve@^1.0.7:
version "1.0.7"
resolved "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz"
integrity sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz"
@@ -8512,11 +8466,6 @@ globals@^14.0.0:
resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz"
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
globals@^15.14.0:
version "15.15.0"
resolved "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz"
integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==
globals@^17.6.0:
version "17.6.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-17.6.0.tgz#0f0be018d5cca8690e6375ead1f65c4bb96191fc"
@@ -9083,6 +9032,11 @@ import-lazy@^4.0.0:
resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz"
integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==
import-meta-resolve@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz#08cb85b5bd37ecc8eb1e0f670dc2767002d43734"
integrity sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
@@ -9792,10 +9746,10 @@ jsonfile@^6.0.1:
object.assign "^4.1.4"
object.values "^1.1.6"
katex@^0.16.22:
version "0.16.22"
resolved "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz"
integrity sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==
katex@^0.16.25:
version "0.16.45"
resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.45.tgz#ba60d39c54746b6b8d39ce0e7f6eace07143149c"
integrity sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==
dependencies:
commander "^8.3.0"
@@ -9826,22 +9780,6 @@ kleur@^4.0.3:
resolved "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz"
integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
kolorist@^1.8.0:
version "1.8.0"
resolved "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz"
integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==
langium@3.3.1:
version "3.3.1"
resolved "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz"
integrity sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==
dependencies:
chevrotain "~11.0.3"
chevrotain-allstar "~0.3.0"
vscode-languageserver "~9.0.1"
vscode-languageserver-textdocument "~1.0.11"
vscode-uri "~3.0.8"
latest-version@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz"
@@ -9992,15 +9930,6 @@ loader-utils@^2.0.0:
emojis-list "^3.0.0"
json5 "^2.1.2"
local-pkg@^1.0.0:
version "1.1.2"
resolved "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz"
integrity sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==
dependencies:
mlly "^1.7.4"
pkg-types "^2.3.0"
quansync "^0.2.11"
locate-path@^6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
@@ -10015,7 +9944,7 @@ locate-path@^7.1.0:
dependencies:
p-locate "^6.0.0"
lodash-es@4.17.21, lodash-es@^4.17.21:
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
@@ -10106,10 +10035,10 @@ markdown-table@^3.0.0:
resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz"
integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==
marked@^16.0.0:
version "16.2.0"
resolved "https://registry.npmjs.org/marked/-/marked-16.2.0.tgz"
integrity sha512-LbbTuye+0dWRz2TS9KJ7wsnD4KAtpj0MVkWc90XvBa6AslXsT0hTBVH5k32pcSyHH1fst9XEFJunXHktVy0zlg==
marked@^16.3.0:
version "16.4.2"
resolved "https://registry.yarnpkg.com/marked/-/marked-16.4.2.tgz#4959a64be6c486f0db7467ead7ce288de54290a3"
integrity sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==
math-expression-evaluator@^1.3.8:
version "1.4.0"
@@ -10430,30 +10359,31 @@ merge2@^1.3.0, merge2@^1.4.1:
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
mermaid@>=11.6.0:
version "11.10.0"
resolved "https://registry.npmjs.org/mermaid/-/mermaid-11.10.0.tgz"
integrity sha512-oQsFzPBy9xlpnGxUqLbVY8pvknLlsNIJ0NWwi8SUJjhbP1IT0E0o1lfhU4iYV3ubpy+xkzkaOyDUQMn06vQElQ==
version "11.15.0"
resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-11.15.0.tgz#b485c13ea5e1e74f3328c4bb00427bda87fa1c1e"
integrity sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==
dependencies:
"@braintree/sanitize-url" "^7.0.4"
"@iconify/utils" "^2.1.33"
"@mermaid-js/parser" "^0.6.2"
"@braintree/sanitize-url" "^7.1.1"
"@iconify/utils" "^3.0.2"
"@mermaid-js/parser" "^1.1.1"
"@types/d3" "^7.4.3"
cytoscape "^3.29.3"
"@upsetjs/venn.js" "^2.0.0"
cytoscape "^3.33.1"
cytoscape-cose-bilkent "^4.1.0"
cytoscape-fcose "^2.2.0"
d3 "^7.9.0"
d3-sankey "^0.12.3"
dagre-d3-es "7.0.11"
dayjs "^1.11.13"
dompurify "^3.2.5"
katex "^0.16.22"
dagre-d3-es "7.0.14"
dayjs "^1.11.19"
dompurify "^3.3.1"
es-toolkit "^1.45.1"
katex "^0.16.25"
khroma "^2.1.0"
lodash-es "^4.17.21"
marked "^16.0.0"
marked "^16.3.0"
roughjs "^4.6.6"
stylis "^4.3.6"
ts-dedent "^2.2.0"
uuid "^11.1.0"
uuid "^11.1.0 || ^12 || ^13 || ^14.0.0"
methods@~1.1.2:
version "1.1.2"
@@ -11159,16 +11089,6 @@ minimist@^1.2.0:
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
mlly@^1.7.4:
version "1.7.4"
resolved "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz"
integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==
dependencies:
acorn "^8.14.0"
pathe "^2.0.1"
pkg-types "^1.3.0"
ufo "^1.5.4"
mri@^1.1.0:
version "1.2.0"
resolved "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz"
@@ -11849,11 +11769,6 @@ path@0.12.7:
process "^0.11.1"
util "^0.10.3"
pathe@^2.0.1, pathe@^2.0.3:
version "2.0.3"
resolved "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz"
integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==
picocolors@^1.0.0, picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
@@ -11881,24 +11796,6 @@ pkg-dir@^7.0.0:
dependencies:
find-up "^6.3.0"
pkg-types@^1.3.0:
version "1.3.1"
resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz"
integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==
dependencies:
confbox "^0.1.8"
mlly "^1.7.4"
pathe "^2.0.1"
pkg-types@^2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz"
integrity sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==
dependencies:
confbox "^0.2.2"
exsolve "^1.0.7"
pathe "^2.0.3"
pluralize@^8.0.0:
version "8.0.0"
resolved "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz"
@@ -12644,11 +12541,6 @@ qs@^6.12.3, qs@~6.14.0:
dependencies:
side-channel "^1.1.0"
quansync@^0.2.11:
version "0.2.11"
resolved "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz"
integrity sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==
querystringify@^2.1.1:
version "2.2.0"
resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz"
@@ -14778,11 +14670,6 @@ typescript@~6.0.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21"
integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==
ufo@^1.5.4:
version "1.6.1"
resolved "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz"
integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==
un-eval@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/un-eval/-/un-eval-1.2.0.tgz"
@@ -15115,10 +15002,10 @@ uuid@8.3.2, uuid@^8.3.2:
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
uuid@^11.1.0:
version "11.1.0"
resolved "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz"
integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==
"uuid@^11.1.0 || ^12 || ^13 || ^14.0.0":
version "14.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-14.0.0.tgz#0af883220163d264ffe0c084f6b8a89b9666966d"
integrity sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==
uvu@^0.5.0:
version "0.5.6"
@@ -15212,41 +15099,6 @@ vfile@^6.0.0, vfile@^6.0.1:
"@types/unist" "^3.0.0"
vfile-message "^4.0.0"
vscode-jsonrpc@8.2.0:
version "8.2.0"
resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz"
integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==
vscode-languageserver-protocol@3.17.5:
version "3.17.5"
resolved "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz"
integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==
dependencies:
vscode-jsonrpc "8.2.0"
vscode-languageserver-types "3.17.5"
vscode-languageserver-textdocument@~1.0.11:
version "1.0.12"
resolved "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz"
integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==
vscode-languageserver-types@3.17.5:
version "3.17.5"
resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz"
integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==
vscode-languageserver@~9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz"
integrity sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==
dependencies:
vscode-languageserver-protocol "3.17.5"
vscode-uri@~3.0.8:
version "3.0.8"
resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz"
integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==
warning@^4.0.3:
version "4.0.3"
resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz"

View File

@@ -96,14 +96,15 @@
}
},
"node_modules/@babel/generator": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"version": "7.29.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"dependencies": {
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
"@babel/parser": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
@@ -224,6 +225,7 @@
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
@@ -244,6 +246,7 @@
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"peer": true,
"dependencies": {
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
@@ -252,13 +255,10 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dependencies": {
"@babel/types": "^7.22.5"
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
"engines": {
"node": ">=6.9.0"
}
@@ -276,32 +276,31 @@
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
"integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
"dependencies": {
"@babel/types": "^7.21.4"
"@babel/traverse": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.21.2",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
"integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
"dependencies": {
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-module-imports": "^7.18.6",
"@babel/helper-simple-access": "^7.20.2",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.21.2",
"@babel/types": "^7.21.2"
"@babel/helper-module-imports": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-optimise-call-expression": {
@@ -317,9 +316,9 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
"integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
"integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
"peer": true,
"engines": {
"node": ">=6.9.0"
@@ -364,6 +363,7 @@
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
"peer": true,
"dependencies": {
"@babel/types": "^7.20.2"
},
@@ -387,6 +387,7 @@
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"peer": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@@ -395,19 +396,17 @@
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"license": "MIT",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"license": "MIT",
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"engines": {
"node": ">=6.9.0"
}
@@ -462,12 +461,11 @@
}
},
"node_modules/@babel/parser": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz",
"integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==",
"license": "MIT",
"version": "7.29.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
"integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
"dependencies": {
"@babel/types": "^7.26.10"
"@babel/types": "^7.29.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -1223,15 +1221,15 @@
}
},
"node_modules/@babel/plugin-transform-modules-systemjs": {
"version": "7.20.11",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz",
"integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==",
"version": "7.29.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz",
"integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==",
"peer": true,
"dependencies": {
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-module-transforms": "^7.20.11",
"@babel/helper-plugin-utils": "^7.20.2",
"@babel/helper-validator-identifier": "^7.19.1"
"@babel/helper-module-transforms": "^7.28.6",
"@babel/helper-plugin-utils": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.29.0"
},
"engines": {
"node": ">=6.9.0"
@@ -1595,73 +1593,68 @@
}
},
"node_modules/@babel/template": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"license": "MIT",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.9",
"@babel/types": "^7.26.9"
"@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template/node_modules/@babel/code-frame": {
"version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"license": "MIT",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dependencies": {
"@babel/helper-validator-identifier": "^7.25.9",
"@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"dependencies": {
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/types": "^7.29.0",
"debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse/node_modules/@babel/code-frame": {
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dependencies": {
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
"@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
"integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
"license": "MIT",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9"
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -2080,16 +2073,12 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
@@ -2100,14 +2089,6 @@
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
@@ -2119,14 +2100,14 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@@ -4932,6 +4913,7 @@
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"peer": true,
"engines": {
"node": ">=4"
}
@@ -5641,14 +5623,14 @@
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=4"
"node": ">=6"
}
},
"node_modules/json-parse-even-better-errors": {
@@ -8758,14 +8740,15 @@
}
},
"@babel/generator": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"version": "7.29.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"requires": {
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
"@babel/parser": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
}
},
"@babel/helper-annotate-as-pure": {
@@ -8857,7 +8840,8 @@
"@babel/helper-environment-visitor": {
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"peer": true
},
"@babel/helper-explode-assignable-expression": {
"version": "7.18.6",
@@ -8872,18 +8856,16 @@
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"peer": true,
"requires": {
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"requires": {
"@babel/types": "^7.22.5"
}
"@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="
},
"@babel/helper-member-expression-to-functions": {
"version": "7.21.0",
@@ -8895,26 +8877,22 @@
}
},
"@babel/helper-module-imports": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
"integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
"requires": {
"@babel/types": "^7.21.4"
"@babel/traverse": "^7.28.6",
"@babel/types": "^7.28.6"
}
},
"@babel/helper-module-transforms": {
"version": "7.21.2",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
"integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
"requires": {
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-module-imports": "^7.18.6",
"@babel/helper-simple-access": "^7.20.2",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.21.2",
"@babel/types": "^7.21.2"
"@babel/helper-module-imports": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.28.6"
}
},
"@babel/helper-optimise-call-expression": {
@@ -8927,9 +8905,9 @@
}
},
"@babel/helper-plugin-utils": {
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
"integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
"integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
"peer": true
},
"@babel/helper-remap-async-to-generator": {
@@ -8962,6 +8940,7 @@
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
"peer": true,
"requires": {
"@babel/types": "^7.20.2"
}
@@ -8979,19 +8958,20 @@
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"peer": true,
"requires": {
"@babel/types": "^7.22.5"
}
},
"@babel/helper-string-parser": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="
},
"@babel/helper-validator-identifier": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="
},
"@babel/helper-validator-option": {
"version": "7.21.0",
@@ -9030,11 +9010,11 @@
}
},
"@babel/parser": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz",
"integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==",
"version": "7.29.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
"integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
"requires": {
"@babel/types": "^7.26.10"
"@babel/types": "^7.29.0"
}
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
@@ -9523,15 +9503,15 @@
}
},
"@babel/plugin-transform-modules-systemjs": {
"version": "7.20.11",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz",
"integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==",
"version": "7.29.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz",
"integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==",
"peer": true,
"requires": {
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-module-transforms": "^7.20.11",
"@babel/helper-plugin-utils": "^7.20.2",
"@babel/helper-validator-identifier": "^7.19.1"
"@babel/helper-module-transforms": "^7.28.6",
"@babel/helper-plugin-utils": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.29.0"
}
},
"@babel/plugin-transform-modules-umd": {
@@ -9786,62 +9766,60 @@
}
},
"@babel/template": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"requires": {
"@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.9",
"@babel/types": "^7.26.9"
"@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.28.6",
"@babel/types": "^7.28.6"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"requires": {
"@babel/helper-validator-identifier": "^7.25.9",
"@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
"picocolors": "^1.1.1"
}
}
}
},
"@babel/traverse": {
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"requires": {
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/types": "^7.29.0",
"debug": "^4.3.1"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"requires": {
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
"@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
}
}
}
},
"@babel/types": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
"integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"requires": {
"@babel/helper-string-parser": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9"
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
}
},
"@colors/colors": {
@@ -10180,12 +10158,11 @@
"integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw=="
},
"@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"requires": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
@@ -10194,11 +10171,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="
},
"@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="
},
"@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
@@ -10210,14 +10182,14 @@
}
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
},
"@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"requires": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@@ -12441,7 +12413,8 @@
"globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"peer": true
},
"globby": {
"version": "11.0.4",
@@ -12945,9 +12918,9 @@
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="
},
"json-parse-even-better-errors": {
"version": "2.3.1",

View File

@@ -194,7 +194,7 @@
"@storybook/test": "^8.6.18",
"@storybook/test-runner": "^0.17.0",
"@svgr/webpack": "^8.1.0",
"@swc/core": "^1.15.32",
"@swc/core": "^1.15.33",
"@swc/plugin-emotion": "^14.9.0",
"@swc/plugin-transform-imports": "^12.5.0",
"@testing-library/dom": "^9.3.4",
@@ -283,7 +283,7 @@
"storybook": "8.6.18",
"style-loader": "^4.0.0",
"swc-loader": "^0.2.7",
"terser-webpack-plugin": "^5.5.0",
"terser-webpack-plugin": "^5.6.0",
"ts-jest": "^29.4.9",
"tscw-config": "^1.1.2",
"tsx": "^4.21.0",
@@ -12485,9 +12485,9 @@
}
},
"node_modules/@swc/core": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.32.tgz",
"integrity": "sha512-/eWL0n43D64QWEUHLtTE+jDqjkJhyidjkDhv6f0uJohOUAhywxQ9wXYp845DNNds0JpCdI4Uo0a9bl+vbXf+ew==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.33.tgz",
"integrity": "sha512-jOlwnFV2xhuuZeAUILGFULeR6vDPfijEJ57evfocwznQldLU3w2cZ9bSDryY9ip+AsM3r1NJKzf47V2NXebkeQ==",
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
@@ -12503,18 +12503,18 @@
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
"@swc/core-darwin-arm64": "1.15.32",
"@swc/core-darwin-x64": "1.15.32",
"@swc/core-linux-arm-gnueabihf": "1.15.32",
"@swc/core-linux-arm64-gnu": "1.15.32",
"@swc/core-linux-arm64-musl": "1.15.32",
"@swc/core-linux-ppc64-gnu": "1.15.32",
"@swc/core-linux-s390x-gnu": "1.15.32",
"@swc/core-linux-x64-gnu": "1.15.32",
"@swc/core-linux-x64-musl": "1.15.32",
"@swc/core-win32-arm64-msvc": "1.15.32",
"@swc/core-win32-ia32-msvc": "1.15.32",
"@swc/core-win32-x64-msvc": "1.15.32"
"@swc/core-darwin-arm64": "1.15.33",
"@swc/core-darwin-x64": "1.15.33",
"@swc/core-linux-arm-gnueabihf": "1.15.33",
"@swc/core-linux-arm64-gnu": "1.15.33",
"@swc/core-linux-arm64-musl": "1.15.33",
"@swc/core-linux-ppc64-gnu": "1.15.33",
"@swc/core-linux-s390x-gnu": "1.15.33",
"@swc/core-linux-x64-gnu": "1.15.33",
"@swc/core-linux-x64-musl": "1.15.33",
"@swc/core-win32-arm64-msvc": "1.15.33",
"@swc/core-win32-ia32-msvc": "1.15.33",
"@swc/core-win32-x64-msvc": "1.15.33"
},
"peerDependencies": {
"@swc/helpers": ">=0.5.17"
@@ -12526,9 +12526,9 @@
}
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.32.tgz",
"integrity": "sha512-/YWMvJDPu+AAwuUsM2G+DNQ/7zhodURGzdQyewEqcvgklAdDHs3LwQmLLnyn6SJl8DT8UOxkbzK+D1PmPeelRg==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.33.tgz",
"integrity": "sha512-N+L0uXhuO7FIfzqwgxmzv0zIpV0qEp8wPX3QQs2p4atjMoywup2JTeDlXPw+z9pWJGCae3JjM+tZ6myclI+2gA==",
"cpu": [
"arm64"
],
@@ -12542,9 +12542,9 @@
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.32.tgz",
"integrity": "sha512-KOTXJXdAhWL+hZ77MYP3z+4pcMFaQhQ74yqyN1uz093q0YnbxpqMtYpPISbYvMHzVRNNx5kN+9RZAXEaadhWVA==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.33.tgz",
"integrity": "sha512-/Il4QHSOhV4FekbsDtkrNmKbsX26oSysvgrRswa/RYOHXAkwXDbB4jaeKq6PsJLSPkzJ2KzQ061gtBnk0vNHfA==",
"cpu": [
"x64"
],
@@ -12558,9 +12558,9 @@
}
},
"node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.32.tgz",
"integrity": "sha512-oOoxLweljlc0A4X8ybsgxV7cVaYTwBOg2iMDJcFR3Sr48C+lsv9VzSmqdK/IVIXF4W4GjLc3VqTAdSMXlfVLuQ==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.33.tgz",
"integrity": "sha512-C64hBnBxq4viOPQ8hlx+2lJ23bzZBGnjw7ryALmS+0Q3zHmwO8lw1/DArLENw4Q18/0w5wdEO1k3m1wWNtKGqQ==",
"cpu": [
"arm"
],
@@ -12574,9 +12574,9 @@
}
},
"node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.32.tgz",
"integrity": "sha512-oDzEkdl6D6BAWdMtU5KGO7y3HR5fJcvByNLyEk9+ugj8nP5Ovb7P4kBcStBXc4MPExFGQryehiINMlmY8HlclA==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.33.tgz",
"integrity": "sha512-TRJfnJbX3jqpxRDRoieMzRiCBS5jOmXNb3iQXmcgjFEHKLnAgK1RZRU8Cq1MsPqO4jAJp/ld1G4O3fXuxv85uw==",
"cpu": [
"arm64"
],
@@ -12590,9 +12590,9 @@
}
},
"node_modules/@swc/core-linux-arm64-musl": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.32.tgz",
"integrity": "sha512-omcqjoZP/b8D8PuczVoRwJieC6ibj7qIxTftNYokz4/aSmKFHvsd7nIFfPk5ZvtzncbH4AY7+Dkr/Lp2gWxYeA==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.33.tgz",
"integrity": "sha512-il7tYM+CpUNzieQbwAjFT1P8zqAhmGWNAGhQZBnxurXZ0aNn+5nqYFTEUKNZl7QibtT0uQXzTZrNGHCIj6Y1Og==",
"cpu": [
"arm64"
],
@@ -12606,9 +12606,9 @@
}
},
"node_modules/@swc/core-linux-ppc64-gnu": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.32.tgz",
"integrity": "sha512-KGkTMyz/Tbn3PBNu0AVZ4GTDFKnICrYcTiNPZq8DrvK42pnFsf3GNDrIG9E5AtQlTmC0YigkWKmu0eMcfTrmgA==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.33.tgz",
"integrity": "sha512-ZtNBwN0Z7CFj9Il0FcPaKdjgP7URyKu/3RfH46vq+0paOBqLj4NYldD6Qo//Duif/7IOtAraUfDOmp0PLAufog==",
"cpu": [
"ppc64"
],
@@ -12622,9 +12622,9 @@
}
},
"node_modules/@swc/core-linux-s390x-gnu": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.32.tgz",
"integrity": "sha512-G3Aa4tVS/3OGZBkoNIwUF9F6RAy+Osb4GOlo62SinLmDiErz/ykmM7KH0wkz6l9kM8jJq1HyAM6atJTUEbBk7g==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.33.tgz",
"integrity": "sha512-De1IyajoOmhOYYjw/lx66bKlyDpHZTueqwpDrWgf5O7T6d1ODeJJO9/OqMBmrBQc5C+dNnlmIufHsp4QVCWufA==",
"cpu": [
"s390x"
],
@@ -12638,9 +12638,9 @@
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.32.tgz",
"integrity": "sha512-ERsjfGcj6CBmj3vJnGDO8m8rTvw6RqMcWo1dogOtNx3/+/0+NNpJiXDobJrr1GwInI/BHAEkvSFIH6d2LqPcUQ==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.33.tgz",
"integrity": "sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw==",
"cpu": [
"x64"
],
@@ -12654,9 +12654,9 @@
}
},
"node_modules/@swc/core-linux-x64-musl": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.32.tgz",
"integrity": "sha512-N4Ggahe/8SUbTX50P6EdhbW9YWcgbZVb52R4cq6MK+zsoMjRq7rGvV5ztA05QnbaCYqMYx8rTY7KAIA3Crdo4Q==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.33.tgz",
"integrity": "sha512-hj628ZkSEJf6zMf5VMbYrG2O6QqyTIp2qwY6VlCjvIa9lAEZ5c2lfPblCLVGYubTeLJDxadLB/CxqQYOQABeEQ==",
"cpu": [
"x64"
],
@@ -12670,9 +12670,9 @@
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.32.tgz",
"integrity": "sha512-01yN0o9jvo8xBTP12aPK2wW8b41jmOlGbDDlAnoynotc4pO6xA0zby9f1z6j++qXDpGBttLySq1omgVrlQKYcw==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.33.tgz",
"integrity": "sha512-GV2oohtN2/5+KSccl86VULu3aT+LrISC8uzgSq0FRnikpD+Zwc+sBlXmoKQ+Db6jI57ITUOIB8jRkdGMABC29g==",
"cpu": [
"arm64"
],
@@ -12686,9 +12686,9 @@
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.32.tgz",
"integrity": "sha512-fLagI9XZYNpTcmlqAcp3KBtmj7E19WCmYD80Jxj1Kn5tGNa7yxNLd3NNdWxuZGUPl5iC0/KqZru7g08gF6Fsrw==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.33.tgz",
"integrity": "sha512-gtyvzSNR8DHKfFEA2uqb8Ld1myqi6uEg2jyeUq3ikn5ytYs7H8RpZYC8mdy4NXr8hfcdJfCLXPlYaqqfBXpoEQ==",
"cpu": [
"ia32"
],
@@ -12702,9 +12702,9 @@
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.15.32",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.32.tgz",
"integrity": "sha512-gbc2bQ/T2CiR+w0OvcVKwLOFAcPZBvmWmolbwpg1E8UrpeC03DGtyMUApOHNXNYWA3SHFrYXCQtosrcMza1YFg==",
"version": "1.15.33",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.33.tgz",
"integrity": "sha512-d6fRqQSkJI+kmMEBWaDQ7TMl8+YjLYbwRUPZQ9DY0ORBJeTzOrG0twvfvlZ2xgw6jA0ScQKgfBm4vHLSLl5Hqg==",
"cpu": [
"x64"
],
@@ -13876,12 +13876,12 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.6.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
"integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
"version": "25.7.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz",
"integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.19.0"
"undici-types": "~7.21.0"
}
},
"node_modules/@types/normalize-package-data": {
@@ -24644,9 +24644,9 @@
}
},
"node_modules/fs-extra": {
"version": "11.3.4",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz",
"integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==",
"version": "11.3.5",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz",
"integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
@@ -45413,9 +45413,9 @@
}
},
"node_modules/terser-webpack-plugin": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.5.0.tgz",
"integrity": "sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==",
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz",
"integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -45435,12 +45435,39 @@
"webpack": "^5.1.0"
},
"peerDependenciesMeta": {
"@minify-html/node": {
"optional": true
},
"@swc/core": {
"optional": true
},
"@swc/css": {
"optional": true
},
"@swc/html": {
"optional": true
},
"clean-css": {
"optional": true
},
"cssnano": {
"optional": true
},
"csso": {
"optional": true
},
"esbuild": {
"optional": true
},
"html-minifier-terser": {
"optional": true
},
"lightningcss": {
"optional": true
},
"postcss": {
"optional": true
},
"uglify-js": {
"optional": true
}
@@ -47052,9 +47079,9 @@
}
},
"node_modules/undici-types": {
"version": "7.19.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
"integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz",
"integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==",
"license": "MIT"
},
"node_modules/unicode-canonical-property-names-ecmascript": {
@@ -49711,9 +49738,9 @@
},
"devDependencies": {
"cross-env": "^10.1.0",
"fs-extra": "^11.3.4",
"fs-extra": "^11.3.5",
"jest": "^30.3.0",
"yeoman-test": "^11.4.2"
"yeoman-test": "^11.5.2"
},
"engines": {
"node": ">= 18.0.0",
@@ -50199,7 +50226,7 @@
"@types/d3-time-format": "^4.0.3",
"@types/jquery": "^4.0.0",
"@types/lodash": "^4.17.24",
"@types/node": "^25.6.0",
"@types/node": "^25.7.0",
"@types/prop-types": "^15.7.15",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/react-table": "^7.7.20",
@@ -50755,7 +50782,7 @@
"acorn": "^8.16.0",
"d3-array": "^3.2.4",
"lodash": "^4.18.1",
"zod": "^4.4.3"
"zod": "^4.4.1"
},
"peerDependencies": {
"@apache-superset/core": "*",

View File

@@ -275,7 +275,7 @@
"@storybook/test": "^8.6.18",
"@storybook/test-runner": "^0.17.0",
"@svgr/webpack": "^8.1.0",
"@swc/core": "^1.15.32",
"@swc/core": "^1.15.33",
"@swc/plugin-emotion": "^14.9.0",
"@swc/plugin-transform-imports": "^12.5.0",
"@testing-library/dom": "^9.3.4",
@@ -364,7 +364,7 @@
"storybook": "8.6.18",
"style-loader": "^4.0.0",
"swc-loader": "^0.2.7",
"terser-webpack-plugin": "^5.5.0",
"terser-webpack-plugin": "^5.6.0",
"ts-jest": "^29.4.9",
"tscw-config": "^1.1.2",
"tsx": "^4.21.0",

View File

@@ -35,9 +35,9 @@
},
"devDependencies": {
"cross-env": "^10.1.0",
"fs-extra": "^11.3.4",
"fs-extra": "^11.3.5",
"jest": "^30.3.0",
"yeoman-test": "^11.4.2"
"yeoman-test": "^11.5.2"
},
"engines": {
"npm": ">= 4.0.0",

View File

@@ -76,7 +76,7 @@
"@types/d3-time-format": "^4.0.3",
"@types/jquery": "^4.0.0",
"@types/lodash": "^4.17.24",
"@types/node": "^25.6.0",
"@types/node": "^25.7.0",
"@types/prop-types": "^15.7.15",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/react-table": "^7.7.20",

View File

@@ -29,7 +29,7 @@
"acorn": "^8.16.0",
"d3-array": "^3.2.4",
"lodash": "^4.18.1",
"zod": "^4.4.3"
"zod": "^4.4.1"
},
"peerDependencies": {
"@apache-superset/core": "*",

View File

@@ -389,6 +389,9 @@ export function transformSeries(
...(colorByPrimaryAxis ? {} : { itemStyle }),
// @ts-ignore
type: plotType,
// Cap bar width so a single data point doesn't stretch across the
// entire chart area. Bars with many categories auto-size below this cap.
...(plotType === 'bar' ? { barMaxWidth: 100 } : {}),
smooth: seriesType === 'smooth',
triggerLineEvent: true,
// @ts-expect-error

View File

@@ -19,10 +19,12 @@
import fetchMock from 'fetch-mock';
import { QueryFormData, SupersetClient } from '@superset-ui/core';
import {
fireEvent,
render,
screen,
userEvent,
waitFor,
within,
} from 'spec/helpers/testing-library';
import { getMockStoreWithNativeFilters } from 'spec/fixtures/mockStore';
import chartQueries, { sliceId } from 'spec/fixtures/mockChartQueries';
@@ -119,6 +121,34 @@ const fetchWithData = () => {
});
};
const fetchWithPaginatedData = () => {
setupDatasetEndpoint();
fetchMock.post(SAMPLES_ENDPOINT, {
result: {
total_count: 100,
data: [
{
year: 1996,
na_sales: 11.27,
eu_sales: 8.89,
},
{
year: 1989,
na_sales: 23.2,
eu_sales: 2.26,
},
{
year: 1999,
na_sales: 9,
eu_sales: 6.18,
},
],
colnames: ['year', 'na_sales', 'eu_sales'],
coltypes: [0, 0, 0],
},
});
};
afterEach(() => {
fetchMock.clearHistory().removeRoutes();
supersetGetCache.clear();
@@ -254,6 +284,54 @@ describe('download actions', () => {
});
});
test('should render pagination when results exceed page size', async () => {
// The "should render the error" test above leaves a SupersetClient.post
// rejection spy active (matching the existing pattern; "should use
// verbose_map" further down does the same cleanup). Reset it here so the
// fetch in this test actually returns data.
jest.restoreAllMocks();
fetchWithPaginatedData();
await waitForRender();
// With total_count=100 and page size=50, pagination should render
await waitFor(() => {
const pagination = document.querySelector('.ant-pagination');
expect(pagination).toBeTruthy();
});
});
test('should offer the full set of page-size options', async () => {
fetchWithPaginatedData();
await waitForRender();
// The page-size changer renders as an antd Select. In jsdom, antd opens
// its overlay on mouseDown of the .ant-select-selector element rather
// than via a click on the inner combobox input.
const selector = await waitFor(() => {
const el = document.querySelector(
'.ant-pagination-options-size-changer .ant-select-selector',
) as HTMLElement | null;
expect(el).toBeTruthy();
return el!;
});
fireEvent.mouseDown(selector);
// The opened listbox lives in a body portal; collect its options and assert
// exactly the canonical [5, 15, 25, 50, 100] set is offered. Without this
// guard, regressing to a single hardcoded option (the pre-rework approach)
// would silently pass CI.
const listbox = await screen.findByRole('listbox');
const offeredSizes = within(listbox)
.getAllByRole('option')
.map(el => el.getAttribute('title'));
expect(offeredSizes).toEqual([
'5 / page',
'15 / page',
'25 / page',
'50 / page',
'100 / page',
]);
});
test('should use verbose_map for column headers when available', async () => {
jest.restoreAllMocks();

View File

@@ -60,7 +60,7 @@ import { getDrillPayload } from './utils';
import { ResultsPage } from './types';
import { datasetLabelLower } from 'src/features/semanticLayers/label';
const PAGE_SIZE = 50;
const DEFAULT_PAGE_SIZE = 50;
interface DataType {
[key: string]: any;
@@ -94,6 +94,7 @@ export default function DrillDetailPane({
}) {
const theme = useTheme();
const [pageIndex, setPageIndex] = useState(0);
const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE);
const lastPageIndex = useRef(pageIndex);
const [filters, setFilters] = useState(initialFilters);
const [isLoading, setIsLoading] = useState(false);
@@ -307,13 +308,13 @@ export default function DrillDetailPane({
if (!responseError && !isLoading && !resultsPages.has(pageIndex)) {
setIsLoading(true);
const jsonPayload = getDrillPayload(formData, filters) ?? {};
const cachePageLimit = Math.ceil(SAMPLES_ROW_LIMIT / PAGE_SIZE);
const cachePageLimit = Math.ceil(SAMPLES_ROW_LIMIT / pageSize);
getDatasourceSamples(
datasourceType as DatasourceType,
Number(datasourceId),
false,
jsonPayload,
PAGE_SIZE,
pageSize,
pageIndex + 1,
dashboardId,
)
@@ -349,6 +350,7 @@ export default function DrillDetailPane({
formData,
isLoading,
pageIndex,
pageSize,
responseError,
resultsPages,
]);
@@ -384,13 +386,20 @@ export default function DrillDetailPane({
data={data}
columns={mappedColumns}
size={TableSize.Small}
defaultPageSize={PAGE_SIZE}
defaultPageSize={DEFAULT_PAGE_SIZE}
recordCount={resultsPage?.total}
usePagination
loading={isLoading}
onChange={pagination =>
setPageIndex(pagination.current ? pagination.current - 1 : 0)
}
onChange={pagination => {
const newPageSize = pagination.pageSize ?? pageSize;
if (newPageSize !== pageSize) {
setPageSize(newPageSize);
setResultsPages(new Map());
setPageIndex(0);
} else {
setPageIndex(pagination.current ? pagination.current - 1 : 0);
}
}}
resizable
virtualize
allowHTML={allowHTML}

View File

@@ -139,6 +139,7 @@ describe('DashboardBuilder', () => {
...overrideState,
}),
useDnd: true,
useRouter: true,
useTheme: true,
});
}
@@ -473,6 +474,7 @@ test('should render ParentSize wrapper with height 100% for tabs', async () => {
dashboardLayout: undoableDashboardLayoutWithTabs,
}),
useDnd: true,
useRouter: true,
useTheme: true,
});
@@ -506,6 +508,7 @@ test('should maintain layout when switching between tabs', async () => {
dashboardLayout: undoableDashboardLayoutWithTabs,
}),
useDnd: true,
useRouter: true,
useTheme: true,
});

View File

@@ -31,6 +31,20 @@ import { DASHBOARD_HEADER_ID } from '../../util/constants';
import { UPDATE_COMPONENTS } from '../../actions/dashboardLayout';
import { AutoRefreshStatus } from '../../types/autoRefresh';
const mockHistoryReplace = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
replace: mockHistoryReplace,
}),
useLocation: jest.fn(() => ({
pathname: '/dashboard',
search: '?standalone=1',
hash: '',
state: undefined,
})),
}));
const initialState = {
dashboardInfo: {
id: 1,
@@ -223,6 +237,13 @@ beforeAll(() => {
beforeEach(() => {
jest.clearAllMocks();
const { useLocation } = jest.requireMock('react-router-dom');
useLocation.mockReturnValue({
pathname: '/dashboard',
search: '?standalone=1',
hash: '',
state: undefined,
});
(useUnsavedChangesPrompt as jest.Mock).mockReturnValue({
showModal: false,
@@ -984,3 +1005,73 @@ test('should sync theme ref when navigating between dashboards', async () => {
expect(setUnsavedChanges).toHaveBeenCalledTimes(0);
});
});
test('should not duplicate subdirectory prefix when toggling fullscreen', async () => {
const { useLocation } = jest.requireMock('react-router-dom');
// Simulate React Router with basename=/pcs: useLocation returns path relative to basename
useLocation.mockReturnValue({
pathname: '/dashboard',
search: '?standalone=1',
hash: '',
state: undefined,
});
// Simulate browser URL including the subdirectory prefix
window.history.pushState({}, 'Test page', '/pcs/dashboard?standalone=1');
setup();
await openActionsDropdown();
userEvent.click(screen.getByText('Exit fullscreen'));
// history.replace must be called with the Router-relative path, not window.location.pathname.
// If the subdirectory prefix (/pcs) were included, React Router would prepend it again,
// producing /pcs/pcs/dashboard (the bug). The path must start with /dashboard, not /pcs/.
expect(mockHistoryReplace).toHaveBeenCalledWith(
expect.not.stringMatching(/^\/pcs\//),
);
expect(mockHistoryReplace).toHaveBeenCalledWith(
expect.stringMatching(/^\/dashboard(\?|$)/),
);
});
test('should not duplicate subdirectory prefix when entering fullscreen', async () => {
const { useLocation } = jest.requireMock('react-router-dom');
useLocation.mockReturnValue({
pathname: '/dashboard',
search: '',
hash: '',
state: undefined,
});
window.history.pushState({}, 'Test page', '/pcs/dashboard');
setup();
await openActionsDropdown();
userEvent.click(screen.getByText('Enter fullscreen'));
expect(mockHistoryReplace).toHaveBeenCalledWith(
expect.not.stringMatching(/^\/pcs\//),
);
expect(mockHistoryReplace).toHaveBeenCalledWith(
expect.stringMatching(/^\/dashboard\?standalone=1$/),
);
});
test('share URL should use browser-absolute pathname to preserve subdirectory prefix', () => {
const { useLocation } = jest.requireMock('react-router-dom');
// Router returns path without the subdirectory prefix
useLocation.mockReturnValue({
pathname: '/dashboard',
search: '',
hash: '',
state: undefined,
});
// Browser URL includes the full prefix
window.history.pushState({}, 'Test page', '/pcs/dashboard');
const { container } = setup();
// The share/embed URL must use window.location.pathname so that shared links
// include the subdirectory prefix and work outside the React Router context.
const emailLink = container.querySelector('[data-test="share-by-email"]');
if (emailLink) {
expect(emailLink.getAttribute('href')).toMatch(/\/pcs\/dashboard/);
}
});

View File

@@ -19,7 +19,7 @@
import type { Dispatch, ReactElement, SetStateAction } from 'react';
import { useState, useEffect, useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useHistory, useLocation } from 'react-router-dom';
import { Menu, MenuItem } from '@superset-ui/core/components/Menu';
import { t } from '@apache-superset/core/translation';
import { isEmpty } from 'lodash';
@@ -75,6 +75,7 @@ export const useHeaderActionsMenu = ({
const [isDropdownVisible, setIsDropdownVisible] = useState(false);
const { canExportImage } = usePermissions();
const history = useHistory();
const location = useLocation();
const directPathToChild = useSelector(
(state: RootState) => state.dashboardState.directPathToChild,
);
@@ -101,8 +102,11 @@ export const useHeaderActionsMenu = ({
case MenuKeys.ToggleFullscreen: {
const isCurrentlyStandalone =
Number(getUrlParam(URL_PARAMS.standalone)) === 1;
// Use location.pathname from React Router (relative to basename) rather than
// window.location.pathname to avoid duplicating the subdirectory prefix when
// history.replace prepends it again.
const url = getDashboardUrl({
pathname: window.location.pathname,
pathname: location.pathname,
filters: getActiveFilters(),
hash: window.location.hash,
standalone: isCurrentlyStandalone ? null : 1,
@@ -125,6 +129,7 @@ export const useHeaderActionsMenu = ({
showRefreshModal,
manageEmbedded,
history,
location,
],
);
@@ -133,6 +138,10 @@ export const useHeaderActionsMenu = ({
[dashboardTitle],
);
// window.location.pathname is intentional here: this URL is used for sharing
// (email, embed, copy link) and must be a full browser-absolute path that
// includes the application root. Do NOT replace with useLocation().pathname —
// that would strip the subdirectory prefix and produce a broken share link.
const url = useMemo(
() =>
getDashboardUrl({

View File

@@ -115,6 +115,16 @@ describe('getChartIdsFromLayout', () => {
windowSpy.mockRestore();
});
test('should pass through a router-relative pathname unchanged', () => {
const url = getDashboardUrl({
pathname: '/dashboard/1/',
filters: {},
hash: '',
standalone: DashboardStandaloneMode.HideNav,
});
expect(url).toBe(`/dashboard/1/?standalone=${DashboardStandaloneMode.HideNav}`);
});
test('should process native filters key', () => {
const windowSpy = jest.spyOn(window, 'window', 'get');
windowSpy.mockImplementation(

View File

@@ -282,7 +282,7 @@ test('disables overwrite option for new slice', () => {
});
test('disables overwrite option for non-owner', () => {
const { getByRole } = setup(
const { getByRole, getByText } = setup(
{},
mockStore({
...initialState,
@@ -290,6 +290,33 @@ test('disables overwrite option for non-owner', () => {
}),
);
expect(getByRole('radio', { name: 'Save (Overwrite)' })).toBeDisabled();
expect(
getByText(
'Must be a chart owner to overwrite this chart. Save as a new chart instead.',
),
).toBeInTheDocument();
});
test('disables overwrite option for externally managed slice', () => {
const { getByRole, getByText } = setup(
{},
mockStore({
...initialState,
explore: {
...initialState.explore,
slice: {
...initialState.explore.slice,
is_managed_externally: true,
},
},
}),
);
expect(getByRole('radio', { name: 'Save (Overwrite)' })).toBeDisabled();
expect(
getByText(
"This chart is managed externally and can't be overwritten in Superset.",
),
).toBeInTheDocument();
});
test('updates slice name and selected dashboard', async () => {

View File

@@ -34,6 +34,7 @@ import {
Loading,
Divider,
Flex,
Typography,
TreeSelect,
} from '@superset-ui/core/components';
import { logging } from '@apache-superset/core/utils';
@@ -597,18 +598,32 @@ class SaveModal extends Component<SaveModalProps, SaveModalState> {
renderSaveChartModal = () => {
const info = this.info();
const canOverwriteSlice = this.canOverwriteSlice();
return (
<Form data-test="save-modal-body" layout="vertical">
<FormItem data-test="radio-group">
<Radio
id="overwrite-radio"
disabled={!this.canOverwriteSlice()}
disabled={!canOverwriteSlice}
checked={this.state.action === 'overwrite'}
onChange={() => this.changeAction('overwrite')}
data-test="save-overwrite-radio"
>
{t('Save (Overwrite)')}
</Radio>
{this.props.slice && !canOverwriteSlice && (
<div>
<Typography.Text type="secondary">
{this.props.slice.is_managed_externally
? t(
"This chart is managed externally and can't be overwritten in Superset.",
)
: t(
'Must be a chart owner to overwrite this chart. Save as a new chart instead.',
)}
</Typography.Text>
</div>
)}
<Radio
id="saveas-radio"
data-test="saveas-radio"

View File

@@ -25,9 +25,9 @@ import { Typography } from '@superset-ui/core/components/Typography';
export interface Languages {
[key: string]: {
flag: string;
url: string;
name: string;
flag?: string;
url?: string;
name?: string;
};
}
@@ -61,9 +61,9 @@ export const useLanguageMenuItems = ({
key: langKey,
label: (
<StyledLabel className="f16">
<i className={`flag ${languages[langKey].flag}`} />
<Typography.Link href={languages[langKey].url}>
{languages[langKey].name}
<i className={`flag ${languages[langKey]?.flag ?? 'us'}`} />
<Typography.Link href={languages[langKey]?.url}>
{languages[langKey]?.name}
</Typography.Link>
</StyledLabel>
),
@@ -75,7 +75,7 @@ export const useLanguageMenuItems = ({
type: 'submenu' as const,
label: (
<span className="f16" aria-label={t('Languages')}>
<i className={`flag ${languages[locale].flag}`} />
<i className={`flag ${languages[locale]?.flag ?? 'us'}`} />
</span>
),
icon: <Icons.CaretDownOutlined iconSize="xs" />,

View File

@@ -229,3 +229,19 @@ test('ensureAppRoot should prefix unknown schemes instead of passing through', a
// Unknown / custom schemes are treated as relative paths
expect(ensureAppRoot('foo:bar')).toBe('/superset/foo:bar');
});
test('ensureAppRoot should be idempotent — not double-prefix an already-prefixed path', async () => {
const { ensureAppRoot } = await loadPathUtils('/superset/');
const once = ensureAppRoot('/sqllab');
const twice = ensureAppRoot(once);
expect(twice).toBe(once); // /superset/sqllab, NOT /superset/superset/sqllab
});
test('makeUrl should be idempotent with subdirectory prefix', async () => {
const { makeUrl } = await loadPathUtils('/superset/');
const once = makeUrl('/sqllab?new=true');
const twice = makeUrl(once);
expect(twice).toBe(once); // /superset/sqllab?new=true, NOT /superset/superset/sqllab?new=true
});

View File

@@ -41,7 +41,15 @@ export function ensureAppRoot(path: string): string {
if (SAFE_ABSOLUTE_URL_RE.test(path) || path.startsWith('//')) {
return path;
}
return `${applicationRoot()}${path.startsWith('/') ? path : `/${path}`}`;
const root = applicationRoot();
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
if (
root &&
(normalizedPath === root || normalizedPath.startsWith(`${root}/`))
) {
return normalizedPath;
}
return `${root}${normalizedPath}`;
}
/**

View File

@@ -115,15 +115,19 @@ def re_encrypt_secrets(previous_secret_key: Optional[str] = None) -> None:
"PREVIOUS_SECRET_KEY"
)
if previous_secret_key is None:
click.secho("A previous secret key must be provided", err=True)
sys.exit(1)
click.secho(
"No previous secret key provided; nothing to re-encrypt.",
fg="yellow",
)
return
secrets_migrator = SecretsMigrator(previous_secret_key=previous_secret_key)
try:
secrets_migrator.run()
except ValueError as exc:
click.secho(
f"An error occurred, "
f"probably an invalid previous secret key was provided. Error:[{exc}]",
err=True,
)
stats = secrets_migrator.run()
except Exception as exc: # pylint: disable=broad-except
click.secho(f"Re-encryption failed: {exc}", err=True)
sys.exit(1)
click.secho(
f"Re-encryption complete: {stats.re_encrypted} re-encrypted, "
f"{stats.skipped} skipped, {stats.null} null, {stats.failed} failed.",
fg="green",
)

View File

@@ -643,7 +643,7 @@ DEFAULT_FEATURE_FLAGS: dict[str, bool] = {
# Experimental with potential security/performance risks.
# See SUPERSET_META_DB_LIMIT.
# @lifecycle: testing
# @docs: https://superset.apache.org/docs/configuration/databases/#querying-across-databases
# @docs: https://superset.apache.org/user-docs/databases/supported/superset-meta-database
"ENABLE_SUPERSET_META_DB": False,
# Enable query cost estimation. Supported in Presto, Postgres, and BigQuery.
# Requires `cost_estimate_enabled: true` in database `extra` attribute.

View File

@@ -353,9 +353,9 @@ class OAuth2RedirectError(SupersetErrorException):
See the `OAuth2RedirectMessage.tsx` component for more details of how this
information is handled.
"""
status = 403
TODO (betodealmeida): change status to 403.
"""
def __init__(self, url: str, tab_id: str, redirect_uri: str):
super().__init__(

View File

@@ -36,6 +36,8 @@ from superset.mcp_service.chart.schemas import (
logger = logging.getLogger(__name__)
SUPPORTED_FORM_DATA_PREVIEW_FORMATS = frozenset({"ascii", "table", "vega_lite"})
def _build_query_columns(form_data: Dict[str, Any]) -> list[str]:
"""Build query columns list from form_data, including both x_axis and groupby."""

View File

@@ -43,6 +43,7 @@ from superset.mcp_service.chart.compile import (
CompileResult,
validate_and_compile,
)
from superset.mcp_service.chart.preview_utils import SUPPORTED_FORM_DATA_PREVIEW_FORMATS
from superset.mcp_service.chart.schemas import (
AccessibilityMetadata,
CHART_FORM_DATA_EXCLUDED_FIELD_NAMES,
@@ -630,11 +631,7 @@ async def generate_chart( # noqa: C901
# For preview-only mode (save_chart=false)
# Note: Screenshot-based URL previews are not
# supported. Use explore_url to view interactively.
if format_type in [
"ascii",
"table",
"vega_lite",
]:
if format_type in SUPPORTED_FORM_DATA_PREVIEW_FORMATS:
# Generate preview from form data
from superset.mcp_service.chart.preview_utils import (
generate_preview_from_form_data,

View File

@@ -40,8 +40,13 @@ from superset.mcp_service.chart.chart_utils import (
map_config_to_form_data,
)
from superset.mcp_service.chart.compile import validate_and_compile
from superset.mcp_service.chart.preview_utils import (
generate_preview_from_form_data,
SUPPORTED_FORM_DATA_PREVIEW_FORMATS,
)
from superset.mcp_service.chart.schemas import (
AccessibilityMetadata,
ChartError,
PerformanceMetadata,
UpdateChartPreviewRequest,
)
@@ -229,9 +234,39 @@ def update_chart_preview( # noqa: C901
high_contrast_available=False,
)
# Note: Screenshot-based previews are not supported.
# Use the explore_url to view the chart interactively.
previews: Dict[str, Any] = {}
if request.generate_preview:
try:
with event_logger.log_context(
action="mcp.update_chart_preview.preview"
):
for format_type in request.preview_formats:
# URL previews are represented by explore_url/chart.url.
# Screenshot-based previews are not supported.
if format_type not in SUPPORTED_FORM_DATA_PREVIEW_FORMATS:
continue
preview_result = generate_preview_from_form_data(
form_data=new_form_data,
dataset_id=dataset.id,
preview_format=format_type,
)
if isinstance(preview_result, ChartError):
logger.warning(
"Preview '%s' failed: %s",
format_type,
preview_result.error,
)
else:
previews[format_type] = (
preview_result.model_dump(mode="json")
if hasattr(preview_result, "model_dump")
else preview_result
)
except (CommandException, ValueError, KeyError) as e:
logger.warning("Preview generation failed: %s", e)
# Return enhanced data
result = {

View File

@@ -16,11 +16,12 @@
# under the License.
import logging
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any, Optional
from flask import Flask
from flask_babel import lazy_gettext as _
from sqlalchemy import text, TypeDecorator
from sqlalchemy import Table, text, TypeDecorator
from sqlalchemy.engine import Connection, Dialect, Row
from sqlalchemy_utils import EncryptedType as SqlaEncryptedType
@@ -33,6 +34,16 @@ ENC_ADAPTER_TAG_ATTR_NAME = "__created_by_enc_field_adapter__"
logger = logging.getLogger(__name__)
@dataclass
class ReEncryptStats:
"""Per-value outcome counts for a SecretsMigrator.run() invocation."""
re_encrypted: int = 0
skipped: int = 0
null: int = 0
failed: int = 0
class AbstractEncryptedFieldAdapter(ABC): # pylint: disable=too-few-public-methods
@abstractmethod
def create(
@@ -97,11 +108,13 @@ class SecretsMigrator:
self._previous_secret_key = previous_secret_key
self._dialect: Dialect = db.engine.url.get_dialect()
def discover_encrypted_fields(self) -> dict[str, dict[str, EncryptedType]]:
def discover_encrypted_fields(
self,
) -> dict[str, tuple[Table, dict[str, EncryptedType]]]:
"""
Iterates over ORM-mapped tables, looking for EncryptedType columns
along the way. Builds up a dict of
table_name -> dict of col_name: enc type instance
table_name -> (Table, dict of col_name: enc type instance)
Superset's ORM models inherit from Flask-AppBuilder's declarative base
(`flask_appbuilder.Model`), whose MetaData is distinct from
@@ -109,13 +122,18 @@ class SecretsMigrator:
regardless of which base a model uses. FAB's metadata takes precedence
when a table name appears in both registries.
:return: mapping of table name to a dict of {column name: EncryptedType}
The Table object is returned alongside the encrypted columns so callers
can introspect the schema (notably the primary key) without assuming a
conventional `id` column — some tables (e.g. `semantic_layers`) use a
`uuid` primary key instead.
:return: mapping of table name to (Table, {column name: EncryptedType})
"""
from flask_appbuilder import ( # pylint: disable=import-outside-toplevel
Model as FABModel,
)
meta_info: dict[str, Any] = {}
meta_info: dict[str, tuple[Table, dict[str, EncryptedType]]] = {}
tables: dict[str, Any] = dict(FABModel.metadata.tables)
for table_name, table in self._db.metadata.tables.items():
@@ -124,9 +142,9 @@ class SecretsMigrator:
for table_name, table in tables.items():
for col_name, col in table.columns.items():
if isinstance(col.type, EncryptedType):
cols = meta_info.get(table_name, {})
_, cols = meta_info.get(table_name, (table, {}))
cols[col_name] = col.type
meta_info[table_name] = cols
meta_info[table_name] = (table, cols)
return meta_info
@@ -151,9 +169,13 @@ class SecretsMigrator:
@staticmethod
def _select_columns_from_table(
conn: Connection, column_names: list[str], table_name: str
conn: Connection,
pk_columns: list[str],
column_names: list[str],
table_name: str,
) -> Row:
return conn.execute(f"SELECT id, {','.join(column_names)} FROM {table_name}") # noqa: S608
cols = ",".join(pk_columns + column_names)
return conn.execute(f"SELECT {cols} FROM {table_name}") # noqa: S608
def _re_encrypt_row(
self,
@@ -161,62 +183,143 @@ class SecretsMigrator:
row: Row,
table_name: str,
columns: dict[str, EncryptedType],
pk_columns: list[str],
stats: ReEncryptStats,
) -> None:
"""
Re encrypts all columns in a Row
Re-encryption is idempotent per column: we first ask whether the
current key can already decrypt the value, and skip if so. Only if
the current key fails do we fall back to decrypting with the
previous key and re-encrypting. Checking the current key first
keeps ``run()`` idempotent regardless of what ``previous_secret_key``
the caller supplies — even re-running with the same (unchanged)
``SECRET_KEY`` will not rewrite rows.
NULL values are never encrypted, so they are reported separately
(neither re-encrypted nor "skipped because already current").
Per-column outcomes are accumulated onto ``stats`` so the caller can
report a summary. Columns whose ciphertext is unreadable under both
keys are counted as failures and logged; the exception is not
propagated, so processing continues. The caller is responsible for
raising once all rows have been scanned.
If no columns need re-encryption, no UPDATE is issued.
:param row: Current row to reencrypt
:param columns: Meta info from columns
:param pk_columns: Primary key column names used to target the row
:param stats: Mutable counters updated per column
"""
re_encrypted_columns = {}
for column_name, encrypted_type in columns.items():
raw_value = self._read_bytes(column_name, row[column_name])
# NULL values aren't encrypted; there is nothing to migrate.
if raw_value is None:
stats.null += 1
continue
# Fast path: if the current key can already read the value,
# leave it untouched. A failure here simply means we need to try
# the previous key below — not a condition worth logging.
try:
encrypted_type.process_result_value(raw_value, self._dialect)
except Exception: # noqa: BLE001, S110 # pylint: disable=broad-except
pass
else:
stats.skipped += 1
continue
# Current key cannot decrypt — try the previous key.
previous_encrypted_type = EncryptedType(
type_in=encrypted_type.underlying_type, key=self._previous_secret_key
)
try:
unencrypted_value = previous_encrypted_type.process_result_value(
self._read_bytes(column_name, row[column_name]), self._dialect
raw_value, self._dialect
)
except ValueError as ex:
# Failed to unencrypt
try:
encrypted_type.process_result_value(
self._read_bytes(column_name, row[column_name]), self._dialect
)
logger.info(
"Current secret is able to decrypt value on column [%s.%s],"
" nothing to do",
table_name,
column_name,
)
return
except Exception:
raise Exception from ex # pylint: disable=broad-exception-raised
except Exception as prev_ex: # noqa: BLE001 # pylint: disable=broad-except
logger.error(
"Column [%s.%s] cannot be decrypted under the previous"
" or current secret key (%s: %s)",
table_name,
column_name,
type(prev_ex).__name__,
prev_ex,
)
stats.failed += 1
continue
re_encrypted_columns[column_name] = encrypted_type.process_bind_param(
unencrypted_value,
self._dialect,
)
stats.re_encrypted += 1
set_cols = ",".join(
[f"{name} = :{name}" for name in list(re_encrypted_columns.keys())]
)
logger.info("Processing table: %s", table_name)
if not re_encrypted_columns:
return
set_cols = ",".join(f"{name} = :{name}" for name in re_encrypted_columns)
where_clause = " AND ".join(f"{pk} = :_pk_{pk}" for pk in pk_columns)
pk_bind = {f"_pk_{pk}": row[pk] for pk in pk_columns}
conn.execute(
text(f"UPDATE {table_name} SET {set_cols} WHERE id = :id"), # noqa: S608
id=row["id"],
text(
f"UPDATE {table_name} SET {set_cols} WHERE {where_clause}" # noqa: S608
),
**pk_bind,
**re_encrypted_columns,
)
def run(self) -> None:
def run(self) -> ReEncryptStats:
"""
Re-encrypt every encrypted column in the ORM under the current
``SECRET_KEY``.
Returns per-value counts of re-encrypted, skipped (already under the
current key), and failed (undecryptable) outcomes. If any failures
occurred the transaction is rolled back by raising after the
summary is logged, so partial re-encryption never commits.
"""
encrypted_meta_info = self.discover_encrypted_fields()
stats = ReEncryptStats()
with self._db.engine.begin() as conn:
logger.info("Collecting info for re encryption")
for table_name, columns in encrypted_meta_info.items():
for table_name, (table, columns) in encrypted_meta_info.items():
pk_columns = [c.name for c in table.primary_key.columns]
if not pk_columns:
logger.warning(
"Skipping %s: no primary key, cannot target rows for update",
table_name,
)
continue
column_names = list(columns.keys())
rows = self._select_columns_from_table(conn, column_names, table_name)
rows = self._select_columns_from_table(
conn, pk_columns, column_names, table_name
)
for row in rows:
self._re_encrypt_row(conn, row, table_name, columns)
self._re_encrypt_row(
conn, row, table_name, columns, pk_columns, stats
)
logger.info(
"Re-encryption summary: %d re-encrypted, %d skipped,"
" %d null, %d failed",
stats.re_encrypted,
stats.skipped,
stats.null,
stats.failed,
)
if stats.failed:
raise Exception( # pylint: disable=broad-exception-raised
f"Re-encryption failed for {stats.failed} value(s); "
"transaction rolled back"
)
logger.info("All tables processed")
return stats

View File

@@ -28,6 +28,7 @@ from freezegun import freeze_time
import superset.cli.importexport
import superset.cli.thumbnails
import superset.cli.update
from superset import db
from superset.models.dashboard import Dashboard
from tests.integration_tests.fixtures.birth_names_dashboard import (
@@ -322,3 +323,44 @@ def test_compute_thumbnails(thumbnail_mock, app_context, fs):
thumbnail_mock.assert_called_with(None, dashboard.id, force=False)
assert response.exit_code == 0
def test_re_encrypt_secrets_without_previous_key_is_noop(app_context):
"""
When neither --previous_secret_key nor config.PREVIOUS_SECRET_KEY is set,
the command should exit cleanly (0) rather than error out, so that
scheduled re-encryption runs don't start failing after a successful
rotation is complete.
"""
current_app.config.pop("PREVIOUS_SECRET_KEY", None)
runner = current_app.test_cli_runner()
with mock.patch.object(superset.cli.update.SecretsMigrator, "run") as run_mock:
response = runner.invoke(superset.cli.update.re_encrypt_secrets, [])
assert response.exit_code == 0
assert "nothing to re-encrypt" in response.output.lower()
run_mock.assert_not_called()
def test_re_encrypt_secrets_failure_exits_nonzero(app_context):
"""
When re-encryption fails for any field, SecretsMigrator.run raises to
trigger rollback. The CLI must surface that as a non-zero exit with a
clear error message — not as an uncaught exception.
"""
runner = current_app.test_cli_runner()
with mock.patch.object(
superset.cli.update.SecretsMigrator,
"run",
side_effect=Exception("Re-encryption failed for 2 value(s)"),
):
response = runner.invoke(
superset.cli.update.re_encrypt_secrets,
["--previous_secret_key", "old-key"],
)
assert response.exit_code == 1
assert "Re-encryption failed" in response.output
# The failure path must be handled by the CLI, not leaked as an
# uncaught exception.
assert response.exception is None or isinstance(response.exception, SystemExit)

View File

@@ -24,6 +24,7 @@ from sqlalchemy_utils.types.encrypted.encrypted_type import StringEncryptedType
from superset.extensions import encrypted_field_factory
from superset.utils.encrypt import (
AbstractEncryptedFieldAdapter,
ReEncryptStats,
SecretsMigrator,
SQLAlchemyUtilsAdapter,
)
@@ -79,7 +80,7 @@ class EncryptedFieldTest(SupersetTestCase):
migrator = SecretsMigrator("")
encrypted_fields = migrator.discover_encrypted_fields()
for table_name, cols in encrypted_fields.items():
for table_name, (_table, cols) in encrypted_fields.items():
for col_name, field in cols.items():
if not encrypted_field_factory.created_by_enc_field_factory(field):
self.fail(
@@ -101,8 +102,33 @@ class EncryptedFieldTest(SupersetTestCase):
"dbs table not found in encrypted fields — "
"discover_encrypted_fields may be using the wrong MetaData instance"
)
dbs_cols = set(encrypted_fields["dbs"].keys())
assert {"password", "encrypted_extra", "server_cert"}.issubset(dbs_cols)
_table, dbs_cols = encrypted_fields["dbs"]
assert {"password", "encrypted_extra", "server_cert"}.issubset(
set(dbs_cols.keys())
)
def test_discover_encrypted_fields_returns_table_with_non_id_pk(self):
"""
Ensure discover_encrypted_fields surfaces the Table object alongside
encrypted columns, and that the PK introspection works for tables
whose primary key is not a conventional integer `id` column
(e.g. `semantic_layers` uses `uuid` as its PK).
"""
# Import triggers FAB metadata registration for the semantic_layers table.
from superset.semantic_layers.models import SemanticLayer # noqa: F401
migrator = SecretsMigrator("")
encrypted_fields = migrator.discover_encrypted_fields()
assert "semantic_layers" in encrypted_fields, (
"semantic_layers table not found — it has an encrypted `configuration` "
"column and should be discovered"
)
table, cols = encrypted_fields["semantic_layers"]
assert "configuration" in cols
pk_columns = [c.name for c in table.primary_key.columns]
assert pk_columns == ["uuid"], (
f"Expected semantic_layers PK to be ['uuid'], got {pk_columns}"
)
def test_lazy_key_resolution(self):
"""
@@ -175,3 +201,190 @@ class EncryptedFieldTest(SupersetTestCase):
# Restore original key
self.app.config["SECRET_KEY"] = key_a
def test_re_encrypt_row_uses_pk_columns(self):
"""
Verify SecretsMigrator builds UPDATE statements targeting the table's
actual primary key columns rather than a hardcoded `id` column.
Regression guard for tables like `semantic_layers` whose PK is `uuid`.
"""
from unittest.mock import MagicMock
from sqlalchemy.engine import make_url
dialect = make_url("sqlite://").get_dialect()
previous_key = "PREVIOUS_KEY_FOR_PK_COLUMN_TEST"
migrator = SecretsMigrator(previous_key)
migrator._dialect = dialect # noqa: SLF001
# Encrypt under the previous key so the current-key decrypt fails
# and the re-encrypt path (which issues the UPDATE) is exercised.
previous_field = EncryptedType(type_in=String(1024), key=previous_key)
ciphertext = previous_field.process_bind_param("hunter2", dialect)
current_field = encrypted_field_factory.create(String(1024))
conn = MagicMock()
row = {"uuid": b"\x00" * 16, "configuration": ciphertext}
stats = ReEncryptStats()
migrator._re_encrypt_row( # noqa: SLF001
conn,
row,
"semantic_layers",
{"configuration": current_field},
["uuid"],
stats,
)
assert conn.execute.call_count == 1
stmt = str(conn.execute.call_args.args[0])
assert "WHERE uuid = :_pk_uuid" in stmt
kwargs = conn.execute.call_args.kwargs
assert kwargs["_pk_uuid"] == row["uuid"]
assert "configuration" in kwargs
assert stats == ReEncryptStats(re_encrypted=1, skipped=0, failed=0)
def test_re_encrypt_row_is_idempotent(self):
"""
Re-running re-encryption on a row that is already encrypted under the
current key must be a no-op: no UPDATE is issued, no error is raised,
and the outcome is counted as skipped.
"""
from unittest.mock import MagicMock
from sqlalchemy.engine import make_url
dialect = make_url("sqlite://").get_dialect()
current_key = self.app.config["SECRET_KEY"]
migrator = SecretsMigrator("WRONG_PREVIOUS_KEY_abcdef")
migrator._dialect = dialect # noqa: SLF001
field = encrypted_field_factory.create(String(1024))
ciphertext = field.process_bind_param("hunter2", dialect)
assert field.process_result_value(ciphertext, dialect) == "hunter2"
conn = MagicMock()
row = {"uuid": b"\x00" * 16, "configuration": ciphertext}
stats = ReEncryptStats()
migrator._re_encrypt_row( # noqa: SLF001
conn,
row,
"semantic_layers",
{"configuration": field},
["uuid"],
stats,
)
assert conn.execute.call_count == 0, (
"Row already readable under current key should not trigger UPDATE"
)
assert stats == ReEncryptStats(re_encrypted=0, skipped=1, failed=0)
# Current key must still decrypt the original ciphertext — nothing
# was mutated.
self.app.config["SECRET_KEY"] = current_key
assert field.process_result_value(ciphertext, dialect) == "hunter2"
def test_re_encrypt_row_idempotent_when_previous_key_also_decrypts(self):
"""
When the supplied previous_secret_key can also decrypt the value
(e.g. re-running after a successful rotation while still passing
the original secret, or mistakenly passing the current secret as
the previous one), the row must still be skipped. Idempotency is
anchored on whether the current key can already read the data,
not on whether the previous key fails to decrypt.
"""
from unittest.mock import MagicMock
from sqlalchemy.engine import make_url
dialect = make_url("sqlite://").get_dialect()
# Previous key == current key — this is the "re-run with no actual
# rotation" scenario.
migrator = SecretsMigrator(self.app.config["SECRET_KEY"])
migrator._dialect = dialect # noqa: SLF001
field = encrypted_field_factory.create(String(1024))
ciphertext = field.process_bind_param("hunter2", dialect)
conn = MagicMock()
row = {"uuid": b"\x00" * 16, "configuration": ciphertext}
stats = ReEncryptStats()
migrator._re_encrypt_row( # noqa: SLF001
conn,
row,
"semantic_layers",
{"configuration": field},
["uuid"],
stats,
)
assert conn.execute.call_count == 0, (
"Idempotency must hold even when previous_secret_key can also "
"decrypt the value"
)
assert stats == ReEncryptStats(re_encrypted=0, skipped=1, failed=0)
def test_re_encrypt_row_counts_failures_without_raising(self):
"""
Per-column failures are accumulated onto the stats counter so the
caller can emit a summary covering every row. The row method itself
must not raise — run() decides whether to abort based on the totals.
"""
from unittest.mock import MagicMock
from sqlalchemy.engine import make_url
dialect = make_url("sqlite://").get_dialect()
migrator = SecretsMigrator("WRONG_PREVIOUS_KEY_abcdef")
migrator._dialect = dialect # noqa: SLF001
field = encrypted_field_factory.create(String(1024))
conn = MagicMock()
row = {"uuid": b"\x00" * 16, "configuration": b"not-valid-ciphertext"}
stats = ReEncryptStats()
migrator._re_encrypt_row( # noqa: SLF001
conn,
row,
"semantic_layers",
{"configuration": field},
["uuid"],
stats,
)
assert conn.execute.call_count == 0
assert stats == ReEncryptStats(re_encrypted=0, skipped=0, failed=1)
def test_re_encrypt_row_counts_nulls_separately(self):
"""
NULL column values are not encrypted and therefore have nothing to
migrate. They must be counted as ``null`` (not ``skipped``) and
must not trigger an UPDATE, regardless of which key is supplied as
the previous secret.
"""
from unittest.mock import MagicMock
from sqlalchemy.engine import make_url
dialect = make_url("sqlite://").get_dialect()
migrator = SecretsMigrator("WRONG_PREVIOUS_KEY_abcdef")
migrator._dialect = dialect # noqa: SLF001
field = encrypted_field_factory.create(String(1024))
conn = MagicMock()
row = {"uuid": b"\x00" * 16, "configuration": None}
stats = ReEncryptStats()
migrator._re_encrypt_row( # noqa: SLF001
conn,
row,
"semantic_layers",
{"configuration": field},
["uuid"],
stats,
)
assert conn.execute.call_count == 0
assert stats == ReEncryptStats(re_encrypted=0, skipped=0, null=1, failed=0)

View File

@@ -32,6 +32,7 @@ from superset.mcp_service.chart.schemas import (
FilterConfig,
LegendConfig,
TableChartConfig,
TablePreview,
UpdateChartPreviewRequest,
XYChartConfig,
)
@@ -698,6 +699,79 @@ class TestUpdateChartPreview:
assert result["warnings"] == []
mock_get_previous_form_data.assert_called_once_with("valid_key_12345")
@patch.object(update_chart_preview_module, "validate_and_compile")
@patch.object(update_chart_preview_module, "has_dataset_access", return_value=True)
@patch("superset.daos.dataset.DatasetDAO.find_by_id")
@patch.object(update_chart_preview_module, "generate_preview_from_form_data")
@patch.object(update_chart_preview_module, "analyze_chart_semantics")
@patch.object(update_chart_preview_module, "analyze_chart_capabilities")
@patch.object(update_chart_preview_module, "generate_explore_link")
@patch.object(update_chart_preview_module, "_get_previous_form_data")
@patch("superset.mcp_service.auth.get_user_from_request")
@pytest.mark.asyncio
async def test_returns_requested_table_preview(
self,
mock_get_user_from_request,
mock_get_previous_form_data,
mock_generate_explore_link,
mock_analyze_chart_capabilities,
mock_analyze_chart_semantics,
mock_generate_preview_from_form_data,
mock_find_by_id,
unused_access_mock,
mock_validate_and_compile,
) -> None:
"""Preview updates honor supported preview_formats."""
mock_user = Mock()
mock_user.id = 1
mock_get_user_from_request.return_value = mock_user
mock_find_by_id.return_value = _mock_dataset(id=3)
mock_validate_and_compile.return_value = Mock(success=True)
mock_get_previous_form_data.return_value = {}
mock_generate_explore_link.return_value = (
"http://localhost:8088/explore/?form_data_key=new_preview_key"
)
mock_analyze_chart_capabilities.return_value = None
mock_analyze_chart_semantics.return_value = None
table_preview = TablePreview(
table_data="Table Preview",
row_count=1,
supports_sorting=True,
)
expected_table_preview = {
"type": "table",
"table_data": "Table Preview",
"row_count": 1,
"supports_sorting": True,
}
mock_generate_preview_from_form_data.return_value = table_preview
request = UpdateChartPreviewRequest(
form_data_key="valid_key_12345",
dataset_id=3,
config=TableChartConfig(
chart_type="table",
columns=[
ColumnRef(name="country", label="Country"),
ColumnRef(name="sales", label="Sales", aggregate="SUM"),
],
),
generate_preview=True,
preview_formats=["url", "table"],
)
result = update_chart_preview_module.update_chart_preview(
request=request, ctx=Mock()
)
assert result["success"] is True
assert result["previews"] == {"table": expected_table_preview}
mock_generate_preview_from_form_data.assert_called_once()
preview_kwargs = mock_generate_preview_from_form_data.call_args.kwargs
assert preview_kwargs["dataset_id"] == 3
assert preview_kwargs["preview_format"] == "table"
assert preview_kwargs["form_data"]["viz_type"] == "table"
class TestUpdateChartPreviewValidation:
"""Tier-1 validation gate and dataset access checks."""