mirror of
https://github.com/apache/superset.git
synced 2026-07-28 09:32:28 +00:00
Compare commits
2 Commits
dependabot
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf9bb70100 | ||
|
|
21cd451a9d |
2
.github/workflows/bump-python-package.yml
vendored
2
.github/workflows/bump-python-package.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-supersetbot/
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }}
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@e0647621c2984b5ed2f768cb892365bf2a616ad1 # v4.37.2
|
||||
uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
||||
14
.github/workflows/superset-frontend.yml
vendored
14
.github/workflows/superset-frontend.yml
vendored
@@ -122,13 +122,25 @@ jobs:
|
||||
pattern: coverage-artifacts-*
|
||||
path: coverage/
|
||||
|
||||
- name: Reorganize test result reports
|
||||
run: |
|
||||
find coverage/
|
||||
for i in {1..8}; do
|
||||
mv coverage/coverage-artifacts-${i}/coverage-final.json coverage/coverage-shard-${i}.json
|
||||
done
|
||||
shell: bash
|
||||
|
||||
- name: Merge Code Coverage
|
||||
run: npx nyc merge coverage/ merged-output/coverage-summary.json
|
||||
|
||||
- name: Upload Code Coverage
|
||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||
with:
|
||||
flags: javascript
|
||||
use_oidc: true
|
||||
verbose: true
|
||||
directory: coverage
|
||||
disable_search: true
|
||||
files: merged-output/coverage-summary.json
|
||||
slug: apache/superset
|
||||
|
||||
lint-frontend:
|
||||
|
||||
@@ -144,7 +144,7 @@ repos:
|
||||
git fetch --no-recurse-submodules origin "$TARGET_BRANCH" 2>/dev/null || true
|
||||
fi
|
||||
BASE=$(git merge-base origin/"$TARGET_BRANCH" HEAD 2>/dev/null) || BASE="HEAD"
|
||||
files=$(git diff --name-only --diff-filter=ACM "$BASE"..HEAD 2>/dev/null | grep '^superset/.*\.py$' | grep -v '^superset/migrations/' || true)
|
||||
files=$(git diff --name-only --diff-filter=ACM "$BASE"..HEAD 2>/dev/null | grep '^superset/.*\.py$' || true)
|
||||
if [ -n "$files" ]; then
|
||||
pylint --rcfile=.pylintrc --load-plugins=superset.extensions.pylint --reports=no $files
|
||||
else
|
||||
|
||||
10
UPDATING.md
10
UPDATING.md
@@ -358,16 +358,6 @@ A read-only companion to the version-history endpoints: each entity type gains a
|
||||
|
||||
Authorization reuses the resource's `can_read` permission and per-object `raise_for_access`; related-entity rows are visibility-filtered to what the caller may see. The stream is empty unless version capture is on (`ENABLE_VERSIONING_CAPTURE`).
|
||||
|
||||
### Version-history retention (pruning)
|
||||
|
||||
Entity version history (the `version_transaction` / `*_version` shadow tables that back version capture) is aged out by a nightly Celery beat task, `version_history.prune_old_versions` (`superset.tasks.version_history_retention`).
|
||||
|
||||
| Key | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `SUPERSET_VERSION_HISTORY_RETENTION_DAYS` | `30` | Version rows whose owning `version_transaction.issued_at` is older than this many days are pruned. Each entity's live row (`end_transaction_id IS NULL`) is always preserved, as are the live rows of its children and associations; closed historical rows (including the baseline) age out. Set to `0` or a negative value to disable pruning. |
|
||||
|
||||
The task ships in the default `CeleryConfig.beat_schedule`; a deployment that overrides `CELERY_CONFIG` without inheriting the default will log a startup warning that the prune task is absent (so it never silently stops running). Retention only prunes whatever history exists — capture itself is gated separately by `ENABLE_VERSIONING_CAPTURE` (ships off).
|
||||
|
||||
### Webhook alerts/reports block private/internal hosts by default
|
||||
|
||||
Webhook alert/report dispatch (`WebhookNotification.send`) now validates the target URL's host against the same private/internal-IP block applied to dataset import URLs. If the resolved host is in a loopback, link-local, private (RFC-1918), shared-CGNAT, or multicast range, the webhook is rejected with `NotificationParamException`.
|
||||
|
||||
@@ -53,14 +53,14 @@
|
||||
"@emotion/core": "^11.0.0",
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@fontsource/fira-code": "^5.3.0",
|
||||
"@fontsource/ibm-plex-mono": "^5.3.0",
|
||||
"@fontsource/inter": "^5.3.0",
|
||||
"@fontsource/fira-code": "^5.2.7",
|
||||
"@fontsource/ibm-plex-mono": "^5.2.7",
|
||||
"@fontsource/inter": "^5.2.8",
|
||||
"@mdx-js/react": "^3.1.1",
|
||||
"@saucelabs/theme-github-codeblock": "^0.3.0",
|
||||
"@storybook/addon-docs": "^10.5.0",
|
||||
"@superset-ui/core": "^0.20.4",
|
||||
"@swc/core": "^1.15.46",
|
||||
"@swc/core": "^1.15.43",
|
||||
"antd": "^6.5.1",
|
||||
"baseline-browser-mapping": "^2.10.43",
|
||||
"caniuse-lite": "^1.0.30001806",
|
||||
@@ -78,7 +78,7 @@
|
||||
"remark-import-partial": "^0.0.2",
|
||||
"reselect": "^5.2.0",
|
||||
"storybook": "^10.5.0",
|
||||
"swagger-ui-react": "^5.32.9",
|
||||
"swagger-ui-react": "^5.32.8",
|
||||
"swc-loader": "^0.2.7",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"unist-util-visit": "^5.1.0"
|
||||
|
||||
174
docs/yarn.lock
174
docs/yarn.lock
@@ -2529,20 +2529,20 @@
|
||||
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-5.5.3.tgz#18e3af6b8eae7984072bbeb0c0858474d7c4cefe"
|
||||
integrity sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==
|
||||
|
||||
"@fontsource/fira-code@^5.3.0":
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/fira-code/-/fira-code-5.3.0.tgz#487475cedfa1f7ba7650810ddce00b6c7b1b7a25"
|
||||
integrity sha512-EJL968RJRkakubAj/coU8pSUaeTE5UNoRjtzAr6kGiSZ3jWuN8/AKWHwym/PFUaQL1q7IL/H+EXs4358YhrTBQ==
|
||||
"@fontsource/fira-code@^5.2.7":
|
||||
version "5.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/fira-code/-/fira-code-5.2.7.tgz#9ecbd909d53e7196a5d895b601747fe34491fc6a"
|
||||
integrity sha512-tnB9NNund9TwIym8/7DMJe573nlPEQb+fKUV5GL8TBYXjIhDvL0D7mgmNVNQUPhXp+R7RylQeiBdkA4EbOHPGQ==
|
||||
|
||||
"@fontsource/ibm-plex-mono@^5.3.0":
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.3.0.tgz#1879699d104602d5331e28e103f33c3b1b766b17"
|
||||
integrity sha512-eTgnZjZEGk1QtD3ZstF+Vclo2HLAni8YMy34/DxllwZvyz1lR/1RF/xTiAquOBO7MvqBx8D2Ig2WCPMVfdZu7Q==
|
||||
"@fontsource/ibm-plex-mono@^5.2.7":
|
||||
version "5.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.2.7.tgz#ef5b6f052115fdf6666208a5f8a0f13fcd7ba1fd"
|
||||
integrity sha512-MKAb8qV+CaiMQn2B0dIi1OV3565NYzp3WN5b4oT6LTkk+F0jR6j0ZN+5BKJiIhffDC3rtBULsYZE65+0018z9w==
|
||||
|
||||
"@fontsource/inter@^5.3.0":
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.3.0.tgz#866278dc2357659f8be1755c8b67f29d3697b440"
|
||||
integrity sha512-RofMylZmjlJEfELXeNHFWBRcSs75rGU/6bV2S2jfnvv/3rPXPGe0LgUJTklcHZ9lM4OZmAVFhcJPnACfb91A3g==
|
||||
"@fontsource/inter@^5.2.8":
|
||||
version "5.2.8"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.2.8.tgz#10c95d877d972c7de5bd4592309d42fb6a5e1a5b"
|
||||
integrity sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==
|
||||
|
||||
"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
|
||||
version "9.3.0"
|
||||
@@ -4697,86 +4697,86 @@
|
||||
dependencies:
|
||||
apg-lite "^1.0.4"
|
||||
|
||||
"@swc/core-darwin-arm64@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.46.tgz#393903c7eda790dbd89abd8fa0afdd9041543e5f"
|
||||
integrity sha512-IsISIT22EfktVJrlvIpnAxG2u/A9aob9l99HMlx80x72WlFmFPk1V3UhkEzx86eJP8hw049KTFv/RISho2cq2Q==
|
||||
"@swc/core-darwin-arm64@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz#386294f8427dde2df1a70dd0a5826d67af70e996"
|
||||
integrity sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==
|
||||
|
||||
"@swc/core-darwin-x64@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.46.tgz#ddf16787e320636621180df480a3490fd9a868ca"
|
||||
integrity sha512-4Tj4ppVIPCmUMpmGFiGtyEriwLyJ+yi/US4WfBrP/ok8COGddDZXLEzQETnKyK46mjvr1v0jevrS23zjoff7vA==
|
||||
"@swc/core-darwin-x64@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz#c4823529c424e2ae25b7eb786438474741521fcb"
|
||||
integrity sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.46.tgz#7bee01b7311c43b913771ef9c7012931871de73b"
|
||||
integrity sha512-i8tUGnNjyOgMmfmgFSg4aeJLQoFyfpIHK5FjpQAwpRyQIqEUB2w1e8zIDQzY1WhOxx8NoS1S5iUL813Un4Sf5A==
|
||||
"@swc/core-linux-arm-gnueabihf@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz#c0a0ed17cffc5d4af192935667f12f05feeb39f9"
|
||||
integrity sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==
|
||||
|
||||
"@swc/core-linux-arm64-gnu@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.46.tgz#964596d757d18f04a02873d85a3660416c09c187"
|
||||
integrity sha512-c0OnhqzdhfOvv6qhNCcByepB+sNYOGZyhtr2Qa6ZCHvAWTYhSRw4j/u92Stue9PbZ/6q74b9nHzi76+kVzqQHQ==
|
||||
"@swc/core-linux-arm64-gnu@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz#1eb2d9c5eeee5bb9d00599b475ddc31dc2870d22"
|
||||
integrity sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==
|
||||
|
||||
"@swc/core-linux-arm64-musl@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.46.tgz#213d3ece772689a8166ed51064836346c6ce1c2a"
|
||||
integrity sha512-imyRpNEcUzFQFV2LE4jL68ErvmKEuZCbvZru77iQREunJ+bR4i658cupTgtG1mLYM3F1Tzy3Sb9xYb02KghWTg==
|
||||
"@swc/core-linux-arm64-musl@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz#ea6b5c38088f3921a57922d3931b2d74fd23a9fd"
|
||||
integrity sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==
|
||||
|
||||
"@swc/core-linux-ppc64-gnu@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.46.tgz#4d2ec554103c6bef60cc1e294f374ea5a5edaf78"
|
||||
integrity sha512-ctEfcl/HcUeomK33cbySiHZm98GEDIxTm1EkpBsYCiHxElYBzvTXVeuQT2YwbUXn9XCrjiw4ipyUNk33k26qRg==
|
||||
"@swc/core-linux-ppc64-gnu@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz#538fac30bbd5f1e678bb7bac9ccc62246a6f6d7a"
|
||||
integrity sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==
|
||||
|
||||
"@swc/core-linux-s390x-gnu@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.46.tgz#097a19792ec22e2f51f6bfac02da1e0b3f5e5bb1"
|
||||
integrity sha512-DxlMdnt84TtRVTv7WL/thWyz9+QU8QZNNoAP9rrk0P68LziuhfePp8MjQ44zIprpTHTsEwyziIuGUUN5iSC1bQ==
|
||||
"@swc/core-linux-s390x-gnu@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz#ee564b45f3f578b1fc82136c4dab163189316641"
|
||||
integrity sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==
|
||||
|
||||
"@swc/core-linux-x64-gnu@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.46.tgz#39c1ca215f9ca643a4aa3ca6250cc38ba5f5c673"
|
||||
integrity sha512-SKxI7J6t90XPl8hRUqtJi9NfGdunN/E/vZMc7Bc0figeRdOPDBT+Tm8g7cx9xM0T0mewh2l+8dewa3Am27/P+A==
|
||||
"@swc/core-linux-x64-gnu@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz#e6e3bfea76921c7f5e16d50a126615f2e04ce1c8"
|
||||
integrity sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==
|
||||
|
||||
"@swc/core-linux-x64-musl@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.46.tgz#323a720bc965fffeedacdc3167b46a291553b5e0"
|
||||
integrity sha512-qj9T6B7bosI0VEsrWOVXZN1OXxS8Tp63ywyrLxNdOycnUtLdkgYcoBsN5y8ImnDDsnwrEWZOy1e+J4xSe7mA3Q==
|
||||
"@swc/core-linux-x64-musl@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz#539f6f2721c0cc32e5db5cf0d453c82045f6662d"
|
||||
integrity sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==
|
||||
|
||||
"@swc/core-win32-arm64-msvc@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.46.tgz#9c2cfd2a59be74671a018097b8914f8cfbcc698d"
|
||||
integrity sha512-8p7l4c3LU+eA5g9Et1JPhNeMC1oQwXTGU+uah8DPIBX7YXzqswvaBtyKVmXefVGi/DJU1x3YJsc3mbAp9aWzSQ==
|
||||
"@swc/core-win32-arm64-msvc@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz#b7bb6b611d484ac19d0ee21469e7012d646c28b5"
|
||||
integrity sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==
|
||||
|
||||
"@swc/core-win32-ia32-msvc@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.46.tgz#bd7bd009a47b0f9826212e7ed36385d32fe193d8"
|
||||
integrity sha512-tUEnfr3Bn9u6FOjUb3PN9p+09qZC2j+wNDLKHzXXZn22rqGcUqR/ohCRSS+nG9B9+X+U+3FewNEHJkTmdIvMjQ==
|
||||
"@swc/core-win32-ia32-msvc@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz#e5b25722a7d27bb0c9a9bdee7863f29c8674364e"
|
||||
integrity sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==
|
||||
|
||||
"@swc/core-win32-x64-msvc@1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.46.tgz#8371845a5bdb330cf05b009f602bb8c4636c6beb"
|
||||
integrity sha512-Vux7UDzBJYQggSuPfcl2w9iu+IJpgpRCxHzgCaVkELnAXAE4XZMOTX9HNcaNiwfeIDqdu2rkr69RuDm6wY8neA==
|
||||
"@swc/core-win32-x64-msvc@1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz#d28842621201c345383d468d40c09648b6cd6e68"
|
||||
integrity sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==
|
||||
|
||||
"@swc/core@^1.15.40", "@swc/core@^1.15.46":
|
||||
version "1.15.46"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.46.tgz#8acc0f68ee55010fdc876adf2a8faf0b097c681b"
|
||||
integrity sha512-Ri3em2mBpq3h2zSPliCYl63otDGqek8PPEfv2nWgRQEbZ/VBCNyypVTVQ6cEbTCXBhy+WE2T3fQb08moIyuYaw==
|
||||
"@swc/core@^1.15.40", "@swc/core@^1.15.43":
|
||||
version "1.15.43"
|
||||
resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.43.tgz#653e6573968fd5c74163b9885ea0a933012c9f22"
|
||||
integrity sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==
|
||||
dependencies:
|
||||
"@swc/counter" "^0.1.3"
|
||||
"@swc/types" "^0.1.27"
|
||||
optionalDependencies:
|
||||
"@swc/core-darwin-arm64" "1.15.46"
|
||||
"@swc/core-darwin-x64" "1.15.46"
|
||||
"@swc/core-linux-arm-gnueabihf" "1.15.46"
|
||||
"@swc/core-linux-arm64-gnu" "1.15.46"
|
||||
"@swc/core-linux-arm64-musl" "1.15.46"
|
||||
"@swc/core-linux-ppc64-gnu" "1.15.46"
|
||||
"@swc/core-linux-s390x-gnu" "1.15.46"
|
||||
"@swc/core-linux-x64-gnu" "1.15.46"
|
||||
"@swc/core-linux-x64-musl" "1.15.46"
|
||||
"@swc/core-win32-arm64-msvc" "1.15.46"
|
||||
"@swc/core-win32-ia32-msvc" "1.15.46"
|
||||
"@swc/core-win32-x64-msvc" "1.15.46"
|
||||
"@swc/core-darwin-arm64" "1.15.43"
|
||||
"@swc/core-darwin-x64" "1.15.43"
|
||||
"@swc/core-linux-arm-gnueabihf" "1.15.43"
|
||||
"@swc/core-linux-arm64-gnu" "1.15.43"
|
||||
"@swc/core-linux-arm64-musl" "1.15.43"
|
||||
"@swc/core-linux-ppc64-gnu" "1.15.43"
|
||||
"@swc/core-linux-s390x-gnu" "1.15.43"
|
||||
"@swc/core-linux-x64-gnu" "1.15.43"
|
||||
"@swc/core-linux-x64-musl" "1.15.43"
|
||||
"@swc/core-win32-arm64-msvc" "1.15.43"
|
||||
"@swc/core-win32-ia32-msvc" "1.15.43"
|
||||
"@swc/core-win32-x64-msvc" "1.15.43"
|
||||
|
||||
"@swc/counter@^0.1.3":
|
||||
version "0.1.3"
|
||||
@@ -7007,7 +7007,7 @@ copy-text-to-clipboard@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.2.tgz#99bc79db3f2d355ec33a08d573aff6804491ddb9"
|
||||
integrity sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==
|
||||
|
||||
copy-to-clipboard@^3.3.3:
|
||||
copy-to-clipboard@^3.3.1:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0"
|
||||
integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==
|
||||
@@ -13243,12 +13243,12 @@ rc@1.2.8:
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
react-copy-to-clipboard@5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.1.tgz#76adb8be03616e99692fcf3f762365ed3fb5ff16"
|
||||
integrity sha512-s+HrzLyJBxrpGTYXF15dTgMjAJpEPZT/Yp6NytAtZMRngejxt6Pt5WrfFxLAcsqUDU6sY1Jz6tyHwIicE1U2Xg==
|
||||
react-copy-to-clipboard@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz#09aae5ec4c62750ccb2e6421a58725eabc41255c"
|
||||
integrity sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==
|
||||
dependencies:
|
||||
copy-to-clipboard "^3.3.3"
|
||||
copy-to-clipboard "^3.3.1"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
react-debounce-input@=3.3.0:
|
||||
@@ -14925,10 +14925,10 @@ swagger-client@^3.37.4:
|
||||
ramda "^0.30.1"
|
||||
ramda-adjunct "^5.1.0"
|
||||
|
||||
swagger-ui-react@^5.32.9:
|
||||
version "5.32.9"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-react/-/swagger-ui-react-5.32.9.tgz#d0e8521091b270e35f8d87771fba49eede425b38"
|
||||
integrity sha512-zs6PG4G6XEWG2evKHSwx32nWXIlk48a9Hw9YS9hlt55O5W0FM1cpltMrM/AnU+mohdnV7oEx0ap2TaG3fbfLIA==
|
||||
swagger-ui-react@^5.32.8:
|
||||
version "5.32.8"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-react/-/swagger-ui-react-5.32.8.tgz#0608b45cf552f33fcc9b3fc5e07740c9a854861f"
|
||||
integrity sha512-Cstx4Tq8fT5l2TBxHxts8pG+ks0qKSkuO1pwUwgrQQiZ241Mqs+KUODLVIonsYXL/gqX143rkcipUa4d0Rid7w==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.27.1"
|
||||
"@scarf/scarf" "=1.4.0"
|
||||
@@ -14946,7 +14946,7 @@ swagger-ui-react@^5.32.9:
|
||||
prop-types "^15.8.1"
|
||||
randexp "^0.5.3"
|
||||
randombytes "^2.1.0"
|
||||
react-copy-to-clipboard "5.1.1"
|
||||
react-copy-to-clipboard "5.1.0"
|
||||
react-debounce-input "=3.3.0"
|
||||
react-immutable-proptypes "2.2.0"
|
||||
react-immutable-pure-component "^2.2.0"
|
||||
|
||||
@@ -29,7 +29,7 @@ maintainers:
|
||||
- name: craig-rueda
|
||||
email: craig@craigrueda.com
|
||||
url: https://github.com/craig-rueda
|
||||
version: 0.22.4 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
|
||||
version: 0.22.3 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
version: 16.7.27
|
||||
|
||||
@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
|
||||
|
||||
# superset
|
||||
|
||||

|
||||

|
||||
|
||||
Apache Superset is a modern, enterprise-ready business intelligence web application
|
||||
|
||||
@@ -159,10 +159,6 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| init.extraInitContainers | list | `[]` | Extra init containers appended after init job initContainers |
|
||||
| init.initContainers | list | a container waiting for postgres | List of initContainers |
|
||||
| init.initscript | string | unused; kept for backwards-compatibility only | DEPRECATED: this field is no longer used by the chart. The init script is rendered entirely from the internal `superset.initScript` template (which runs `superset db upgrade`, `superset init`, admin creation, and examples). Any customization placed here is silently ignored. See UPGRADING.md. |
|
||||
| init.istio | object | `{"disableSidecarInjection":false,"quitEndpoint":"http://localhost:15020/quitquitquit","terminateSidecarOnExit":false}` | Configuration for compatibility with the Istio service mesh. Without these mitigations, when the init-db Job runs in a namespace with automatic Istio sidecar injection enabled, the injected envoy-proxy container keeps running after the init container has exited, preventing the Job from ever reaching the Completed state. See https://github.com/apache/superset/issues/25798 |
|
||||
| init.istio.disableSidecarInjection | bool | `false` | When true, adds the `sidecar.istio.io/inject: "false"` label to the init job pod template, opting it out of Istio automatic sidecar injection. This is the recommended fix when the cluster's mesh policy allows opting out per pod. |
|
||||
| init.istio.quitEndpoint | string | `"http://localhost:15020/quitquitquit"` | Endpoint that the trap POSTs to in order to terminate the sidecar. The default matches the standard Istio pilot-agent admin port. |
|
||||
| init.istio.terminateSidecarOnExit | bool | `false` | When true, the rendered `superset_init.sh` script (from the internal `superset.initScript` template) registers an `EXIT` trap that POSTs to the Istio pilot-agent's `/quitquitquit` endpoint after the init logic finishes, gracefully terminating an injected envoy-proxy sidecar so the Job can complete. Enable this when sidecar injection cannot be disabled per pod (e.g. when enforced by a cluster-wide Istio policy). Note: requires `curl` to be available in the init container image (it is included in the default `apache/superset` image) and only takes effect when `init.command` sources the rendered `superset_init.sh`. |
|
||||
| init.jobAnnotations."helm.sh/hook" | string | `"post-install,post-upgrade"` | |
|
||||
| init.jobAnnotations."helm.sh/hook-delete-policy" | string | `"before-hook-creation"` | |
|
||||
| init.loadExamples | bool | `false` | |
|
||||
|
||||
@@ -685,14 +685,6 @@ TALISMAN_CONFIG = {
|
||||
{{- define "superset.initScript" -}}
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
{{- if dig "istio" "terminateSidecarOnExit" false .Values.init }}
|
||||
# Notify the Istio pilot-agent sidecar to exit when this script completes
|
||||
# (whether successfully or via `set -e`), so that the Job can reach the
|
||||
# Completed state instead of hanging on a still-running envoy-proxy.
|
||||
# See https://github.com/apache/superset/issues/25798
|
||||
ISTIO_QUIT_ENDPOINT={{ dig "istio" "quitEndpoint" "http://localhost:15020/quitquitquit" .Values.init | replace "'" "'\\''" | squote }}
|
||||
trap 'rc=$?; curl -fsS -m 5 -X POST "$ISTIO_QUIT_ENDPOINT" >/dev/null 2>&1 || echo "WARNING: failed to notify Istio sidecar at $ISTIO_QUIT_ENDPOINT to quit; the Job may hang if sidecar injection is active" >&2; exit $rc' EXIT
|
||||
{{- end }}
|
||||
echo "Upgrading DB schema..."
|
||||
superset db upgrade
|
||||
echo "Initializing roles and permissions..."
|
||||
|
||||
@@ -35,7 +35,6 @@ spec:
|
||||
{{- if .Values.init.podAnnotations }}
|
||||
annotations: {{- toYaml .Values.init.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- $istioDisableInject := dig "istio" "disableSidecarInjection" false .Values.init }}
|
||||
labels:
|
||||
{{- include "superset.componentSelectorLabels" (dict "component" "init" "root" .) | nindent 8 }}
|
||||
job: {{ template "superset.fullname" . }}-init-db
|
||||
@@ -45,9 +44,6 @@ spec:
|
||||
{{- if .Values.init.podLabels }}
|
||||
{{- toYaml .Values.init.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if $istioDisableInject }}
|
||||
sidecar.istio.io/inject: "false"
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.init.additionalPodSpec }}
|
||||
{{- tpl (toYaml .Values.init.additionalPodSpec) . | nindent 6 }}
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Renders the chart with `helm template` for several `init.istio.*` value
|
||||
# combinations and asserts that the relevant manifests contain (or omit)
|
||||
# the expected fields. Intended to be run from the chart directory or via
|
||||
# `bash helm/superset/tests/test-istio.sh` from the repo root.
|
||||
#
|
||||
# Covers the fix for:
|
||||
# https://github.com/apache/superset/issues/25798
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CHART_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
assert_contains() {
|
||||
local label="$1"
|
||||
local needle="$2"
|
||||
local haystack="$3"
|
||||
if grep -qF -- "${needle}" <<<"${haystack}"; then
|
||||
echo " PASS: ${label}"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo " FAIL: ${label}"
|
||||
echo " expected to contain: ${needle}"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_contains() {
|
||||
local label="$1"
|
||||
local needle="$2"
|
||||
local haystack="$3"
|
||||
if ! grep -qF -- "${needle}" <<<"${haystack}"; then
|
||||
echo " PASS: ${label}"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo " FAIL: ${label}"
|
||||
echo " expected NOT to contain: ${needle}"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
render() {
|
||||
helm template release "${CHART_DIR}" "$@"
|
||||
}
|
||||
|
||||
extract_init_job() {
|
||||
awk '
|
||||
/^# Source: superset\/templates\/init-job\.yaml/ { capture = 1 }
|
||||
capture && /^---$/ { capture = 0 }
|
||||
capture { print }
|
||||
' <<<"$1"
|
||||
}
|
||||
|
||||
extract_config_secret() {
|
||||
awk '
|
||||
/^# Source: superset\/templates\/secret-superset-config\.yaml/ { capture = 1 }
|
||||
capture && /^---$/ { capture = 0 }
|
||||
capture { print }
|
||||
' <<<"$1"
|
||||
}
|
||||
|
||||
echo "==> defaults: no istio mitigations applied"
|
||||
out_default="$(render)"
|
||||
init_job_default="$(extract_init_job "${out_default}")"
|
||||
config_default="$(extract_config_secret "${out_default}")"
|
||||
assert_not_contains "default does not set sidecar.istio.io/inject label" \
|
||||
'sidecar.istio.io/inject' "${init_job_default}"
|
||||
assert_not_contains "default initscript does not register quitquitquit trap" \
|
||||
'quitquitquit' "${config_default}"
|
||||
|
||||
echo "==> init.istio.disableSidecarInjection=true"
|
||||
out_disable="$(render --set init.istio.disableSidecarInjection=true)"
|
||||
init_job_disable="$(extract_init_job "${out_disable}")"
|
||||
config_disable="$(extract_config_secret "${out_disable}")"
|
||||
assert_contains "init job sets sidecar.istio.io/inject: \"false\"" \
|
||||
'sidecar.istio.io/inject: "false"' "${init_job_disable}"
|
||||
assert_not_contains "disableSidecarInjection alone does not add quitquitquit trap" \
|
||||
'quitquitquit' "${config_disable}"
|
||||
|
||||
echo "==> init.istio.terminateSidecarOnExit=true"
|
||||
out_terminate="$(render --set init.istio.terminateSidecarOnExit=true)"
|
||||
init_job_terminate="$(extract_init_job "${out_terminate}")"
|
||||
config_terminate="$(extract_config_secret "${out_terminate}")"
|
||||
assert_not_contains "terminateSidecarOnExit alone does not add inject label" \
|
||||
'sidecar.istio.io/inject' "${init_job_terminate}"
|
||||
assert_contains "initscript registers EXIT trap that calls quitquitquit" \
|
||||
"trap 'rc=\$?; curl -fsS -m 5 -X POST" "${config_terminate}"
|
||||
assert_contains "initscript trap targets the configured quit endpoint" \
|
||||
'http://localhost:15020/quitquitquit' "${config_terminate}"
|
||||
assert_contains "initscript trap binds to the EXIT signal" \
|
||||
"' EXIT" "${config_terminate}"
|
||||
|
||||
echo "==> init.istio.quitEndpoint override"
|
||||
out_endpoint="$(render --set init.istio.terminateSidecarOnExit=true \
|
||||
--set init.istio.quitEndpoint=http://127.0.0.1:15020/quitquitquit)"
|
||||
config_endpoint="$(extract_config_secret "${out_endpoint}")"
|
||||
assert_contains "trap honours custom quitEndpoint" \
|
||||
'http://127.0.0.1:15020/quitquitquit' "${config_endpoint}"
|
||||
|
||||
echo "==> both options combined"
|
||||
out_both="$(render --set init.istio.disableSidecarInjection=true \
|
||||
--set init.istio.terminateSidecarOnExit=true)"
|
||||
init_job_both="$(extract_init_job "${out_both}")"
|
||||
config_both="$(extract_config_secret "${out_both}")"
|
||||
assert_contains "combined: inject label present" \
|
||||
'sidecar.istio.io/inject: "false"' "${init_job_both}"
|
||||
assert_contains "combined: trap present" \
|
||||
'quitquitquit' "${config_both}"
|
||||
|
||||
echo "==> existing init.podLabels are preserved alongside istio label"
|
||||
out_labels="$(render --set init.istio.disableSidecarInjection=true \
|
||||
--set init.podLabels.team=data-platform)"
|
||||
init_job_labels="$(extract_init_job "${out_labels}")"
|
||||
assert_contains "user-supplied podLabel still rendered" \
|
||||
'team: data-platform' "${init_job_labels}"
|
||||
assert_contains "istio inject label rendered alongside" \
|
||||
'sidecar.istio.io/inject: "false"' "${init_job_labels}"
|
||||
|
||||
echo "==> init.istio explicitly overridden to null"
|
||||
out_null_istio="$(render --set init.istio=null)"
|
||||
init_job_null_istio="$(extract_init_job "${out_null_istio}")"
|
||||
config_null_istio="$(extract_config_secret "${out_null_istio}")"
|
||||
assert_not_contains "null init.istio does not set inject label" \
|
||||
'sidecar.istio.io/inject' "${init_job_null_istio}"
|
||||
assert_not_contains "null init.istio does not register quitquitquit trap" \
|
||||
'quitquitquit' "${config_null_istio}"
|
||||
|
||||
echo "==> EXIT trap propagates the script's exit code, not the notification's"
|
||||
# The trap's own curl call is best-effort (failures are logged with
|
||||
# `|| echo ... >&2`, not swallowed with `|| true`) and must not mask a
|
||||
# failed migration. Extract the two rendered lines and actually run them,
|
||||
# with curl pointed at a closed local port so the notification itself fails,
|
||||
# to make sure the wrapped script's real exit code still comes through.
|
||||
quit_endpoint_line="$(grep -F 'ISTIO_QUIT_ENDPOINT=' <<<"${config_terminate}" || true)"
|
||||
trap_line="$(grep -F "trap 'rc=\$?; curl" <<<"${config_terminate}" || true)"
|
||||
if [[ -z "${quit_endpoint_line}" || -z "${trap_line}" ]]; then
|
||||
echo " FAIL: script exit code (42) survives a failing quitquitquit notification"
|
||||
echo " could not locate the rendered ISTIO_QUIT_ENDPOINT/trap lines to exercise"
|
||||
fail=$((fail + 1))
|
||||
else
|
||||
set +e
|
||||
(
|
||||
eval "${quit_endpoint_line}"
|
||||
ISTIO_QUIT_ENDPOINT="http://127.0.0.1:1/quitquitquit"
|
||||
eval "${trap_line}"
|
||||
exit 42
|
||||
)
|
||||
trap_test_rc=$?
|
||||
set -e
|
||||
if [[ "${trap_test_rc}" -eq 42 ]]; then
|
||||
echo " PASS: script exit code (42) survives a failing quitquitquit notification"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo " FAIL: script exit code (42) survives a failing quitquitquit notification"
|
||||
echo " got exit code: ${trap_test_rc}"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "passed: ${pass}, failed: ${fail}"
|
||||
if [[ ${fail} -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -1241,31 +1241,6 @@ init:
|
||||
topologySpreadConstraints: []
|
||||
# -- Set priorityClassName for init job pods
|
||||
priorityClassName: ~
|
||||
# -- Configuration for compatibility with the Istio service mesh.
|
||||
# Without these mitigations, when the init-db Job runs in a namespace with
|
||||
# automatic Istio sidecar injection enabled, the injected envoy-proxy
|
||||
# container keeps running after the init container has exited, preventing
|
||||
# the Job from ever reaching the Completed state.
|
||||
# See https://github.com/apache/superset/issues/25798
|
||||
istio:
|
||||
# -- When true, adds the `sidecar.istio.io/inject: "false"` label to the
|
||||
# init job pod template, opting it out of Istio automatic sidecar
|
||||
# injection. This is the recommended fix when the cluster's mesh policy
|
||||
# allows opting out per pod.
|
||||
disableSidecarInjection: false
|
||||
# -- When true, the rendered `superset_init.sh` script (from the internal
|
||||
# `superset.initScript` template) registers an `EXIT` trap that POSTs to
|
||||
# the Istio pilot-agent's `/quitquitquit` endpoint after the init logic
|
||||
# finishes, gracefully terminating an injected envoy-proxy sidecar so
|
||||
# the Job can complete. Enable this when sidecar injection cannot be
|
||||
# disabled per pod (e.g. when enforced by a cluster-wide Istio policy).
|
||||
# Note: requires `curl` to be available in the init container image
|
||||
# (it is included in the default `apache/superset` image) and only
|
||||
# takes effect when `init.command` sources the rendered `superset_init.sh`.
|
||||
terminateSidecarOnExit: false
|
||||
# -- Endpoint that the trap POSTs to in order to terminate the sidecar.
|
||||
# The default matches the standard Istio pilot-agent admin port.
|
||||
quitEndpoint: "http://localhost:15020/quitquitquit"
|
||||
|
||||
# -- Configuration values for the postgresql dependency.
|
||||
# ref: https://github.com/bitnami/charts/tree/main/bitnami/postgresql
|
||||
|
||||
@@ -215,7 +215,6 @@
|
||||
"jsx-a11y/no-noninteractive-tabindex": "error",
|
||||
"jsx-a11y/no-redundant-roles": "error",
|
||||
"jsx-a11y/no-static-element-interactions": "error",
|
||||
"jsx-a11y/prefer-tag-over-role": "error",
|
||||
"jsx-a11y/role-has-required-aria-props": "error",
|
||||
"jsx-a11y/role-supports-aria-props": "error",
|
||||
"jsx-a11y/scope": "error",
|
||||
|
||||
346
superset-frontend/package-lock.json
generated
346
superset-frontend/package-lock.json
generated
@@ -30,9 +30,9 @@
|
||||
"@emotion/cache": "^11.4.0",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@fontsource/fira-code": "^5.3.0",
|
||||
"@fontsource/ibm-plex-mono": "^5.3.0",
|
||||
"@fontsource/inter": "^5.3.0",
|
||||
"@fontsource/fira-code": "^5.2.7",
|
||||
"@fontsource/ibm-plex-mono": "^5.2.7",
|
||||
"@fontsource/inter": "^5.2.8",
|
||||
"@googleapis/sheets": "^13.0.2",
|
||||
"@great-expectations/jsonforms-antd-renderers": "^2.2.10",
|
||||
"@jsonforms/core": "^3.7.0",
|
||||
@@ -45,9 +45,9 @@
|
||||
"@luma.gl/shadertools": "~9.2.5",
|
||||
"@luma.gl/webgl": "~9.2.5",
|
||||
"@reduxjs/toolkit": "^1.9.3",
|
||||
"@rjsf/core": "^6.7.0",
|
||||
"@rjsf/core": "^6.6.2",
|
||||
"@rjsf/utils": "^6.6.2",
|
||||
"@rjsf/validator-ajv8": "^6.7.0",
|
||||
"@rjsf/validator-ajv8": "^6.6.2",
|
||||
"@scarf/scarf": "^1.4.0",
|
||||
"@superset-ui/chart-controls": "file:./packages/superset-ui-chart-controls",
|
||||
"@superset-ui/core": "file:./packages/superset-ui-core",
|
||||
@@ -84,7 +84,7 @@
|
||||
"ag-grid-community": "36.0.1",
|
||||
"ag-grid-react": "36.0.1",
|
||||
"antd": "^6.5.1",
|
||||
"chrono-node": "^2.10.1",
|
||||
"chrono-node": "^2.10.0",
|
||||
"classnames": "^2.2.5",
|
||||
"content-disposition": "^2.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
@@ -121,7 +121,7 @@
|
||||
"query-string": "9.4.1",
|
||||
"re-resizable": "^6.11.2",
|
||||
"react": "^18.3.0",
|
||||
"react-arborist": "^3.15.0",
|
||||
"react-arborist": "^3.13.2",
|
||||
"react-checkbox-tree": "^1.8.0",
|
||||
"react-diff-viewer-continued": "^4.4.0",
|
||||
"react-dnd": "^11.1.3",
|
||||
@@ -187,7 +187,7 @@
|
||||
"@storybook/react-webpack5": "10.5.2",
|
||||
"@storybook/test-runner": "0.24.4",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@swc/core": "^1.15.46",
|
||||
"@swc/core": "^1.15.43",
|
||||
"@swc/plugin-emotion": "^14.15.0",
|
||||
"@swc/plugin-transform-imports": "^12.5.0",
|
||||
"@testing-library/dom": "^9.3.4",
|
||||
@@ -255,7 +255,7 @@
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"jsdom": "^29.1.1",
|
||||
"lerna": "^9.0.4",
|
||||
"lightningcss": "^1.33.0",
|
||||
"lightningcss": "^1.32.0",
|
||||
"mini-css-extract-plugin": "^2.10.2",
|
||||
"minimizer-webpack-plugin": "^5.6.1",
|
||||
"open-cli": "^9.0.0",
|
||||
@@ -269,12 +269,12 @@
|
||||
"react-refresh": "^0.18.0",
|
||||
"react-resizable": "^4.0.2",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"source-map": "^0.8.0",
|
||||
"source-map": "^0.7.6",
|
||||
"source-map-support": "^0.5.21",
|
||||
"speed-measure-webpack-plugin": "^1.6.0",
|
||||
"storybook": "10.5.2",
|
||||
"style-loader": "^4.0.0",
|
||||
"stylelint": "^17.14.1",
|
||||
"stylelint": "^17.14.0",
|
||||
"swc-loader": "^0.2.7",
|
||||
"ts-jest": "^29.4.11",
|
||||
"tscw-config": "^1.1.2",
|
||||
@@ -4064,27 +4064,27 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@fontsource/fira-code": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-5.3.0.tgz",
|
||||
"integrity": "sha512-EJL968RJRkakubAj/coU8pSUaeTE5UNoRjtzAr6kGiSZ3jWuN8/AKWHwym/PFUaQL1q7IL/H+EXs4358YhrTBQ==",
|
||||
"version": "5.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-5.2.7.tgz",
|
||||
"integrity": "sha512-tnB9NNund9TwIym8/7DMJe573nlPEQb+fKUV5GL8TBYXjIhDvL0D7mgmNVNQUPhXp+R7RylQeiBdkA4EbOHPGQ==",
|
||||
"license": "OFL-1.1",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ayuhito"
|
||||
}
|
||||
},
|
||||
"node_modules/@fontsource/ibm-plex-mono": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.3.0.tgz",
|
||||
"integrity": "sha512-eTgnZjZEGk1QtD3ZstF+Vclo2HLAni8YMy34/DxllwZvyz1lR/1RF/xTiAquOBO7MvqBx8D2Ig2WCPMVfdZu7Q==",
|
||||
"version": "5.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.2.7.tgz",
|
||||
"integrity": "sha512-MKAb8qV+CaiMQn2B0dIi1OV3565NYzp3WN5b4oT6LTkk+F0jR6j0ZN+5BKJiIhffDC3rtBULsYZE65+0018z9w==",
|
||||
"license": "OFL-1.1",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ayuhito"
|
||||
}
|
||||
},
|
||||
"node_modules/@fontsource/inter": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.3.0.tgz",
|
||||
"integrity": "sha512-RofMylZmjlJEfELXeNHFWBRcSs75rGU/6bV2S2jfnvv/3rPXPGe0LgUJTklcHZ9lM4OZmAVFhcJPnACfb91A3g==",
|
||||
"version": "5.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz",
|
||||
"integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==",
|
||||
"license": "OFL-1.1",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ayuhito"
|
||||
@@ -9040,16 +9040,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
|
||||
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnpm/config.env-replace": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
|
||||
@@ -9963,33 +9953,33 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rjsf/core": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/core/-/core-6.7.0.tgz",
|
||||
"integrity": "sha512-TdiiRf9H6R7mYXyRq1TQHhTSdX9lpvYHsfn1obWksICbZEg4jBFBh7BuyrcHhzGos6976GsLO4TTYw11fQUbpQ==",
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/core/-/core-6.6.2.tgz",
|
||||
"integrity": "sha512-rmckOHIc0N3Vu0egcjrm4aRnw4ETW1i4fGdm0m63qd/298zHfF7x2md2rDh8F5HLgoxW3X/LdvrCHcsD1lxbGw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"lodash": "^4.18.1",
|
||||
"lodash-es": "^4.18.1",
|
||||
"markdown-to-jsx": "^9.8.2",
|
||||
"markdown-to-jsx": "^9.8.1",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rjsf/utils": "^6.7.0",
|
||||
"@rjsf/utils": "^6.6.x",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/utils": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-6.7.1.tgz",
|
||||
"integrity": "sha512-6goBapMwyHcXvjLkCnFs4S3P1oKUi1H083BdPk4pDZALFWn5ZdG50ECNfHSddBmL3O0pyx1/WFq1C/MuR7Y54A==",
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-6.6.2.tgz",
|
||||
"integrity": "sha512-npqdWuuFmCkiXETrDLRx8a4EwDJoUdTTnGhJA/774bwDgT99u4nAEyXbJd75VuobunewcLm2FOS2cErD3e28cg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@x0k/json-schema-merge": "^1.0.3",
|
||||
"fast-equals": "^6.0.0",
|
||||
"fast-uri": "^4.1.1",
|
||||
"fast-uri": "^3.1.2",
|
||||
"jsonpointer": "^5.0.1",
|
||||
"lodash": "^4.18.1",
|
||||
"lodash-es": "^4.18.1",
|
||||
@@ -10003,9 +9993,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/validator-ajv8": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-6.7.0.tgz",
|
||||
"integrity": "sha512-GAo1BknPXVncMwCsnAg/UpLPvdzVuyB73FbdPe5p3VjefrdVFjbbtaYMsFUN5iGMKe5fIQOZD9ke5ajvTZjJPA==",
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-6.6.2.tgz",
|
||||
"integrity": "sha512-pi+CBfkXxyR1JhEveuwi7qA9NcqYvFSvadY8LkQDC6wP89bZS8TYXzolirvXC7okDdI3WCtPjx/FYnxYpXbj7Q==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"ajv": "^8.20.0",
|
||||
@@ -10017,7 +10007,7 @@
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rjsf/utils": "^6.7.0"
|
||||
"@rjsf/utils": "^6.6.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@rtsao/scc": {
|
||||
@@ -11122,9 +11112,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.46.tgz",
|
||||
"integrity": "sha512-Ri3em2mBpq3h2zSPliCYl63otDGqek8PPEfv2nWgRQEbZ/VBCNyypVTVQ6cEbTCXBhy+WE2T3fQb08moIyuYaw==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz",
|
||||
"integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
@@ -11140,18 +11130,18 @@
|
||||
"url": "https://opencollective.com/swc"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-darwin-arm64": "1.15.46",
|
||||
"@swc/core-darwin-x64": "1.15.46",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.15.46",
|
||||
"@swc/core-linux-arm64-gnu": "1.15.46",
|
||||
"@swc/core-linux-arm64-musl": "1.15.46",
|
||||
"@swc/core-linux-ppc64-gnu": "1.15.46",
|
||||
"@swc/core-linux-s390x-gnu": "1.15.46",
|
||||
"@swc/core-linux-x64-gnu": "1.15.46",
|
||||
"@swc/core-linux-x64-musl": "1.15.46",
|
||||
"@swc/core-win32-arm64-msvc": "1.15.46",
|
||||
"@swc/core-win32-ia32-msvc": "1.15.46",
|
||||
"@swc/core-win32-x64-msvc": "1.15.46"
|
||||
"@swc/core-darwin-arm64": "1.15.43",
|
||||
"@swc/core-darwin-x64": "1.15.43",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.15.43",
|
||||
"@swc/core-linux-arm64-gnu": "1.15.43",
|
||||
"@swc/core-linux-arm64-musl": "1.15.43",
|
||||
"@swc/core-linux-ppc64-gnu": "1.15.43",
|
||||
"@swc/core-linux-s390x-gnu": "1.15.43",
|
||||
"@swc/core-linux-x64-gnu": "1.15.43",
|
||||
"@swc/core-linux-x64-musl": "1.15.43",
|
||||
"@swc/core-win32-arm64-msvc": "1.15.43",
|
||||
"@swc/core-win32-ia32-msvc": "1.15.43",
|
||||
"@swc/core-win32-x64-msvc": "1.15.43"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/helpers": ">=0.5.17"
|
||||
@@ -11163,9 +11153,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.46.tgz",
|
||||
"integrity": "sha512-IsISIT22EfktVJrlvIpnAxG2u/A9aob9l99HMlx80x72WlFmFPk1V3UhkEzx86eJP8hw049KTFv/RISho2cq2Q==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz",
|
||||
"integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -11179,9 +11169,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-x64": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.46.tgz",
|
||||
"integrity": "sha512-4Tj4ppVIPCmUMpmGFiGtyEriwLyJ+yi/US4WfBrP/ok8COGddDZXLEzQETnKyK46mjvr1v0jevrS23zjoff7vA==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz",
|
||||
"integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -11195,9 +11185,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.46.tgz",
|
||||
"integrity": "sha512-i8tUGnNjyOgMmfmgFSg4aeJLQoFyfpIHK5FjpQAwpRyQIqEUB2w1e8zIDQzY1WhOxx8NoS1S5iUL813Un4Sf5A==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz",
|
||||
"integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -11211,15 +11201,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.46.tgz",
|
||||
"integrity": "sha512-c0OnhqzdhfOvv6qhNCcByepB+sNYOGZyhtr2Qa6ZCHvAWTYhSRw4j/u92Stue9PbZ/6q74b9nHzi76+kVzqQHQ==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz",
|
||||
"integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -11230,15 +11217,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-musl": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.46.tgz",
|
||||
"integrity": "sha512-imyRpNEcUzFQFV2LE4jL68ErvmKEuZCbvZru77iQREunJ+bR4i658cupTgtG1mLYM3F1Tzy3Sb9xYb02KghWTg==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz",
|
||||
"integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -11249,15 +11233,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-ppc64-gnu": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.46.tgz",
|
||||
"integrity": "sha512-ctEfcl/HcUeomK33cbySiHZm98GEDIxTm1EkpBsYCiHxElYBzvTXVeuQT2YwbUXn9XCrjiw4ipyUNk33k26qRg==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz",
|
||||
"integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -11268,15 +11249,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-s390x-gnu": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.46.tgz",
|
||||
"integrity": "sha512-DxlMdnt84TtRVTv7WL/thWyz9+QU8QZNNoAP9rrk0P68LziuhfePp8MjQ44zIprpTHTsEwyziIuGUUN5iSC1bQ==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz",
|
||||
"integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -11287,15 +11265,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.46.tgz",
|
||||
"integrity": "sha512-SKxI7J6t90XPl8hRUqtJi9NfGdunN/E/vZMc7Bc0figeRdOPDBT+Tm8g7cx9xM0T0mewh2l+8dewa3Am27/P+A==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz",
|
||||
"integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -11306,15 +11281,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-musl": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.46.tgz",
|
||||
"integrity": "sha512-qj9T6B7bosI0VEsrWOVXZN1OXxS8Tp63ywyrLxNdOycnUtLdkgYcoBsN5y8ImnDDsnwrEWZOy1e+J4xSe7mA3Q==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz",
|
||||
"integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -11325,9 +11297,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.46.tgz",
|
||||
"integrity": "sha512-8p7l4c3LU+eA5g9Et1JPhNeMC1oQwXTGU+uah8DPIBX7YXzqswvaBtyKVmXefVGi/DJU1x3YJsc3mbAp9aWzSQ==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz",
|
||||
"integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -11341,9 +11313,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.46.tgz",
|
||||
"integrity": "sha512-tUEnfr3Bn9u6FOjUb3PN9p+09qZC2j+wNDLKHzXXZn22rqGcUqR/ohCRSS+nG9B9+X+U+3FewNEHJkTmdIvMjQ==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz",
|
||||
"integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -11357,9 +11329,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-x64-msvc": {
|
||||
"version": "1.15.46",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.46.tgz",
|
||||
"integrity": "sha512-Vux7UDzBJYQggSuPfcl2w9iu+IJpgpRCxHzgCaVkELnAXAE4XZMOTX9HNcaNiwfeIDqdu2rkr69RuDm6wY8neA==",
|
||||
"version": "1.15.43",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz",
|
||||
"integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -12749,15 +12721,6 @@
|
||||
"source-map": "^0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/webpack-sources/node_modules/source-map": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
|
||||
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
|
||||
@@ -16781,9 +16744,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chrono-node": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-2.10.1.tgz",
|
||||
"integrity": "sha512-tPOsBzYVAK5zth+CiHCgp5NGeqRc4mMD8FPthQ5IxkgjPWWxIFdM5odnmfw//IRAzl6C++Xy8olQW7wn5qBR1g==",
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-2.10.0.tgz",
|
||||
"integrity": "sha512-5fJ4zr5W/5DEf+8FMPMXF2qk9L5dc1rAP9Pw009iMlKAghPgx5o7aUcnjEMe6PTwqiqTa5yzmfSm05EHuwr31Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
@@ -28341,9 +28304,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
|
||||
"integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
@@ -28357,23 +28320,23 @@
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"lightningcss-android-arm64": "1.33.0",
|
||||
"lightningcss-darwin-arm64": "1.33.0",
|
||||
"lightningcss-darwin-x64": "1.33.0",
|
||||
"lightningcss-freebsd-x64": "1.33.0",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.33.0",
|
||||
"lightningcss-linux-arm64-gnu": "1.33.0",
|
||||
"lightningcss-linux-arm64-musl": "1.33.0",
|
||||
"lightningcss-linux-x64-gnu": "1.33.0",
|
||||
"lightningcss-linux-x64-musl": "1.33.0",
|
||||
"lightningcss-win32-arm64-msvc": "1.33.0",
|
||||
"lightningcss-win32-x64-msvc": "1.33.0"
|
||||
"lightningcss-android-arm64": "1.32.0",
|
||||
"lightningcss-darwin-arm64": "1.32.0",
|
||||
"lightningcss-darwin-x64": "1.32.0",
|
||||
"lightningcss-freebsd-x64": "1.32.0",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.32.0",
|
||||
"lightningcss-linux-arm64-gnu": "1.32.0",
|
||||
"lightningcss-linux-arm64-musl": "1.32.0",
|
||||
"lightningcss-linux-x64-gnu": "1.32.0",
|
||||
"lightningcss-linux-x64-musl": "1.32.0",
|
||||
"lightningcss-win32-arm64-msvc": "1.32.0",
|
||||
"lightningcss-win32-x64-msvc": "1.32.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-android-arm64": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz",
|
||||
"integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
|
||||
"integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -28392,9 +28355,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-arm64": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz",
|
||||
"integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
|
||||
"integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -28413,9 +28376,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-x64": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz",
|
||||
"integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
|
||||
"integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -28434,9 +28397,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-freebsd-x64": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz",
|
||||
"integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
|
||||
"integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -28455,9 +28418,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz",
|
||||
"integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
|
||||
"integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -28476,16 +28439,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-gnu": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz",
|
||||
"integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
|
||||
"integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -28500,16 +28460,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-musl": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz",
|
||||
"integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
|
||||
"integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -28524,16 +28481,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-gnu": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz",
|
||||
"integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
|
||||
"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -28548,16 +28502,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-musl": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz",
|
||||
"integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
|
||||
"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -28572,9 +28523,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-arm64-msvc": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz",
|
||||
"integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
|
||||
"integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -28593,9 +28544,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-x64-msvc": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
|
||||
"integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
|
||||
"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -35199,9 +35150,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-arborist": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/react-arborist/-/react-arborist-3.15.0.tgz",
|
||||
"integrity": "sha512-wlXxTMtGW+HYZqeD7Sb7LVZ6W1saWJV6BwBfe/6VfBSQQHeeUEF0e0z/g3rejE/HpcbB+0pCeYYejNrxCod7jg==",
|
||||
"version": "3.13.2",
|
||||
"resolved": "https://registry.npmjs.org/react-arborist/-/react-arborist-3.13.2.tgz",
|
||||
"integrity": "sha512-Qa5h2MwBGflTZXsg8vXOHOonF04w31u6DyPL06iyboe+A8CMqxRxgI/Imd5mwTo679iNNJ4e7CuinJGe3rGqgg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-dnd": "^14.0.3",
|
||||
@@ -38103,10 +38054,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0.tgz",
|
||||
"integrity": "sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==",
|
||||
"dev": true,
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
|
||||
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
@@ -39210,9 +39160,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/stylelint": {
|
||||
"version": "17.14.1",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.14.1.tgz",
|
||||
"integrity": "sha512-xVQwyiuxALUBNB2fBe0tmNemg9KqLtdj3T64mioFDar79B2cU8LIyz+3KL6LdiHs9NkeNfwxpKSaIVOY8f112g==",
|
||||
"version": "17.14.0",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.14.0.tgz",
|
||||
"integrity": "sha512-8xkHPpdqYryeIsOgfsYTmr6cIeC4nLYWk5S8BPxpodq8mIuepggkMljsHewWfuAjj/+qpRKou2QerhjMH3iasg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -39228,7 +39178,7 @@
|
||||
"dependencies": {
|
||||
"@csstools/css-calc": "^3.2.1",
|
||||
"@csstools/css-parser-algorithms": "^4.0.0",
|
||||
"@csstools/css-syntax-patches-for-csstree": "^1.1.6",
|
||||
"@csstools/css-syntax-patches-for-csstree": "^1.1.5",
|
||||
"@csstools/css-tokenizer": "^4.0.0",
|
||||
"@csstools/media-query-list-parser": "^5.0.0",
|
||||
"@csstools/selector-resolve-nested": "^4.0.0",
|
||||
@@ -39240,9 +39190,9 @@
|
||||
"debug": "^4.4.3",
|
||||
"fast-glob": "^3.3.3",
|
||||
"fastest-levenshtein": "^1.0.16",
|
||||
"file-entry-cache": "^11.1.5",
|
||||
"file-entry-cache": "^11.1.3",
|
||||
"global-modules": "^2.0.0",
|
||||
"globby": "^16.2.1",
|
||||
"globby": "^16.2.0",
|
||||
"globjoin": "^0.1.4",
|
||||
"html-tags": "^5.1.0",
|
||||
"ignore": "^7.0.5",
|
||||
@@ -39252,12 +39202,12 @@
|
||||
"micromatch": "^4.0.8",
|
||||
"normalize-path": "^3.0.0",
|
||||
"picocolors": "^1.1.1",
|
||||
"postcss": "^8.5.16",
|
||||
"postcss": "^8.5.15",
|
||||
"postcss-safe-parser": "^7.0.1",
|
||||
"postcss-selector-parser": "^7.1.4",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"string-width": "^8.2.1",
|
||||
"supports-hyperlinks": "^4.5.0",
|
||||
"supports-hyperlinks": "^4.4.0",
|
||||
"svg-tags": "^1.0.0",
|
||||
"table": "^6.9.0",
|
||||
"write-file-atomic": "^7.0.1"
|
||||
|
||||
@@ -115,9 +115,9 @@
|
||||
"@emotion/cache": "^11.4.0",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@fontsource/fira-code": "^5.3.0",
|
||||
"@fontsource/ibm-plex-mono": "^5.3.0",
|
||||
"@fontsource/inter": "^5.3.0",
|
||||
"@fontsource/fira-code": "^5.2.7",
|
||||
"@fontsource/ibm-plex-mono": "^5.2.7",
|
||||
"@fontsource/inter": "^5.2.8",
|
||||
"@googleapis/sheets": "^13.0.2",
|
||||
"@great-expectations/jsonforms-antd-renderers": "^2.2.10",
|
||||
"@jsonforms/core": "^3.7.0",
|
||||
@@ -130,9 +130,9 @@
|
||||
"@luma.gl/shadertools": "~9.2.5",
|
||||
"@luma.gl/webgl": "~9.2.5",
|
||||
"@reduxjs/toolkit": "^1.9.3",
|
||||
"@rjsf/core": "^6.7.0",
|
||||
"@rjsf/core": "^6.6.2",
|
||||
"@rjsf/utils": "^6.6.2",
|
||||
"@rjsf/validator-ajv8": "^6.7.0",
|
||||
"@rjsf/validator-ajv8": "^6.6.2",
|
||||
"@scarf/scarf": "^1.4.0",
|
||||
"@superset-ui/chart-controls": "file:./packages/superset-ui-chart-controls",
|
||||
"@superset-ui/core": "file:./packages/superset-ui-core",
|
||||
@@ -169,7 +169,7 @@
|
||||
"ag-grid-community": "36.0.1",
|
||||
"ag-grid-react": "36.0.1",
|
||||
"antd": "^6.5.1",
|
||||
"chrono-node": "^2.10.1",
|
||||
"chrono-node": "^2.10.0",
|
||||
"classnames": "^2.2.5",
|
||||
"content-disposition": "^2.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
@@ -206,7 +206,7 @@
|
||||
"query-string": "9.4.1",
|
||||
"re-resizable": "^6.11.2",
|
||||
"react": "^18.3.0",
|
||||
"react-arborist": "^3.15.0",
|
||||
"react-arborist": "^3.13.2",
|
||||
"react-checkbox-tree": "^1.8.0",
|
||||
"react-diff-viewer-continued": "^4.4.0",
|
||||
"react-dnd": "^11.1.3",
|
||||
@@ -272,7 +272,7 @@
|
||||
"@storybook/react-webpack5": "10.5.2",
|
||||
"@storybook/test-runner": "0.24.4",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@swc/core": "^1.15.46",
|
||||
"@swc/core": "^1.15.43",
|
||||
"@swc/plugin-emotion": "^14.15.0",
|
||||
"@swc/plugin-transform-imports": "^12.5.0",
|
||||
"@testing-library/dom": "^9.3.4",
|
||||
@@ -340,7 +340,7 @@
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"jsdom": "^29.1.1",
|
||||
"lerna": "^9.0.4",
|
||||
"lightningcss": "^1.33.0",
|
||||
"lightningcss": "^1.32.0",
|
||||
"mini-css-extract-plugin": "^2.10.2",
|
||||
"minimizer-webpack-plugin": "^5.6.1",
|
||||
"open-cli": "^9.0.0",
|
||||
@@ -354,12 +354,12 @@
|
||||
"react-refresh": "^0.18.0",
|
||||
"react-resizable": "^4.0.2",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"source-map": "^0.8.0",
|
||||
"source-map": "^0.7.6",
|
||||
"source-map-support": "^0.5.21",
|
||||
"speed-measure-webpack-plugin": "^1.6.0",
|
||||
"storybook": "10.5.2",
|
||||
"style-loader": "^4.0.0",
|
||||
"stylelint": "^17.14.1",
|
||||
"stylelint": "^17.14.0",
|
||||
"swc-loader": "^0.2.7",
|
||||
"ts-jest": "^29.4.11",
|
||||
"tscw-config": "^1.1.2",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { render, screen, userEvent } from '@superset-ui/core/spec';
|
||||
import { render, screen, userEvent, fireEvent } from '@superset-ui/core/spec';
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import { ActionButton } from '.';
|
||||
|
||||
@@ -45,6 +45,18 @@ test('calls onClick when clicked', async () => {
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('calls onClick when activated with the keyboard', () => {
|
||||
const onClick = jest.fn();
|
||||
render(<ActionButton {...defaultProps} onClick={onClick} />);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
fireEvent.keyDown(button, { key: 'Enter' });
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
|
||||
fireEvent.keyDown(button, { key: ' ' });
|
||||
expect(onClick).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('renders with tooltip when tooltip prop is provided', async () => {
|
||||
const tooltipText = 'This is a tooltip';
|
||||
render(<ActionButton {...defaultProps} tooltip={tooltipText} />);
|
||||
@@ -103,6 +115,6 @@ test('has proper accessibility attributes', () => {
|
||||
render(<ActionButton {...defaultProps} />);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
expect(button.tagName).toBe('BUTTON');
|
||||
expect(button).toHaveAttribute('type', 'button');
|
||||
expect(button).toHaveAttribute('tabIndex', '0');
|
||||
expect(button).toHaveAttribute('role', 'button');
|
||||
});
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { handleKeyboardActivation } from '../../utils';
|
||||
import type { ReactElement, ReactNode } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { Tooltip, type TooltipPlacement } from '@superset-ui/core/components';
|
||||
import { css, useTheme } from '@apache-superset/core/theme';
|
||||
|
||||
@@ -28,9 +28,6 @@ export interface ActionProps {
|
||||
placement?: TooltipPlacement;
|
||||
icon: ReactNode;
|
||||
onClick: () => void;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
dataTest?: string;
|
||||
}
|
||||
|
||||
export const ActionButton = ({
|
||||
@@ -39,45 +36,30 @@ export const ActionButton = ({
|
||||
placement,
|
||||
icon,
|
||||
onClick,
|
||||
className,
|
||||
disabled = false,
|
||||
dataTest,
|
||||
}: ActionProps) => {
|
||||
const theme = useTheme();
|
||||
const actionButton = (
|
||||
<button
|
||||
type="button"
|
||||
aria-disabled={disabled}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={typeof tooltip === 'string' ? tooltip : label}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
line-height: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
color: ${theme.colorIcon};
|
||||
margin-right: ${theme.sizeUnit}px;
|
||||
&:not(.disabled):hover {
|
||||
&:hover {
|
||||
path {
|
||||
fill: ${theme.colorPrimary};
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
color: ${theme.colorTextDisabled};
|
||||
cursor: not-allowed;
|
||||
}
|
||||
`}
|
||||
className={cx('action-button', className, { disabled })}
|
||||
data-test={dataTest ?? label}
|
||||
onClick={disabled ? undefined : onClick}
|
||||
className="action-button"
|
||||
data-test={label}
|
||||
onClick={onClick}
|
||||
onKeyDown={onClick ? handleKeyboardActivation(onClick) : undefined}
|
||||
>
|
||||
{icon}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
|
||||
const tooltipId = `${label.replaceAll(' ', '-').toLowerCase()}-tooltip`;
|
||||
|
||||
@@ -21,11 +21,7 @@ import type { ButtonGroupProps } from './types';
|
||||
export function ButtonGroup(props: ButtonGroupProps) {
|
||||
const { className, children } = props;
|
||||
return (
|
||||
// role="group" is the correct ARIA pattern for a generic button toolbar;
|
||||
// the suggested native tags (fieldset, etc.) carry unrelated form
|
||||
// semantics and unwanted default browser styling.
|
||||
<div
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="group"
|
||||
className={className}
|
||||
css={{
|
||||
|
||||
@@ -134,10 +134,6 @@ const ImageContainer = ({
|
||||
? imageMap[image as keyof typeof imageMap]
|
||||
: image;
|
||||
return (
|
||||
// Groups Empty's SVG illustration + description into one accessible
|
||||
// image; can't be a literal <img> since it's a component tree, not an
|
||||
// image file reference.
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
<div role="img" aria-label="empty">
|
||||
<Empty
|
||||
description={false}
|
||||
|
||||
@@ -25,12 +25,8 @@ import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import { Tooltip } from '../Tooltip';
|
||||
import type { FaveStarProps } from './types';
|
||||
|
||||
const StyledLink = styled.button`
|
||||
const StyledLink = styled.a`
|
||||
${({ theme }) => css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
font-size: ${theme.fontSizeXL}px;
|
||||
display: flex;
|
||||
padding: 0 0 0 ${theme.sizeUnit * 2}px;
|
||||
@@ -59,10 +55,12 @@ export const FaveStar = ({
|
||||
|
||||
const content = (
|
||||
<StyledLink
|
||||
type="button"
|
||||
href="#"
|
||||
onClick={onClick}
|
||||
className="fave-unfave-icon"
|
||||
data-test="fave-unfave-icon"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
{isStarred ? (
|
||||
<Icons.StarFilled
|
||||
|
||||
@@ -102,10 +102,6 @@ export const LabeledErrorBoundInput = ({
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
// input[type=password] doesn't get an implicit "textbox" role
|
||||
// (unlike other text inputs), so this explicit override is
|
||||
// needed for it to be discoverable via role-based queries/AT.
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="textbox"
|
||||
/>
|
||||
) : renderAsTextArea ? (
|
||||
|
||||
@@ -79,12 +79,8 @@ const IconButton: React.FC<IconButtonProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
// antd's Card renders a fixed <div> (no polymorphic tag support) with
|
||||
// its own rich internal layout (cover/title/tooltip); that doesn't map
|
||||
// onto a native <button>, so role="button" is used instead.
|
||||
<Card
|
||||
hoverable
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={buttonText}
|
||||
|
||||
@@ -99,10 +99,6 @@ export function Loading({
|
||||
$spinnerHeight="auto"
|
||||
$opacity={opacity}
|
||||
className={cls('loading', position, className)}
|
||||
// role="status" is the standard WAI-ARIA live-region pattern for a
|
||||
// loading spinner; <output> (the suggested tag) is for form
|
||||
// calculation results, not a fit here.
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
aria-label={t('Loading')}
|
||||
|
||||
@@ -89,7 +89,6 @@ const StyledItem = styled.div<{
|
||||
& .metadata-text {
|
||||
color: ${theme.colorTextSecondary};
|
||||
min-width: ${TEXT_MIN_WIDTH}px;
|
||||
max-width: ${TEXT_MAX_WIDTH}px;
|
||||
overflow: hidden;
|
||||
text-overflow: ${collapsed ? 'unset' : 'ellipsis'};
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -127,15 +127,10 @@ export const ModalTrigger = forwardRef(
|
||||
</Button>
|
||||
)}
|
||||
{!isButton && (
|
||||
// Generic wrapper used by 19+ callers passing arbitrary
|
||||
// triggerNode content that relies on block-level <div> layout;
|
||||
// swapping to <button> risks a layout regression across callers
|
||||
// with no shared CSS to guide a safe reset.
|
||||
<div
|
||||
data-test="span-modal-trigger"
|
||||
onClick={open}
|
||||
onKeyDown={handleKeyboardActivation(open)}
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
|
||||
@@ -103,18 +103,7 @@ const PopoverDropdown = (props: PopoverDropdownProps) => {
|
||||
})),
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
css={{
|
||||
appearance: 'none',
|
||||
border: 'none',
|
||||
background: 'none',
|
||||
padding: 0,
|
||||
font: 'inherit',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<div role="button" css={{ display: 'flex', alignItems: 'center' }}>
|
||||
{selected && renderButton(selected)}
|
||||
<Icons.DownOutlined
|
||||
iconSize="s"
|
||||
@@ -123,7 +112,7 @@ const PopoverDropdown = (props: PopoverDropdownProps) => {
|
||||
marginLeft: theme.sizeUnit * 0.5,
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ import PopoverSection from '.';
|
||||
test('renders with default props', async () => {
|
||||
render(
|
||||
<PopoverSection title="Title">
|
||||
<form aria-label="test-form" />
|
||||
<div role="form" />
|
||||
</PopoverSection>,
|
||||
);
|
||||
expect(await screen.findByRole('form')).toBeInTheDocument();
|
||||
@@ -32,7 +32,7 @@ test('renders with default props', async () => {
|
||||
test('renders tooltip icon', async () => {
|
||||
render(
|
||||
<PopoverSection title="Title" info="Tooltip">
|
||||
<form />
|
||||
<div role="form" />
|
||||
</PopoverSection>,
|
||||
);
|
||||
expect((await screen.findAllByRole('img')).length).toBe(2);
|
||||
@@ -41,7 +41,7 @@ test('renders tooltip icon', async () => {
|
||||
test('renders a tooltip when hovered', async () => {
|
||||
render(
|
||||
<PopoverSection title="Title" info="Tooltip">
|
||||
<form />
|
||||
<div role="form" />
|
||||
</PopoverSection>,
|
||||
);
|
||||
await userEvent.hover(screen.getAllByRole('img')[0]);
|
||||
@@ -52,7 +52,7 @@ test('calls onSelect when clicked', async () => {
|
||||
const onSelect = jest.fn();
|
||||
render(
|
||||
<PopoverSection title="Title" onSelect={onSelect}>
|
||||
<form />
|
||||
<div role="form" />
|
||||
</PopoverSection>,
|
||||
);
|
||||
await userEvent.click(await screen.findByRole('img'));
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { MouseEventHandler, ReactNode } from 'react';
|
||||
import { handleKeyboardActivation } from '../../utils';
|
||||
import { ReactNode, SyntheticEvent } from 'react';
|
||||
import { css, useTheme } from '@apache-superset/core/theme';
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import { Tooltip } from '../Tooltip';
|
||||
@@ -24,7 +25,10 @@ import { Tooltip } from '../Tooltip';
|
||||
export interface PopoverSectionProps {
|
||||
title: string;
|
||||
isSelected?: boolean;
|
||||
onSelect?: MouseEventHandler<HTMLButtonElement>;
|
||||
// `SyntheticEvent` (rather than `MouseEventHandler`) so the same callback
|
||||
// can be reused as the keyboard-activation handler via
|
||||
// `handleKeyboardActivation`, which invokes it with a `KeyboardEvent`.
|
||||
onSelect?: (event: SyntheticEvent) => void;
|
||||
info?: string;
|
||||
children?: ReactNode;
|
||||
}
|
||||
@@ -44,17 +48,12 @@ export default function PopoverSection({
|
||||
opacity: isSelected ? 1 : 0.6,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onSelect}
|
||||
onKeyDown={onSelect ? handleKeyboardActivation(onSelect) : undefined}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: ${onSelect ? 'pointer' : 'default'};
|
||||
@@ -69,9 +68,8 @@ export default function PopoverSection({
|
||||
margin-right: ${theme.sizeUnit}px;
|
||||
`}
|
||||
>
|
||||
{/* role is auto-computed by BaseIconComponent as "img" since
|
||||
there's no onClick, so no explicit role needed here. */}
|
||||
<Icons.InfoCircleOutlined
|
||||
role="img"
|
||||
iconSize="s"
|
||||
iconColor={theme.colorIcon}
|
||||
/>
|
||||
@@ -79,9 +77,10 @@ export default function PopoverSection({
|
||||
)}
|
||||
<Icons.CheckOutlined
|
||||
iconSize="s"
|
||||
role="img"
|
||||
iconColor={isSelected ? theme.colorPrimary : theme.colorIcon}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
css={css`
|
||||
margin-left: ${theme.sizeUnit}px;
|
||||
|
||||
@@ -35,8 +35,7 @@ const RefreshLabel = ({
|
||||
<Tooltip title={tooltipContent}>
|
||||
<Icons.SyncOutlined
|
||||
iconSize="l"
|
||||
// role is auto-computed by BaseIconComponent as "button" whenever
|
||||
// onClick is present (and "img" otherwise), so no explicit role here.
|
||||
role="button"
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
onClick={disabled ? undefined : onClick}
|
||||
css={(theme: SupersetTheme) => ({
|
||||
|
||||
@@ -870,14 +870,14 @@ test('Renders only an overflow tag if dropdown is open in oneLine mode', async (
|
||||
test('does not fire onChange when searching but no selection', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
<main>
|
||||
<div role="main">
|
||||
<AsyncSelect
|
||||
{...defaultProps}
|
||||
onChange={onChange}
|
||||
mode="multiple"
|
||||
allowNewOptions
|
||||
/>
|
||||
</main>,
|
||||
</div>,
|
||||
);
|
||||
await open();
|
||||
await type('Joh');
|
||||
|
||||
@@ -1032,35 +1032,6 @@ test('do not count unselected disabled options in "Select all"', async () => {
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('"Select all" does not count null-valued options', async () => {
|
||||
// A falsy-valued option (e.g. <NULL>, value: null) is skipped by
|
||||
// handleSelectAll, so it must not be counted in the "Select all" badge or
|
||||
// the count overstates the selection. Regression test for #40228. Uses a
|
||||
// local options array to stay isolated from tests that mutate OPTIONS.
|
||||
const localOptions = [
|
||||
{ label: 'Alpha', value: 1 },
|
||||
{ label: 'Bravo', value: 2 },
|
||||
];
|
||||
render(
|
||||
<Select
|
||||
{...defaultProps}
|
||||
options={[...localOptions, NULL_OPTION]}
|
||||
mode="multiple"
|
||||
maxTagCount={0}
|
||||
/>,
|
||||
);
|
||||
await open();
|
||||
// Three options are visible, but the <NULL> option is not bulk-selectable,
|
||||
// so the badge must count only the two real options (would be 3 before fix).
|
||||
await userEvent.click(
|
||||
await screen.findByText(selectAllButtonText(localOptions.length)),
|
||||
);
|
||||
// And Select all selects exactly those two — the null option is skipped.
|
||||
const values = await findAllSelectValues();
|
||||
expect(values.length).toBe(1);
|
||||
expect(values[0]).toHaveTextContent(`+ ${localOptions.length} ...`);
|
||||
});
|
||||
|
||||
test('"Deselect all" counts all selected options', async () => {
|
||||
render(<Select {...defaultProps} allowNewOptions mode="multiple" />);
|
||||
await open();
|
||||
@@ -1163,14 +1134,14 @@ test('dropdown takes full width of the select input for single select', async ()
|
||||
test('does not fire onChange when searching but no selection', async () => {
|
||||
const onChange = jest.fn();
|
||||
render(
|
||||
<main>
|
||||
<div role="main">
|
||||
<Select
|
||||
{...defaultProps}
|
||||
onChange={onChange}
|
||||
mode="multiple"
|
||||
allowNewOptions
|
||||
/>
|
||||
</main>,
|
||||
</div>,
|
||||
);
|
||||
await open();
|
||||
await type('Joh');
|
||||
|
||||
@@ -332,12 +332,7 @@ const Select = forwardRef(
|
||||
const isDisabled = option.disabled;
|
||||
const isNew = option.isNewOption;
|
||||
|
||||
// Mirror handleSelectAll, which skips falsy-valued options (e.g. the
|
||||
// <NULL> option whose value is null): they are not bulk-selectable,
|
||||
// so counting them here makes the "Select all" badge overstate what
|
||||
// gets selected.
|
||||
if (
|
||||
option.value &&
|
||||
(!isDisabled || isSelected) &&
|
||||
((isNew && isSelected) || !isNew)
|
||||
) {
|
||||
|
||||
@@ -142,9 +142,7 @@ EditableTabs.defaultProps = {
|
||||
};
|
||||
|
||||
EditableTabs.TabPane.defaultProps = {
|
||||
// rc-tabs already wraps closeIcon in its own <button role="tab"
|
||||
// aria-label="remove">; this is just decorative content inside it.
|
||||
closeIcon: <StyledCloseOutlined iconSize="s" />,
|
||||
closeIcon: <StyledCloseOutlined iconSize="s" role="button" tabIndex={0} />,
|
||||
};
|
||||
|
||||
export const StyledLineEditableTabs = styled(EditableTabs)`
|
||||
|
||||
@@ -66,30 +66,3 @@ test('falls back to localeCompare when strings have no match relationship to sea
|
||||
expect(rankedSearchCompare('abc', 'def', 'xyz')).toBeLessThan(0);
|
||||
expect(rankedSearchCompare('def', 'abc', 'xyz')).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('ranks a case-insensitive substring match above a non-match', () => {
|
||||
// `zzABCzz` contains the search term ignoring case, `aaaa` does not match at
|
||||
// all, so the match must win even though localeCompare would order it last.
|
||||
expect(rankedSearchCompare('zzABCzz', 'aaaa', 'abc')).toBeLessThan(0);
|
||||
expect(rankedSearchCompare('aaaa', 'zzABCzz', 'abc')).toBeGreaterThan(0);
|
||||
expect(['aaaa', 'zzABCzz'].sort(searchSort('abc'))).toEqual([
|
||||
'zzABCzz',
|
||||
'aaaa',
|
||||
]);
|
||||
});
|
||||
|
||||
test('is antisymmetric so Array.prototype.sort stays well defined', () => {
|
||||
const pairs: [string, string, string][] = [
|
||||
['zzABCzz', 'aaaa', 'abc'],
|
||||
['Total Revenue', 'ARR', 'revenue'],
|
||||
['My Country', 'zzz', 'country'],
|
||||
['%f %B', '%F %b', '%F'],
|
||||
['her', 'Cher', 'Her'],
|
||||
];
|
||||
pairs.forEach(([a, b, search]) => {
|
||||
expect(
|
||||
Math.sign(rankedSearchCompare(a, b, search)) +
|
||||
Math.sign(rankedSearchCompare(b, a, search)),
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,8 +32,7 @@ export function rankedSearchCompare(a: string, b: string, search: string) {
|
||||
Number(bLower.startsWith(searchLower)) -
|
||||
Number(aLower.startsWith(searchLower)) ||
|
||||
Number(b.includes(search)) - Number(a.includes(search)) ||
|
||||
Number(bLower.includes(searchLower)) -
|
||||
Number(aLower.includes(searchLower)) ||
|
||||
Number(bLower.includes(searchLower)) - Number(a.includes(searchLower)) ||
|
||||
a.localeCompare(b)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,9 +69,8 @@ describe('ChartDataProvider', () => {
|
||||
formData: { ...bigNumberFormData },
|
||||
children: ({ loading, payload, error }) => (
|
||||
<div>
|
||||
{/* eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors the real Loading component's role="status" pattern */}
|
||||
{loading && <span role="status">Loading...</span>}
|
||||
{payload && <footer>{JSON.stringify(payload)}</footer>}
|
||||
{payload && <pre role="contentinfo">{JSON.stringify(payload)}</pre>}
|
||||
{error && <div role="alert">{error.message}</div>}
|
||||
</div>
|
||||
),
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -33,6 +33,6 @@
|
||||
{ "type": "Feature", "properties": { "ISO": "IR-25", "NAME_1": "Yazd" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 53.650710076708663, 32.61286754000497 ], [ 54.70904341032508, 32.920083929729572 ], [ 54.814670038291581, 32.970700994954939 ], [ 54.908204380227914, 33.088161526533213 ], [ 54.986339146034709, 33.329955553206219 ], [ 55.040082635105477, 33.385688585459832 ], [ 55.139404737638529, 33.430362861356969 ], [ 55.217229445082808, 33.437261664194409 ], [ 55.274590285313366, 33.470644639738339 ], [ 55.359856397954388, 33.594642238948154 ], [ 55.386418085026548, 33.665464788968791 ], [ 55.375255974983247, 34.344363918859756 ], [ 55.484706658785228, 34.365163682857656 ], [ 55.741125116131172, 34.360331935770205 ], [ 55.850885858295669, 34.407254137268581 ], [ 56.210450474010145, 34.906060898691521 ], [ 56.619211053447316, 34.993678289721288 ], [ 57.016602818165495, 35.148294175835531 ], [ 57.268370395577278, 35.201314195393763 ], [ 57.37957807766611, 35.177336330707078 ], [ 57.671239861630283, 34.993936672139682 ], [ 57.705553013161023, 34.930994777786736 ], [ 57.692013788105783, 34.86686432502853 ], [ 57.595172154271495, 34.788807075386217 ], [ 57.198917271115135, 34.557735908285508 ], [ 57.13080773289056, 34.456295071360444 ], [ 57.004820591397163, 34.142567449728006 ], [ 56.9966557148893, 33.973482164370353 ], [ 57.05887413883039, 33.685256863513416 ], [ 57.105796340328823, 33.623581041032196 ], [ 57.304440545394812, 33.603737291442826 ], [ 57.559928826753946, 33.653243313528094 ], [ 57.602716913155007, 33.607716376009932 ], [ 57.642301060445561, 33.54405101214445 ], [ 57.71702518066752, 33.121699530808655 ], [ 57.782240838144162, 32.996797594033694 ], [ 58.04062300025123, 32.871068834059429 ], [ 58.147696568142067, 32.748595689139734 ], [ 58.152554151852598, 32.671882025734874 ], [ 58.10036095639299, 32.568141588163769 ], [ 58.224384393125206, 32.352547512457704 ], [ 58.222213982789071, 32.297563788138291 ], [ 58.173948195053129, 32.146048489246368 ], [ 58.040726353038735, 31.994533189455126 ], [ 58.003932732809346, 31.907200019265474 ], [ 57.901199985590836, 31.771549384496495 ], [ 57.834744093764868, 31.637268175286067 ], [ 56.761631300743886, 32.03008657533519 ], [ 56.634093865639386, 32.049181016990303 ], [ 56.566397738564774, 31.978926906851257 ], [ 56.358451776328366, 31.879036363537352 ], [ 56.287758416617578, 31.815086777932436 ], [ 55.756834750623227, 31.576264146373262 ], [ 55.712289666834636, 31.495183823874356 ], [ 55.684487746312413, 31.110917873960716 ], [ 55.514989048006157, 31.046787421202509 ], [ 55.32637006962301, 31.024773261276948 ], [ 55.116460401726158, 31.043247586207144 ], [ 54.554427525110157, 30.957774767091792 ], [ 54.466474237296211, 30.873361314273211 ], [ 54.420275506209634, 30.797913722740077 ], [ 54.398054640709063, 30.725075792014195 ], [ 54.400638462195275, 30.675466417141422 ], [ 54.515566848231458, 30.450441393055826 ], [ 54.539441359231319, 30.350550848842602 ], [ 54.603830194407919, 30.297349962131022 ], [ 54.591221144440226, 29.973106187400617 ], [ 54.616749301838809, 29.847971707528245 ], [ 54.430197381004291, 29.793220527205563 ], [ 54.227212355265976, 29.882879137362295 ], [ 54.071769646851692, 29.984268297443975 ], [ 54.043140904029485, 30.044161282317305 ], [ 54.007587518149421, 30.263191840231229 ], [ 53.964075962235825, 30.329983628841376 ], [ 53.80460249241105, 30.499068915098348 ], [ 53.638411086002804, 30.755151476559377 ], [ 53.404936964569231, 31.261502996865772 ], [ 53.276469354377184, 31.395086574985442 ], [ 53.125160760160952, 31.51394236874529 ], [ 52.870706007576189, 31.597451483998782 ], [ 52.827091098875087, 31.744419257542688 ], [ 52.824093866238911, 31.813846544482431 ], [ 52.904915806319366, 32.164600328542292 ], [ 52.883728468693846, 32.505199692911503 ], [ 53.060358513834331, 32.576694037399875 ], [ 53.164641554664001, 32.640333563742956 ], [ 53.261069777348325, 32.672011216944099 ], [ 53.334036900182753, 32.67412995043685 ], [ 53.650710076708663, 32.61286754000497 ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "ISO": "IR-26", "NAME_1": "Qom" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 51.788911574109818, 34.54197459605075 ], [ 51.451671176683419, 34.469730942728802 ], [ 51.158355747219957, 34.452522691469028 ], [ 51.063064406097453, 34.418235379259329 ], [ 51.013765089587196, 34.357903143914939 ], [ 50.983689405941277, 34.161610216338374 ], [ 51.004670037991843, 34.11838288036563 ], [ 51.032988723350854, 34.105799668819657 ], [ 50.802201776190998, 34.157889513290399 ], [ 50.699262323397477, 34.20488922825524 ], [ 50.441190219652867, 34.224784653788731 ], [ 50.32874230321471, 34.317879747052643 ], [ 50.30445438016551, 34.367463284403016 ], [ 50.30869184805033, 34.408520209140306 ], [ 50.264146763362419, 34.466423651730111 ], [ 50.158313429820907, 34.492106838759582 ], [ 50.060024855162908, 34.577062893038089 ], [ 50.069429966020095, 34.628739325459492 ], [ 50.162757603280738, 34.671992498954637 ], [ 50.173402947587931, 34.692042955018337 ], [ 50.152629022011752, 34.716124172492528 ], [ 50.153972609148582, 34.781494858700739 ], [ 50.21112674290481, 34.819373684547884 ], [ 50.301147088267498, 34.809374295387386 ], [ 50.388170200094635, 34.829915676067571 ], [ 50.447598097873879, 34.862058417262119 ], [ 50.57151818181859, 34.878129787859393 ], [ 50.693681268375826, 34.915956935963777 ], [ 50.723033481609889, 35.107883206244935 ], [ 50.784735141613453, 35.218419093866089 ], [ 51.072159457692806, 35.213251450893722 ], [ 51.31235151570985, 35.153952745222966 ], [ 51.882342564157966, 34.875494290429117 ], [ 51.893194614040169, 34.754002997440352 ], [ 51.866116163929803, 34.66646312077637 ], [ 51.788911574109818, 34.54197459605075 ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "ISO": "IR-07", "NAME_1": "Tehran" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 50.784735141613453, 35.218419093866089 ], [ 50.8712414886038, 35.4471906603207 ], [ 50.870828078353099, 35.517031358410463 ], [ 50.798687778717976, 35.604777939750079 ], [ 50.825095940725078, 35.654454591106457 ], [ 50.889640414373616, 35.686726828380415 ], [ 50.942082799381637, 35.739169213388493 ], [ 50.970321006209417, 35.799679657490174 ], [ 51.059069657138934, 35.803713687037032 ], [ 51.075205776225573, 35.916666515247471 ], [ 51.135716220327254, 35.97314292980235 ], [ 51.216396812163111, 35.997347107083328 ], [ 51.297077403998969, 35.989279047989669 ], [ 51.353553818553848, 36.017517255716768 ], [ 51.356896600397761, 36.116271267305137 ], [ 51.465003697062969, 36.064698188570503 ], [ 51.618275995141062, 36.054052843363991 ], [ 51.754391717004125, 36.010980536122815 ], [ 51.856504348396925, 35.921554469962814 ], [ 51.950245395908269, 35.799804796354238 ], [ 52.029206984015048, 35.77091767021426 ], [ 52.108168573021203, 35.767171128744565 ], [ 52.177001580758315, 35.789960435925366 ], [ 52.306812778986512, 35.917394518242418 ], [ 52.398486768949226, 35.976202298397311 ], [ 52.625863072322886, 35.931347154447622 ], [ 52.740274692622961, 35.881014309162993 ], [ 52.816342400881069, 35.86825023046373 ], [ 52.901401807947025, 35.889695950507701 ], [ 52.944810011972436, 35.881556912421559 ], [ 53.0347270036483, 35.831094875927761 ], [ 53.066249628117816, 35.718905341008679 ], [ 53.079375441123659, 35.618136298551292 ], [ 53.047232699929111, 35.528374334707735 ], [ 52.888275994941182, 35.410190335415621 ], [ 52.674955682358814, 35.336189683806822 ], [ 52.594133742278359, 35.338721829348913 ], [ 52.21968631437187, 35.414221095926791 ], [ 51.982078077840981, 35.54431651499516 ], [ 51.922443475386046, 35.54684866053725 ], [ 51.870146926239613, 35.569818833971965 ], [ 51.853403762073924, 35.555452785717478 ], [ 51.821054315304366, 35.403420721988709 ], [ 51.822501255228701, 35.315260727700377 ], [ 51.980631137916646, 35.125246487135655 ], [ 51.968022087948953, 35.063725694285324 ], [ 51.916862420364396, 34.998587551174523 ], [ 51.882342564157966, 34.875494290429117 ], [ 51.31235151570985, 35.153952745222966 ], [ 51.072159457692806, 35.213251450893722 ], [ 50.784735141613453, 35.218419093866089 ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "ISO": "IR-07", "NAME_1": "Alborz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 50.696471795436992, 35.550543525163562 ], [ 50.689753858853464, 35.639246120911707 ], [ 50.650996534762271, 35.676478989813518 ], [ 50.594772576992796, 35.677047431493747 ], [ 50.581956822349468, 35.650072333271567 ], [ 50.620714146440662, 35.60635407178296 ], [ 50.610378858697345, 35.574831448212763 ], [ 50.527696568441854, 35.62911754054204 ], [ 50.285540805663629, 35.666014513558935 ], [ 50.238618605064573, 35.741022853721688 ], [ 50.2302470229817, 35.771925361466231 ], [ 50.242752720161889, 35.81083771428905 ], [ 50.297736443581982, 35.853961697474347 ], [ 50.500204706282148, 35.934266872717956 ], [ 50.534517856913567, 35.960802721368452 ], [ 50.625881789413029, 36.164769599037754 ], [ 50.47188602092308, 36.239648748890602 ], [ 50.420829706126028, 36.296389472396186 ], [ 50.449665155422565, 36.331684474958536 ], [ 50.563146599735774, 36.339177557897983 ], [ 50.966222772263109, 36.292203681354806 ], [ 51.029888137027854, 36.27179149008515 ], [ 51.086008742009824, 36.222259630477538 ], [ 51.127970005211523, 36.20745433175199 ], [ 51.291991001283634, 36.178102118517927 ], [ 51.356896600397761, 36.116271267305137 ], [ 51.353553818553848, 36.017517255716768 ], [ 51.297077403998969, 35.989279047989669 ], [ 51.216396812163111, 35.997347107083328 ], [ 51.135716220327254, 35.97314292980235 ], [ 51.075205776225573, 35.916666515247471 ], [ 51.059069657138934, 35.803713687037032 ], [ 50.970321006209417, 35.799679657490174 ], [ 50.942082799381637, 35.739169213388493 ], [ 50.889640414373616, 35.686726828380415 ], [ 50.825095940725078, 35.654454591106457 ], [ 50.798687778717976, 35.604777939750079 ], [ 50.75269575410573, 35.601341458441539 ], [ 50.724893832684188, 35.555168564877363 ], [ 50.696471795436992, 35.550543525163562 ] ] ] } }
|
||||
{ "type": "Feature", "properties": { "ISO": "IR-32", "NAME_1": "Alborz" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 50.696471795436992, 35.550543525163562 ], [ 50.689753858853464, 35.639246120911707 ], [ 50.650996534762271, 35.676478989813518 ], [ 50.594772576992796, 35.677047431493747 ], [ 50.581956822349468, 35.650072333271567 ], [ 50.620714146440662, 35.60635407178296 ], [ 50.610378858697345, 35.574831448212763 ], [ 50.527696568441854, 35.62911754054204 ], [ 50.285540805663629, 35.666014513558935 ], [ 50.238618605064573, 35.741022853721688 ], [ 50.2302470229817, 35.771925361466231 ], [ 50.242752720161889, 35.81083771428905 ], [ 50.297736443581982, 35.853961697474347 ], [ 50.500204706282148, 35.934266872717956 ], [ 50.534517856913567, 35.960802721368452 ], [ 50.625881789413029, 36.164769599037754 ], [ 50.47188602092308, 36.239648748890602 ], [ 50.420829706126028, 36.296389472396186 ], [ 50.449665155422565, 36.331684474958536 ], [ 50.563146599735774, 36.339177557897983 ], [ 50.966222772263109, 36.292203681354806 ], [ 51.029888137027854, 36.27179149008515 ], [ 51.086008742009824, 36.222259630477538 ], [ 51.127970005211523, 36.20745433175199 ], [ 51.291991001283634, 36.178102118517927 ], [ 51.356896600397761, 36.116271267305137 ], [ 51.353553818553848, 36.017517255716768 ], [ 51.297077403998969, 35.989279047989669 ], [ 51.216396812163111, 35.997347107083328 ], [ 51.135716220327254, 35.97314292980235 ], [ 51.075205776225573, 35.916666515247471 ], [ 51.059069657138934, 35.803713687037032 ], [ 50.970321006209417, 35.799679657490174 ], [ 50.942082799381637, 35.739169213388493 ], [ 50.889640414373616, 35.686726828380415 ], [ 50.825095940725078, 35.654454591106457 ], [ 50.798687778717976, 35.604777939750079 ], [ 50.75269575410573, 35.601341458441539 ], [ 50.724893832684188, 35.555168564877363 ], [ 50.696471795436992, 35.550543525163562 ] ] ] } }
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
type Feature = {
|
||||
properties: {
|
||||
ISO: string;
|
||||
NAME_1: string;
|
||||
};
|
||||
};
|
||||
|
||||
// `.geojson` imports are mocked out to an empty object by the Jest module
|
||||
// mapper (see jest.config.js), so the file is read from disk directly to
|
||||
// exercise the real, committed data.
|
||||
function loadIranGeoJson(): { features: Feature[] } {
|
||||
const filePath = path.join(__dirname, '../src/countries/iran.geojson');
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
||||
}
|
||||
|
||||
test('every Iranian province has its own distinct ISO 3166-2 code', () => {
|
||||
const { features } = loadIranGeoJson();
|
||||
|
||||
// Sanity check: every province name in this file is unique, so a
|
||||
// duplicate ISO code below can only mean two different provinces were
|
||||
// mistakenly assigned the same code (as opposed to one province being
|
||||
// split across multiple polygon features).
|
||||
const names = features.map(feature => feature.properties.NAME_1);
|
||||
expect(new Set(names).size).toBe(names.length);
|
||||
|
||||
const isoByName = new Map(
|
||||
features.map(feature => [
|
||||
feature.properties.NAME_1,
|
||||
feature.properties.ISO,
|
||||
]),
|
||||
);
|
||||
const isoCodes = features.map(feature => feature.properties.ISO);
|
||||
|
||||
expect(new Set(isoCodes).size).toBe(isoCodes.length);
|
||||
|
||||
// Tehran and Alborz were split into separate provinces in 2010, but the
|
||||
// GeoJSON still assigned both the same ISO code (IR-07), which used to
|
||||
// make it impossible to distinguish them on the Country Map chart. Alborz
|
||||
// now uses its pre-2020 ISO 3166-2 code, IR-32.
|
||||
expect(isoByName.get('Tehran')).toBe('IR-07');
|
||||
expect(isoByName.get('Alborz')).toBe('IR-32');
|
||||
});
|
||||
69
superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.ts
vendored
Normal file
69
superset-frontend/plugins/legacy-preset-chart-nvd3/src/vendor/superset/exploreUtils.ts
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
// @ts-nocheck -- vendor file; not fully typed
|
||||
/* eslint camelcase: 0 */
|
||||
import URI from 'urijs';
|
||||
import safeStringify from 'fast-safe-stringify';
|
||||
|
||||
const MAX_URL_LENGTH = 8000;
|
||||
|
||||
export function getURIDirectory(formData, endpointType = 'base') {
|
||||
// Building the directory part of the URI
|
||||
let directory = '/explore/';
|
||||
if (['json', 'csv', 'query', 'results', 'samples'].includes(endpointType)) {
|
||||
directory = '/superset/explore_json/';
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
export function getExploreLongUrl(
|
||||
formData,
|
||||
endpointType,
|
||||
allowOverflow = true,
|
||||
extraSearch = {},
|
||||
) {
|
||||
if (!formData.datasource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uri = new URI('/');
|
||||
const directory = getURIDirectory(formData, endpointType);
|
||||
const search = uri.search(true);
|
||||
Object.keys(extraSearch).forEach(key => {
|
||||
search[key] = extraSearch[key];
|
||||
});
|
||||
search.form_data = safeStringify(formData);
|
||||
if (endpointType === 'standalone') {
|
||||
search.standalone = 'true';
|
||||
}
|
||||
const url = uri.directory(directory).search(search).toString();
|
||||
if (!allowOverflow && url.length > MAX_URL_LENGTH) {
|
||||
const minimalFormData = {
|
||||
datasource: formData.datasource,
|
||||
viz_type: formData.viz_type,
|
||||
};
|
||||
|
||||
return getExploreLongUrl(minimalFormData, endpointType, false, {
|
||||
URL_IS_TOO_LONG_TO_SHARE: null,
|
||||
});
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
@@ -19,7 +19,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { useRef, useState, useEffect, MouseEvent } from 'react';
|
||||
import { handleKeyboardActivation } from '@superset-ui/core';
|
||||
import { useRef, useState, useEffect, SyntheticEvent } from 'react';
|
||||
import { t } from '@apache-superset/core/translation';
|
||||
import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
|
||||
import { Column } from '@superset-ui/core/components/ThemedAgGridReact';
|
||||
@@ -186,7 +187,10 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
|
||||
return undefined;
|
||||
}, [lastFilteredColumn, colId, lastFilteredInputPosition]);
|
||||
|
||||
const handleMenuClick = (e: MouseEvent<HTMLButtonElement>) => {
|
||||
// `SyntheticEvent` (rather than `MouseEvent`) so this callback can also be
|
||||
// used as the keyboard-activation handler via `handleKeyboardActivation`,
|
||||
// which invokes it with a `KeyboardEvent`.
|
||||
const handleMenuClick = (e: SyntheticEvent) => {
|
||||
e.stopPropagation();
|
||||
setMenuVisible(!isMenuVisible);
|
||||
};
|
||||
@@ -201,27 +205,37 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
|
||||
const menuContent = (
|
||||
<MenuContainer>
|
||||
{shouldShowAsc && (
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => applySort('asc')}
|
||||
onKeyDown={handleKeyboardActivation(() => applySort('asc'))}
|
||||
className="menu-item"
|
||||
>
|
||||
<ArrowUpOutlined /> {t('Sort Ascending')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{shouldShowDesc && (
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => applySort('desc')}
|
||||
onKeyDown={handleKeyboardActivation(() => applySort('desc'))}
|
||||
className="menu-item"
|
||||
>
|
||||
<ArrowDownOutlined /> {t('Sort Descending')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{currentSort && currentSort?.colId === colId && (
|
||||
<button type="button" onClick={clearSort} className="menu-item">
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={clearSort}
|
||||
onKeyDown={handleKeyboardActivation(clearSort)}
|
||||
className="menu-item"
|
||||
>
|
||||
<span style={{ fontSize: 16 }}>↻</span> {t('Clear Sort')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</MenuContainer>
|
||||
);
|
||||
@@ -255,13 +269,15 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
|
||||
isOpen={isMenuVisible}
|
||||
onClose={() => setMenuVisible(false)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="three-dots-menu"
|
||||
onClick={handleMenuClick}
|
||||
onKeyDown={handleKeyboardActivation(handleMenuClick)}
|
||||
>
|
||||
<KebabMenu />
|
||||
</button>
|
||||
</div>
|
||||
</CustomPopover>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
@@ -27,10 +27,6 @@ export const Container = styled.div`
|
||||
width: 100%;
|
||||
|
||||
.three-dots-menu {
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
align-self: center;
|
||||
margin-left: ${theme.sizeUnit}px;
|
||||
cursor: pointer;
|
||||
@@ -126,12 +122,6 @@ export const MenuContainer = styled.div`
|
||||
padding: ${theme.sizeUnit}px 0;
|
||||
|
||||
.menu-item {
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: ${theme.sizeUnit * 2}px ${theme.sizeUnit * 4}px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
@@ -144,23 +144,7 @@ export const Styles = styled.div<{ isDashboardEditMode: boolean }>`
|
||||
}
|
||||
|
||||
.toggle {
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding-right: ${theme.sizeUnit}px;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sort-icon-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
import {
|
||||
ReactNode,
|
||||
MouseEvent,
|
||||
SyntheticEvent,
|
||||
useState,
|
||||
useCallback,
|
||||
useRef,
|
||||
useMemo,
|
||||
useEffect,
|
||||
} from 'react';
|
||||
import { safeHtmlSpan } from '@superset-ui/core';
|
||||
import { safeHtmlSpan, handleKeyboardActivation } from '@superset-ui/core';
|
||||
import { t } from '@apache-superset/core/translation';
|
||||
import { supersetTheme } from '@apache-superset/core/theme';
|
||||
import PropTypes from 'prop-types';
|
||||
@@ -154,7 +155,10 @@ function displayCell(value: unknown, allowRenderHtml?: boolean): ReactNode {
|
||||
function displayHeaderCell(
|
||||
needToggle: boolean,
|
||||
ArrowIcon: ReactNode,
|
||||
onArrowClick: ((e: MouseEvent<HTMLButtonElement>) => void) | null,
|
||||
// `SyntheticEvent` (rather than `MouseEvent`) so this callback can also be
|
||||
// used as the keyboard-activation handler via `handleKeyboardActivation`,
|
||||
// which invokes it with a `KeyboardEvent`.
|
||||
onArrowClick: ((e: SyntheticEvent) => void) | null,
|
||||
value: unknown,
|
||||
namesMapping: Record<string, string>,
|
||||
allowRenderHtml?: boolean,
|
||||
@@ -167,13 +171,17 @@ function displayHeaderCell(
|
||||
: parsedLabel;
|
||||
return needToggle ? (
|
||||
<span className="toggle-wrapper">
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="toggle"
|
||||
onClick={onArrowClick || undefined}
|
||||
onKeyDown={
|
||||
onArrowClick ? handleKeyboardActivation(onArrowClick) : undefined
|
||||
}
|
||||
>
|
||||
{ArrowIcon}
|
||||
</button>
|
||||
</span>
|
||||
<span className="toggle-val">{labelContent}</span>
|
||||
</span>
|
||||
) : (
|
||||
@@ -460,7 +468,7 @@ export function TableRenderer(props: TableRendererProps) {
|
||||
);
|
||||
|
||||
const toggleRowKey = useCallback(
|
||||
(flatRowKey: string) => (e: MouseEvent<HTMLButtonElement>) => {
|
||||
(flatRowKey: string) => (e: SyntheticEvent) => {
|
||||
e.stopPropagation();
|
||||
setCollapsedRows(state => ({
|
||||
...state,
|
||||
@@ -471,7 +479,7 @@ export function TableRenderer(props: TableRendererProps) {
|
||||
);
|
||||
|
||||
const toggleColKey = useCallback(
|
||||
(flatColKey: string) => (e: MouseEvent<HTMLButtonElement>) => {
|
||||
(flatColKey: string) => (e: SyntheticEvent) => {
|
||||
e.stopPropagation();
|
||||
setCollapsedCols(state => ({
|
||||
...state,
|
||||
@@ -1036,9 +1044,9 @@ export function TableRenderer(props: TableRendererProps) {
|
||||
namesMapping,
|
||||
settingsAllowRenderHtml,
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="sort-icon-btn"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
// Prevents event bubbling to avoid conflict with column header click handlers
|
||||
// Ensures sort operation executes without triggering cross-filtration
|
||||
onClick={e => {
|
||||
@@ -1052,7 +1060,7 @@ export function TableRenderer(props: TableRendererProps) {
|
||||
}
|
||||
>
|
||||
{visibleSortIcon && getSortIcon(i)}
|
||||
</button>
|
||||
</span>
|
||||
</th>,
|
||||
);
|
||||
} else if (attrIdx === colKey.length) {
|
||||
|
||||
@@ -98,13 +98,16 @@ export default memo(
|
||||
key={item}
|
||||
className={currentPage === item ? 'active' : undefined}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`${item + 1}`}
|
||||
onClick={() => onPageChange(item)}
|
||||
<a
|
||||
href={`#page-${item}`}
|
||||
role="button"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
onPageChange(item);
|
||||
}}
|
||||
>
|
||||
{item + 1}
|
||||
</button>
|
||||
</a>
|
||||
</li>
|
||||
) : (
|
||||
<li key={item} className="dt-pagination-ellipsis">
|
||||
|
||||
@@ -363,16 +363,12 @@ function StickyWrap({
|
||||
}
|
||||
|
||||
return (
|
||||
// Virtualized/sticky table built from divs so the header/body can be
|
||||
// positioned independently; a real <table> would break that layout, so
|
||||
// role="table" is the correct ARIA pattern here, not the suggested tag.
|
||||
<div
|
||||
style={{
|
||||
width: maxWidth,
|
||||
height: sticky.realHeight || maxHeight,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="table"
|
||||
>
|
||||
{headerTable}
|
||||
|
||||
@@ -163,11 +163,8 @@ export default styled.div`
|
||||
margin: 0 ${theme.marginXXS}px;
|
||||
}
|
||||
|
||||
.dt-pagination .pagination > li > button,
|
||||
.dt-pagination .pagination > li > a,
|
||||
.dt-pagination .pagination > li > span {
|
||||
appearance: none;
|
||||
border: 1px solid transparent;
|
||||
font: inherit;
|
||||
background-color: ${theme.colorBgBase};
|
||||
color: ${theme.colorText};
|
||||
border-color: ${theme.colorBorderSecondary};
|
||||
@@ -175,10 +172,10 @@ export default styled.div`
|
||||
border-radius: ${theme.borderRadius}px;
|
||||
}
|
||||
|
||||
.dt-pagination .pagination > li.active > button,
|
||||
.dt-pagination .pagination > li.active > a,
|
||||
.dt-pagination .pagination > li.active > span,
|
||||
.dt-pagination .pagination > li.active > button:focus,
|
||||
.dt-pagination .pagination > li.active > button:hover,
|
||||
.dt-pagination .pagination > li.active > a:focus,
|
||||
.dt-pagination .pagination > li.active > a:hover,
|
||||
.dt-pagination .pagination > li.active > span:focus,
|
||||
.dt-pagination .pagination > li.active > span:hover {
|
||||
background-color: ${theme.colorPrimary};
|
||||
|
||||
@@ -2334,12 +2334,7 @@ describe('plugin-chart-table', () => {
|
||||
expect(screen.getByText('User 1')).toBeInTheDocument();
|
||||
expect(screen.queryByText('User 11')).not.toBeInTheDocument();
|
||||
|
||||
// The pagination bar is styled `visibility: hidden` until sticky
|
||||
// height is measured, which jsdom never reports. Accessible-name
|
||||
// computation treats CSS-hidden elements as nameless regardless of
|
||||
// the `hidden: true` query option, so query the button directly by
|
||||
// its `aria-label` instead of through the accessibility tree.
|
||||
const page2Link = container.querySelector('button[aria-label="2"]')!;
|
||||
const page2Link = container.querySelector('a[href="#page-1"]')!;
|
||||
expect(page2Link).toBeTruthy();
|
||||
fireEvent.click(page2Link);
|
||||
|
||||
@@ -2386,8 +2381,8 @@ describe('plugin-chart-table', () => {
|
||||
expect(screen.queryByText('User 1')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
const activePage = container.querySelector('li.active button')!;
|
||||
expect(activePage).toHaveTextContent('2');
|
||||
const activePage = container.querySelector('li.active a')!;
|
||||
expect(activePage).toHaveAttribute('href', '#page-1');
|
||||
});
|
||||
|
||||
test('should build columnLabelToNameMap for adhoc columns with custom labels', () => {
|
||||
|
||||
@@ -71,9 +71,9 @@ test('leaves labels untouched when no format is provided', () => {
|
||||
});
|
||||
|
||||
test('clicking a legend item toggles the category without triggering anchor navigation', () => {
|
||||
// Regression proof for #33576: legend items render as real <button>
|
||||
// elements (not href="#" anchors), so a click has no default navigation
|
||||
// action to begin with.
|
||||
// Regression proof for #33576: the legend items are href="#" anchors, so a
|
||||
// click whose default action is not prevented would navigate to "#" and
|
||||
// scroll the browser window to the top of the page.
|
||||
const toggleCategory = jest.fn();
|
||||
renderWithTheme(
|
||||
<Legend
|
||||
@@ -87,18 +87,18 @@ test('clicking a legend item toggles the category without triggering anchor navi
|
||||
);
|
||||
|
||||
const legendItem = screen.getByRole('button', { name: 'Positive' });
|
||||
expect(legendItem.tagName).toBe('BUTTON');
|
||||
const clickEvent = createEvent.click(legendItem);
|
||||
fireEvent(legendItem, clickEvent);
|
||||
|
||||
expect(clickEvent.defaultPrevented).toBe(true);
|
||||
expect(toggleCategory).toHaveBeenCalledTimes(1);
|
||||
expect(toggleCategory).toHaveBeenCalledWith('Positive');
|
||||
});
|
||||
|
||||
test('ctrl+clicking a legend item toggles the category without opening a new tab', () => {
|
||||
// Regression proof for #34157: legend items render as real <button>
|
||||
// elements (not href="#" anchors), so a ctrl+click has no "open link in
|
||||
// new tab" behavior to begin with.
|
||||
// Regression proof for #34157: legend items are href="#" anchors, so a
|
||||
// ctrl+click whose default action is not prevented would ask the browser
|
||||
// to open the "#" href in a new tab instead of just toggling the layer.
|
||||
const toggleCategory = jest.fn();
|
||||
renderWithTheme(
|
||||
<Legend
|
||||
@@ -112,12 +112,14 @@ test('ctrl+clicking a legend item toggles the category without opening a new tab
|
||||
);
|
||||
|
||||
const legendItem = screen.getByRole('button', { name: 'cat1' });
|
||||
expect(legendItem.tagName).toBe('BUTTON');
|
||||
const ctrlClickEvent = createEvent.click(legendItem, {
|
||||
ctrlKey: true,
|
||||
}) as MouseEvent;
|
||||
fireEvent(legendItem, ctrlClickEvent);
|
||||
|
||||
// preventDefault() in the onClick handler is what stops the browser's
|
||||
// native ctrl+click "open link in new tab" behavior on the anchor.
|
||||
expect(ctrlClickEvent.defaultPrevented).toBe(true);
|
||||
expect(ctrlClickEvent.ctrlKey).toBe(true);
|
||||
expect(toggleCategory).toHaveBeenCalledTimes(1);
|
||||
expect(toggleCategory).toHaveBeenCalledWith('cat1');
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable react/jsx-sort-default-props */
|
||||
/* eslint-disable react/sort-prop-types */
|
||||
/* eslint-disable jsx-a11y/anchor-is-valid */
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
@@ -42,18 +43,11 @@ const StyledLegend = styled.div`
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
|
||||
& li button {
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
& li a {
|
||||
display: flex;
|
||||
color: ${theme.colorText};
|
||||
text-decoration: none;
|
||||
padding: ${theme.sizeUnit}px 0;
|
||||
cursor: pointer;
|
||||
|
||||
& span {
|
||||
margin-right: ${theme.sizeUnit}px;
|
||||
@@ -166,13 +160,20 @@ const Legend = ({
|
||||
|
||||
return (
|
||||
<li key={k}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleCategory(k)}
|
||||
onDoubleClick={() => showSingleCategory(k)}
|
||||
<a
|
||||
href="#"
|
||||
role="button"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
toggleCategory(k);
|
||||
}}
|
||||
onDoubleClick={e => {
|
||||
e.preventDefault();
|
||||
showSingleCategory(k);
|
||||
}}
|
||||
>
|
||||
<span aria-hidden style={swatchStyle} /> {formatCategoryLabel(k)}
|
||||
</button>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ export function getURIDirectory(endpointType = 'base') {
|
||||
// Building the directory part of the URI
|
||||
let directory = '/explore/';
|
||||
if (['json', 'csv', 'query', 'results', 'samples'].includes(endpointType)) {
|
||||
directory = '/explore_json/';
|
||||
directory = '/superset/explore_json/';
|
||||
}
|
||||
|
||||
return directory;
|
||||
|
||||
@@ -43,6 +43,7 @@ const ExploreResultsButton = ({
|
||||
icon={<Icons.LineChartOutlined iconSize="m" />}
|
||||
onClick={onClick}
|
||||
disabled={!allowsSubquery}
|
||||
role="button"
|
||||
tooltip={t('Create chart')}
|
||||
aria-label={t('Create chart')}
|
||||
data-test="explore-results-button"
|
||||
|
||||
@@ -111,9 +111,7 @@ const TemplateParamsEditor = ({
|
||||
title={t('Edit template parameters')}
|
||||
trigger={['hover']}
|
||||
>
|
||||
{/* ModalTrigger's own wrapper div already provides role="button"
|
||||
and the click handler; this inner div is just layout. */}
|
||||
<div css={{ width: 'inherit' }}>
|
||||
<div role="button" css={{ width: 'inherit' }}>
|
||||
{t('Parameters ')}
|
||||
<Badge count={paramCount} />
|
||||
{!isValid && (
|
||||
|
||||
@@ -101,7 +101,7 @@ test('shows the stop message and a re-run affordance when the query was stopped'
|
||||
expect(screen.getByText('Updating chart was stopped')).toBeInTheDocument();
|
||||
|
||||
const rerun = screen.getByText('click here');
|
||||
expect(rerun.tagName).toBe('BUTTON');
|
||||
fireEvent.click(rerun);
|
||||
expect(onQuery).toHaveBeenCalledTimes(1);
|
||||
fireEvent.keyDown(rerun, { key: 'Enter' });
|
||||
expect(onQuery).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
@@ -30,8 +30,9 @@ import {
|
||||
type FilterState,
|
||||
type JsonObject,
|
||||
type AgGridChartState,
|
||||
handleKeyboardActivation,
|
||||
} from '@superset-ui/core';
|
||||
import { css, styled } from '@apache-superset/core/theme';
|
||||
import { styled } from '@apache-superset/core/theme';
|
||||
import type { ChartState, Datasource, ChartStatus } from 'src/explore/types';
|
||||
import { PLACEHOLDER_DATASOURCE } from 'src/dashboard/constants';
|
||||
import { EmptyState, Loading } from '@superset-ui/core/components';
|
||||
@@ -447,21 +448,14 @@ function Chart({
|
||||
description={
|
||||
<span>
|
||||
{t('Run a new query using the "Update chart" button or')}{' '}
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onQuery}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
`}
|
||||
onKeyDown={handleKeyboardActivation(() => onQuery?.())}
|
||||
>
|
||||
{t('click here')}
|
||||
</button>
|
||||
</span>
|
||||
.
|
||||
</span>
|
||||
}
|
||||
@@ -496,21 +490,14 @@ function Chart({
|
||||
{t(
|
||||
'Click on "Create chart" button in the control panel on the left to preview a visualization or',
|
||||
)}{' '}
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onQuery}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
`}
|
||||
onKeyDown={handleKeyboardActivation(() => onQuery?.())}
|
||||
>
|
||||
{t('click here')}
|
||||
</button>
|
||||
</span>
|
||||
.
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ test('render breadcrumbs', async () => {
|
||||
// we need to assert that there is only 1 element now
|
||||
// eslint-disable-next-line jest-dom/prefer-in-document
|
||||
expect(newBreadcrumbItems).toHaveLength(1);
|
||||
expect(within(newBreadcrumbItems[0]).getByText('gender')).toBeInTheDocument();
|
||||
expect(within(breadcrumbItems[0]).getByText('gender')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should render "Edit chart" as disabled without can_explore permission', async () => {
|
||||
|
||||
@@ -17,7 +17,14 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
SyntheticEvent,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { t } from '@apache-superset/core/translation';
|
||||
import {
|
||||
BinaryQueryObjectFilterClause,
|
||||
@@ -28,6 +35,7 @@ import {
|
||||
isDefined,
|
||||
ContextMenuFilters,
|
||||
AdhocFilter,
|
||||
handleKeyboardActivation,
|
||||
} from '@superset-ui/core';
|
||||
import { Alert } from '@apache-superset/core/components';
|
||||
import { css, useTheme } from '@apache-superset/core/theme';
|
||||
@@ -554,27 +562,30 @@ export default function DrillByModal({
|
||||
items={breadcrumbItems}
|
||||
itemRender={(route, _, routes, paths) => {
|
||||
const isLastElement = routes.indexOf(route) === routes.length - 1;
|
||||
// `route.onClick` is typed by antd as a `MouseEventHandler`, but
|
||||
// the underlying handler ignores its argument, so it's safe to
|
||||
// broaden it to an optional `SyntheticEvent` callback here to
|
||||
// reuse it as the keyboard-activation handler below.
|
||||
const onRouteClick = route.onClick as
|
||||
((event?: SyntheticEvent) => void) | undefined;
|
||||
return isLastElement ? (
|
||||
<span data-test="drill-by-breadcrumb-item">
|
||||
{route.title}
|
||||
{paths}
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
data-test="drill-by-breadcrumb-item"
|
||||
onClick={route.onClick}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onRouteClick}
|
||||
onKeyDown={handleKeyboardActivation(() => onRouteClick?.())}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
`}
|
||||
>
|
||||
{route.title}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -84,7 +84,7 @@ export const DrillBySubmenu = ({
|
||||
const [debouncedSearchInput, setDebouncedSearchInput] = useState('');
|
||||
const [popoverOpen, setPopoverOpen] = useState(false);
|
||||
const ref = useRef<InputRef>(null);
|
||||
const menuItemRef = useRef<HTMLButtonElement>(null);
|
||||
const menuItemRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const columns = useMemo(
|
||||
() => (dataset ? ensureIsArray(dataset.drillable_columns) : []),
|
||||
@@ -284,18 +284,11 @@ export const DrillBySubmenu = ({
|
||||
);
|
||||
|
||||
const menuItem = (
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
ref={menuItemRef}
|
||||
aria-disabled={isDisabled}
|
||||
role="button"
|
||||
tabIndex={isDisabled ? -1 : 0}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -306,6 +299,12 @@ export const DrillBySubmenu = ({
|
||||
}
|
||||
`}
|
||||
onClick={() => !isDisabled && setPopoverOpen(!popoverOpen)}
|
||||
onKeyDown={e => {
|
||||
if (!isDisabled && (e.key === 'Enter' || e.key === ' ')) {
|
||||
e.preventDefault();
|
||||
setPopoverOpen(!popoverOpen);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span>{t('Drill by')}</span>
|
||||
{isDisabled ? (
|
||||
@@ -313,7 +312,7 @@ export const DrillBySubmenu = ({
|
||||
) : (
|
||||
<Icons.RightOutlined iconSize="s" iconColor={theme.colorTextTertiary} />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (isDisabled) {
|
||||
|
||||
@@ -58,19 +58,11 @@ const DownloadDropdown = ({
|
||||
}}
|
||||
>
|
||||
<Tooltip title={t('Download')}>
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
aria-label={t('Download')}
|
||||
data-test="drill-detail-download-btn"
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
`}
|
||||
>
|
||||
<Icons.DownloadOutlined
|
||||
iconColor={theme.colorIcon}
|
||||
@@ -81,7 +73,7 @@ const DownloadDropdown = ({
|
||||
}
|
||||
`}
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Dropdown>
|
||||
);
|
||||
|
||||
@@ -158,12 +158,11 @@ export default function TableControls({
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={t('Reload')}>
|
||||
{/* role is auto-computed by BaseIconComponent as "button" since
|
||||
onClick is present, so no explicit role needed here. */}
|
||||
<Icons.ReloadOutlined
|
||||
iconColor={theme.colorIcon}
|
||||
iconSize="l"
|
||||
aria-label={t('Reload')}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onReload}
|
||||
/>
|
||||
|
||||
@@ -31,7 +31,7 @@ export const InteractiveCopyToClipboard = ({ copyNode, ...rest }: any) => {
|
||||
if (copyNode === 'Icon') {
|
||||
node = <Icons.CopyOutlined />;
|
||||
} else if (copyNode === 'Text') {
|
||||
node = <button type="button">Copy</button>;
|
||||
node = <span role="button">Copy</span>;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -100,7 +100,7 @@ function CopyToClip({
|
||||
}
|
||||
const handleKeyDown = disabled
|
||||
? undefined
|
||||
: (event: KeyboardEvent<HTMLButtonElement>) => {
|
||||
: (event: KeyboardEvent<HTMLSpanElement>) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
// Prevent space-scroll when the wrapper is focused.
|
||||
event.preventDefault();
|
||||
@@ -108,23 +108,16 @@ function CopyToClip({
|
||||
}
|
||||
};
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
`}
|
||||
<span
|
||||
style={{ cursor }}
|
||||
onClick={disabled ? undefined : onClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
role="button"
|
||||
aria-disabled={disabled || undefined}
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
>
|
||||
{copyNode}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
}, [copyNode, disabled, onClick]);
|
||||
|
||||
|
||||
@@ -84,12 +84,7 @@ const ConfirmModalStyled = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSpan = styled.button`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
const StyledSpan = styled.span`
|
||||
cursor: pointer;
|
||||
color: ${({ theme }) => theme.colorPrimaryText};
|
||||
&: hover {
|
||||
@@ -207,7 +202,8 @@ const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({
|
||||
{
|
||||
Cell: ({ row: { original } }: any) => (
|
||||
<StyledSpan
|
||||
type="button"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
data-test="datasource-link"
|
||||
onClick={() => selectDatasource({ type: 'table', ...original })}
|
||||
>
|
||||
|
||||
@@ -446,12 +446,11 @@ export default function CRUDCollection({
|
||||
color: ${theme.colorTextTertiary};
|
||||
`}
|
||||
>
|
||||
{/* role is auto-computed by BaseIconComponent as "button" since
|
||||
onClick is present, so no explicit role needed here. */}
|
||||
<Icons.DeleteOutlined
|
||||
aria-label={t('Delete item')}
|
||||
className="pointer"
|
||||
data-test="crud-delete-icon"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => deleteItem(record.id)}
|
||||
iconSize="l"
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
SupersetClient,
|
||||
getClientErrorObject,
|
||||
getExtensionsRegistry,
|
||||
handleKeyboardActivation,
|
||||
} from '@superset-ui/core';
|
||||
import { GenericDataType } from '@apache-superset/core/common';
|
||||
import { t } from '@apache-superset/core/translation';
|
||||
@@ -1753,17 +1754,14 @@ function DatasourceEditor({
|
||||
() => (
|
||||
<div>
|
||||
<EditLockContainer>
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
css={themeParam => css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
color: ${themeParam.colorTextTertiary};
|
||||
`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onChangeEditMode}
|
||||
onKeyDown={handleKeyboardActivation(onChangeEditMode)}
|
||||
>
|
||||
{isEditMode ? (
|
||||
<Icons.UnlockOutlined
|
||||
@@ -1780,7 +1778,7 @@ function DatasourceEditor({
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</span>
|
||||
{!isEditMode && <div>{t('Click the lock to make changes.')}</div>}
|
||||
{isEditMode && (
|
||||
<div>{t('Click the lock to prevent further changes.')}</div>
|
||||
|
||||
@@ -26,7 +26,6 @@ jest.mock(
|
||||
'@superset-ui/core/components/Icons/AsyncIcon',
|
||||
() =>
|
||||
({ fileName }: { fileName: string }) => (
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors AsyncIcon's real span+role="img" shape
|
||||
<span role="img" aria-label={fileName.replace('_', '-')} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -25,7 +25,6 @@ jest.mock(
|
||||
'@superset-ui/core/components/Icons/AsyncIcon',
|
||||
() =>
|
||||
({ fileName }: { fileName: string }) => (
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors AsyncIcon's real span+role="img" shape
|
||||
<span role="img" aria-label={fileName.replace('_', '-')} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -25,7 +25,6 @@ jest.mock(
|
||||
'@superset-ui/core/components/Icons/AsyncIcon',
|
||||
() =>
|
||||
({ fileName }: { fileName: string }) => (
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors AsyncIcon's real span+role="img" shape
|
||||
<span role="img" aria-label={fileName.replace('_', '-')} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { handleKeyboardActivation } from '@superset-ui/core';
|
||||
import { useState } from 'react';
|
||||
import { t } from '@apache-superset/core/translation';
|
||||
import { Alert } from '@apache-superset/core/components';
|
||||
import { css, useTheme } from '@apache-superset/core/theme';
|
||||
import { useTheme } from '@apache-superset/core/theme';
|
||||
import {
|
||||
Icons,
|
||||
Modal,
|
||||
@@ -99,21 +100,15 @@ export const ErrorAlert: React.FC<ErrorAlertProps> = ({
|
||||
{descriptionDetails}
|
||||
</Typography.Paragraph>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={toggleDescription}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
`}
|
||||
onKeyDown={handleKeyboardActivation(toggleDescription)}
|
||||
style={{ textDecoration: 'underline', cursor: 'pointer' }}
|
||||
>
|
||||
{isDescriptionVisible ? t('See less') : t('See more')}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
@@ -134,19 +129,14 @@ export const ErrorAlert: React.FC<ErrorAlertProps> = ({
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={`${errorType}: ${message}`}>
|
||||
<button
|
||||
type="button"
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
`}
|
||||
<span
|
||||
role="button"
|
||||
onClick={() => setShowModal(true)}
|
||||
onKeyDown={handleKeyboardActivation(() => setShowModal(true))}
|
||||
tabIndex={0}
|
||||
>
|
||||
{renderTrigger()}
|
||||
</button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Modal
|
||||
name={errorType}
|
||||
|
||||
@@ -26,7 +26,6 @@ jest.mock(
|
||||
'@superset-ui/core/components/Icons/AsyncIcon',
|
||||
() =>
|
||||
({ fileName }: { fileName: string }) => (
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors AsyncIcon's real span+role="img" shape
|
||||
<span role="img" aria-label={fileName.replace('_', '-')} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -25,7 +25,6 @@ jest.mock(
|
||||
'@superset-ui/core/components/Icons/AsyncIcon',
|
||||
() =>
|
||||
({ fileName }: { fileName: string }) => (
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors AsyncIcon's real span+role="img" shape
|
||||
<span role="img" aria-label={fileName.replace('_', '-')} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -25,7 +25,6 @@ jest.mock(
|
||||
'@superset-ui/core/components/Icons/AsyncIcon',
|
||||
() =>
|
||||
({ fileName }: { fileName: string }) => (
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors AsyncIcon's real span+role="img" shape
|
||||
<span role="img" aria-label={fileName.replace('_', '-')} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -25,7 +25,6 @@ jest.mock(
|
||||
'@superset-ui/core/components/Icons/AsyncIcon',
|
||||
() =>
|
||||
({ fileName }: { fileName: string }) => (
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role -- mirrors AsyncIcon's real span+role="img" shape
|
||||
<span role="img" aria-label={fileName.replace('_', '-')} />
|
||||
),
|
||||
);
|
||||
|
||||
@@ -259,11 +259,6 @@ function CompactSelectPanel(
|
||||
/>
|
||||
</SearchRow>
|
||||
)}
|
||||
{/* Custom-rendered, searchable, keyboard-navigable option list with
|
||||
rich per-option content (active state, icons); native <select>/
|
||||
<option> can't render that, so the ARIA listbox pattern is used
|
||||
instead of the tag the linter suggests. */}
|
||||
{/* eslint-disable-next-line jsx-a11y/prefer-tag-over-role */}
|
||||
<OptionList role="listbox" aria-label={t('Filter options')}>
|
||||
{isLoading ? (
|
||||
<StatusText>{t('Loading...')}</StatusText>
|
||||
@@ -280,8 +275,6 @@ function CompactSelectPanel(
|
||||
<OptionItem
|
||||
key={opt.value}
|
||||
$active={isActive}
|
||||
// See the OptionList comment above: native <option> can't render this.
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="option"
|
||||
aria-selected={isActive}
|
||||
tabIndex={0}
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { render, screen, within, waitFor } from 'spec/helpers/testing-library';
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
within,
|
||||
waitFor,
|
||||
fireEvent,
|
||||
} from 'spec/helpers/testing-library';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { QueryParamProvider } from 'use-query-params';
|
||||
import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
|
||||
@@ -360,7 +366,7 @@ describe('ListView', () => {
|
||||
expect(mockedPropsComprehensive.fetchData).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('switches view mode via click of the toggle buttons', async () => {
|
||||
test('switches view mode via keyboard activation of the toggle buttons', () => {
|
||||
const { container } = factory({
|
||||
renderCard: jest.fn(),
|
||||
data: [],
|
||||
@@ -373,10 +379,10 @@ describe('ListView', () => {
|
||||
|
||||
expect(screen.getByTestId('empty-state')).toHaveClass('card');
|
||||
|
||||
await userEvent.click(tableToggle);
|
||||
fireEvent.keyDown(tableToggle, { key: 'Enter' });
|
||||
expect(screen.getByTestId('empty-state')).toHaveClass('table');
|
||||
|
||||
await userEvent.click(cardToggle);
|
||||
fireEvent.keyDown(cardToggle, { key: ' ' });
|
||||
expect(screen.getByTestId('empty-state')).toHaveClass('card');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { handleKeyboardActivation } from '@superset-ui/core';
|
||||
import { t } from '@apache-superset/core/translation';
|
||||
import { Alert } from '@apache-superset/core/components';
|
||||
import { css, styled } from '@apache-superset/core/theme';
|
||||
import { styled } from '@apache-superset/core/theme';
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -184,15 +185,10 @@ const ViewModeContainer = styled.div`
|
||||
display: inline-block;
|
||||
|
||||
.toggle-button {
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
display: inline-block;
|
||||
border-radius: ${theme.borderRadius}px;
|
||||
padding: ${theme.sizeUnit}px;
|
||||
padding-bottom: ${theme.sizeUnit * 0.5}px;
|
||||
cursor: pointer;
|
||||
|
||||
&:first-of-type {
|
||||
margin-right: ${theme.sizeUnit * 2}px;
|
||||
@@ -209,15 +205,6 @@ const ViewModeContainer = styled.div`
|
||||
`}
|
||||
`;
|
||||
|
||||
const inlineTextButtonCss = css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const ClearAllButton = styled.button`
|
||||
${({ theme }) => `
|
||||
background: none;
|
||||
@@ -261,30 +248,34 @@ const ViewModeToggle = ({
|
||||
}) => (
|
||||
<ViewModeContainer>
|
||||
<Tooltip title={t('Grid view')}>
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-pressed={mode === 'card'}
|
||||
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onClick={(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.currentTarget.blur();
|
||||
setMode('card');
|
||||
}}
|
||||
onKeyDown={handleKeyboardActivation(() => setMode('card'))}
|
||||
className={cx('toggle-button', { active: mode === 'card' })}
|
||||
>
|
||||
<Icons.AppstoreOutlined iconSize="xl" />
|
||||
</button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip title={t('List view')}>
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-pressed={mode === 'table'}
|
||||
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onClick={(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.currentTarget.blur();
|
||||
setMode('table');
|
||||
}}
|
||||
onKeyDown={handleKeyboardActivation(() => setMode('table'))}
|
||||
className={cx('toggle-button', { active: mode === 'table' })}
|
||||
>
|
||||
<Icons.UnorderedListOutlined iconSize="xl" />
|
||||
</button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</ViewModeContainer>
|
||||
);
|
||||
@@ -514,15 +505,19 @@ export function ListView<T extends object = any>({
|
||||
</div>
|
||||
{Boolean(selectedFlatRows.length) && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
data-test="bulk-select-deselect-all"
|
||||
css={inlineTextButtonCss}
|
||||
style={{ cursor: 'pointer' }}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="deselect-all"
|
||||
onClick={() => toggleAllRowsSelected(false)}
|
||||
onKeyDown={handleKeyboardActivation(() =>
|
||||
toggleAllRowsSelected(false),
|
||||
)}
|
||||
>
|
||||
{t('Deselect all')}
|
||||
</button>
|
||||
</span>
|
||||
<div className="divider" />
|
||||
{bulkActions
|
||||
.filter(
|
||||
@@ -548,15 +543,19 @@ export function ListView<T extends object = any>({
|
||||
</Button>
|
||||
))}
|
||||
{enableBulkTag && (
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
data-test="bulk-select-tag-btn"
|
||||
css={inlineTextButtonCss}
|
||||
role="button"
|
||||
style={{ cursor: 'pointer' }}
|
||||
tabIndex={0}
|
||||
className="tag-btn"
|
||||
onClick={() => setShowBulkTagModal(true)}
|
||||
onKeyDown={handleKeyboardActivation(() =>
|
||||
setShowBulkTagModal(true),
|
||||
)}
|
||||
>
|
||||
{t('Add Tag')}
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -152,11 +152,10 @@ export default function Toast({ toast, onCloseToast }: ToastPresenterProps) {
|
||||
{icon}
|
||||
<Interweave content={toast.text} noHtml={!toast.allowHtml} />
|
||||
</div>
|
||||
{/* role is auto-computed by BaseIconComponent as "button" since
|
||||
onClick is present, so no explicit role needed here. */}
|
||||
<Icons.CloseOutlined
|
||||
iconSize="m"
|
||||
className="toast__close pointer"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={handleClosePress}
|
||||
aria-label={t('Close')}
|
||||
|
||||
@@ -27,7 +27,7 @@ import { initSliceEntities } from 'src/dashboard/reducers/sliceEntities';
|
||||
import { getInitialState as getInitialNativeFilterState } from 'src/dashboard/reducers/nativeFilters';
|
||||
import { applyDefaultFormData } from 'src/explore/store';
|
||||
import { buildActiveFilters } from 'src/dashboard/util/activeDashboardFilters';
|
||||
import { canDownloadData, findPermission } from 'src/utils/findPermission';
|
||||
import { findPermission } from 'src/utils/findPermission';
|
||||
import {
|
||||
canUserEditDashboard,
|
||||
canUserSaveAsDashboard,
|
||||
@@ -369,7 +369,7 @@ export const hydrateDashboard =
|
||||
'Superset',
|
||||
roles,
|
||||
),
|
||||
superset_can_download: canDownloadData(roles),
|
||||
superset_can_download: findPermission('can_csv', 'Superset', roles),
|
||||
common: {
|
||||
// legacy, please use state.common instead
|
||||
conf: common?.conf,
|
||||
|
||||
@@ -162,10 +162,6 @@ export const StatusIndicatorDot: FC<StatusIndicatorDotProps> = ({
|
||||
return (
|
||||
<span
|
||||
css={dotStyles}
|
||||
// role="status" is the standard WAI-ARIA live-region pattern for a
|
||||
// status indicator; <output> (the suggested tag) is for form
|
||||
// calculation results, not a fit here.
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="status"
|
||||
aria-label={`Auto-refresh status: ${displayStatus}`}
|
||||
data-test="status-indicator-dot"
|
||||
|
||||
@@ -295,10 +295,6 @@ export const CustomizationsBadge = ({ chartId }: CustomizationsBadgeProps) => {
|
||||
<StyledTag
|
||||
ref={triggerRef}
|
||||
aria-label={t('Display controls (%s)', customizationsCount)}
|
||||
// Tag doesn't support a polymorphic `as` prop, and this element has
|
||||
// no click action of its own (Tooltip attaches its own hover/focus
|
||||
// handlers to it) - tabIndex + role keep it keyboard-discoverable.
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
|
||||
@@ -23,7 +23,7 @@ import type { IconType } from '@superset-ui/core/components/Icons/types';
|
||||
import IconButton from './IconButton';
|
||||
|
||||
type DeleteComponentButtonProps = {
|
||||
onDelete: MouseEventHandler<HTMLButtonElement>;
|
||||
onDelete: MouseEventHandler<HTMLDivElement>;
|
||||
iconSize?: IconType['iconSize'];
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ const mockPopoverTriggerRef = {
|
||||
current: {
|
||||
focus: jest.fn(),
|
||||
},
|
||||
} as unknown as RefObject<HTMLButtonElement>;
|
||||
} as unknown as RefObject<HTMLDivElement>;
|
||||
|
||||
const createProps = () => ({
|
||||
popoverVisible: true,
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface DetailsPanelProps {
|
||||
children: JSX.Element;
|
||||
popoverVisible: boolean;
|
||||
popoverContentRef: RefObject<HTMLDivElement>;
|
||||
popoverTriggerRef: RefObject<HTMLButtonElement>;
|
||||
popoverTriggerRef: RefObject<HTMLDivElement>;
|
||||
setPopoverVisible: (visible: boolean) => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,11 +55,8 @@ export interface FiltersBadgeProps {
|
||||
chartId: number;
|
||||
}
|
||||
|
||||
const StyledFilterCount = styled.button`
|
||||
const StyledFilterCount = styled.div`
|
||||
${({ theme }) => `
|
||||
appearance: none;
|
||||
border: none;
|
||||
font: inherit;
|
||||
display: flex;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
@@ -138,7 +135,7 @@ export const FiltersBadge = ({ chartId }: FiltersBadgeProps) => {
|
||||
);
|
||||
const [popoverVisible, setPopoverVisible] = useState(false);
|
||||
const popoverContentRef = useRef<HTMLDivElement>(null);
|
||||
const popoverTriggerRef = useRef<HTMLButtonElement>(null);
|
||||
const popoverTriggerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const onHighlightFilterSource = useCallback(
|
||||
(path: string[]) => {
|
||||
@@ -147,7 +144,7 @@ export const FiltersBadge = ({ chartId }: FiltersBadgeProps) => {
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {
|
||||
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
||||
if (event.key === 'Enter') {
|
||||
setPopoverVisible(true);
|
||||
}
|
||||
@@ -309,14 +306,15 @@ export const FiltersBadge = ({ chartId }: FiltersBadgeProps) => {
|
||||
popoverTriggerRef={popoverTriggerRef}
|
||||
>
|
||||
<StyledFilterCount
|
||||
type="button"
|
||||
aria-label={t('Applied filters (%s)', filterCount)}
|
||||
aria-haspopup="true"
|
||||
role="button"
|
||||
ref={popoverTriggerRef}
|
||||
className={cx(
|
||||
'filter-counts',
|
||||
!!appliedCrossFilterIndicators.length && 'has-cross-filters',
|
||||
)}
|
||||
tabIndex={0}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<Icons.FilterOutlined iconSize="m" />
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
import { forwardRef, HTMLAttributes, MouseEventHandler } from 'react';
|
||||
import { styled, SupersetTheme } from '@apache-superset/core/theme';
|
||||
|
||||
interface IconButtonProps extends HTMLAttributes<HTMLButtonElement> {
|
||||
interface IconButtonProps extends HTMLAttributes<HTMLDivElement> {
|
||||
icon: JSX.Element;
|
||||
label?: string;
|
||||
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||
onClick: MouseEventHandler<HTMLDivElement>;
|
||||
disabled?: boolean;
|
||||
'data-test'?: string;
|
||||
}
|
||||
@@ -39,11 +39,7 @@ const activeCss = ({ theme }: { theme: SupersetTheme }) => `
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledButton = styled.button<{ isDisabled?: boolean }>`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
const StyledDiv = styled.div<{ isDisabled?: boolean }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
@@ -58,7 +54,7 @@ const StyledSpan = styled.span`
|
||||
margin-left: ${({ theme }) => theme.sizeUnit * 2}px;
|
||||
`;
|
||||
|
||||
const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||
const IconButton = forwardRef<HTMLDivElement, IconButtonProps>(
|
||||
(
|
||||
{
|
||||
icon,
|
||||
@@ -71,10 +67,11 @@ const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||
},
|
||||
ref,
|
||||
) => (
|
||||
<StyledButton
|
||||
<StyledDiv
|
||||
{...rest}
|
||||
ref={ref}
|
||||
type="button"
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
role="button"
|
||||
isDisabled={disabled}
|
||||
aria-disabled={disabled}
|
||||
data-test={dataTest}
|
||||
@@ -92,7 +89,7 @@ const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||
>
|
||||
{icon}
|
||||
{label && <StyledSpan>{label}</StyledSpan>}
|
||||
</StyledButton>
|
||||
</StyledDiv>
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ const createOwnStateWithChartState = (
|
||||
|
||||
const Chart = (props: ChartProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const descriptionRef = useRef<HTMLElement>(null);
|
||||
const descriptionRef = useRef<HTMLDivElement>(null);
|
||||
const headerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const boundActionCreators = useMemo(
|
||||
@@ -756,13 +756,14 @@ const Chart = (props: ChartProps) => {
|
||||
https://github.com/apache/superset/pull/23862
|
||||
*/}
|
||||
{isExpanded && slice.description_markdown && (
|
||||
<aside
|
||||
<div
|
||||
className="slice_description bs-callout bs-callout-default"
|
||||
ref={descriptionRef}
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: slice.description_markdown,
|
||||
}}
|
||||
role="complementary"
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { handleKeyboardActivation } from '@superset-ui/core';
|
||||
import {
|
||||
Fragment,
|
||||
useCallback,
|
||||
@@ -27,7 +28,7 @@ import {
|
||||
} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { css, styled } from '@apache-superset/core/theme';
|
||||
import { styled } from '@apache-superset/core/theme';
|
||||
import { t } from '@apache-superset/core/translation';
|
||||
|
||||
import { EditableTitle, EmptyState } from '@superset-ui/core/components';
|
||||
@@ -347,21 +348,16 @@ const Tab = (props: TabProps): ReactElement => {
|
||||
) : (
|
||||
<span>
|
||||
{t('You can add the components in the')}{' '}
|
||||
<button
|
||||
type="button"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => dispatch(setEditMode(true))}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
`}
|
||||
onKeyDown={handleKeyboardActivation(() =>
|
||||
dispatch(setEditMode(true)),
|
||||
)}
|
||||
>
|
||||
{t('edit mode')}
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
))
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ interface ShowDropIndicatorsResult {
|
||||
|
||||
interface CloseIconWithDropIndicatorProps {
|
||||
showDropIndicators: ShowDropIndicatorsResult;
|
||||
role?: string;
|
||||
tabIndex?: number;
|
||||
}
|
||||
|
||||
const CloseIconWithDropIndicator = (
|
||||
@@ -479,9 +481,9 @@ const Tabs = (props: TabsProps): ReactElement => {
|
||||
</>
|
||||
),
|
||||
closeIcon: (
|
||||
// rc-tabs already wraps closeIcon content in its own
|
||||
// <button role="tab" aria-label="remove">.
|
||||
<CloseIconWithDropIndicator
|
||||
role="button"
|
||||
tabIndex={tabIndex}
|
||||
showDropIndicators={showDropIndicators(tabIndex)}
|
||||
/>
|
||||
),
|
||||
|
||||
@@ -48,50 +48,10 @@ const mockProps: TabsRendererProps = {
|
||||
tabBarPaddingLeft: 16,
|
||||
};
|
||||
|
||||
// Mirrors the tab label markup of Tab.tsx: the title lives in a
|
||||
// .dragdroppable-tab container and renders as a textarea via EditableTitle
|
||||
const draggableTabProps: TabsRendererProps = {
|
||||
...mockProps,
|
||||
editMode: true,
|
||||
tabItems: [
|
||||
{
|
||||
...mockTabItems[0],
|
||||
label: (
|
||||
<div className="dragdroppable-tab">
|
||||
<span className="editable-title">
|
||||
<textarea defaultValue="Tab 1" />
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
mockTabItems[1],
|
||||
],
|
||||
};
|
||||
|
||||
// jsdom implements no PointerEvent, so @dnd-kit's PointerSensor never activates
|
||||
class MockPointerEvent extends MouseEvent {
|
||||
isPrimary: boolean;
|
||||
|
||||
pointerId: number;
|
||||
|
||||
constructor(type: string, init: PointerEventInit = {}) {
|
||||
super(type, init);
|
||||
this.isPrimary = init.isPrimary ?? true;
|
||||
this.pointerId = init.pointerId ?? 1;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
|
||||
describe('TabsRenderer', () => {
|
||||
const { PointerEvent: OriginalPointerEvent } = globalThis;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
globalThis.PointerEvent = MockPointerEvent as typeof PointerEvent;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.PointerEvent = OriginalPointerEvent;
|
||||
});
|
||||
|
||||
test('renders tabs container with correct test attributes', () => {
|
||||
@@ -239,29 +199,4 @@ describe('TabsRenderer', () => {
|
||||
expect(screen.getByText('Tab 1 Content')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Tab 2 Content')).not.toBeInTheDocument(); // Not active
|
||||
});
|
||||
|
||||
test('drags from the tab title and shows the drag indicator only then', () => {
|
||||
render(<TabsRenderer {...draggableTabProps} />);
|
||||
const container = screen.getByTestId('dashboard-component-tabs');
|
||||
const title = container.querySelector('textarea') as HTMLTextAreaElement;
|
||||
|
||||
// At rest the title keeps the text cursor it sets on itself
|
||||
expect(container).not.toHaveStyleRule('cursor', 'move', {
|
||||
target: '.dragdroppable-tab *',
|
||||
});
|
||||
|
||||
// Pressing on the title and moving past the sensor's distance constraint
|
||||
// has to start a drag: the title covers most of the tab, so a tab that
|
||||
// cannot be dragged from there cannot really be dragged at all
|
||||
fireEvent.pointerDown(title, { button: 0, isPrimary: true, clientX: 0 });
|
||||
fireEvent.pointerMove(document, {
|
||||
button: 0,
|
||||
isPrimary: true,
|
||||
clientX: 50,
|
||||
});
|
||||
|
||||
expect(container).toHaveStyleRule('cursor', 'move', {
|
||||
target: '.dragdroppable-tab *',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,16 +72,10 @@ const StyledTabsContainer = styled.div<{ isDragging?: boolean }>`
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide ink-bar during drag */
|
||||
${({ isDragging }) =>
|
||||
isDragging &&
|
||||
`
|
||||
/* Show the drag indicator during drag, over the tab title textarea too.
|
||||
The doubled parent outranks the title's own cursor; a single & loses. */
|
||||
&& .dragdroppable-tab * {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
/* Hide ink-bar during drag */
|
||||
.ant-tabs-card > .ant-tabs-nav .ant-tabs-ink-bar,
|
||||
.ant-tabs > .ant-tabs-nav .ant-tabs-ink-bar {
|
||||
display: none !important;
|
||||
|
||||
@@ -80,8 +80,7 @@ const CrossFilterChartTitle = (props: {
|
||||
<StyledIconSearch
|
||||
iconSize="s"
|
||||
data-test="cross-filters-highlight-emitter"
|
||||
// role is auto-computed by BaseIconComponent as "button" whenever
|
||||
// onClick is present, so no explicit role here.
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={t('Locate the chart')}
|
||||
onClick={onHighlightFilterSource}
|
||||
|
||||
@@ -177,8 +177,11 @@ test('Uses callbacks on click', () => {
|
||||
expect(DEFAULT_PROPS.removeCustomScope).toHaveBeenCalledWith(4);
|
||||
});
|
||||
|
||||
test('Renders charts scoping list panel with FilterTitle rendered as a button', () => {
|
||||
test('Renders charts scoping list panel with FilterTitle rendered with role="button"', () => {
|
||||
setup();
|
||||
expect(screen.getByText('All charts/global scoping')).toBeVisible();
|
||||
expect(screen.getByText('All charts/global scoping').tagName).toBe('BUTTON');
|
||||
expect(screen.getByText('All charts/global scoping')).toHaveAttribute(
|
||||
'role',
|
||||
'button',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -141,16 +141,8 @@ export const ChartsScopingListPanel = ({
|
||||
</Button>
|
||||
</AddButtonContainer>
|
||||
<FilterTitle
|
||||
as="button"
|
||||
{...{ type: 'button' }}
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setCurrentChartId(undefined)}
|
||||
className={activeChartId === undefined ? 'active' : ''}
|
||||
>
|
||||
|
||||
@@ -47,12 +47,6 @@ const CrossFiltersVerticalCollapse = (props: {
|
||||
|
||||
const sectionHeaderStyle = useCallback(
|
||||
(theme: SupersetTheme) => css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -125,10 +119,21 @@ const CrossFiltersVerticalCollapse = (props: {
|
||||
return (
|
||||
<div css={sectionContainerStyle}>
|
||||
{!hideHeader && (
|
||||
<button type="button" css={sectionHeaderStyle} onClick={toggleSection}>
|
||||
<div
|
||||
css={sectionHeaderStyle}
|
||||
onClick={toggleSection}
|
||||
onKeyDown={e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
toggleSection();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<h4 css={sectionTitleStyle}>{t('Cross-filters')}</h4>
|
||||
<Icons.UpOutlined iconSize="m" css={iconStyle(isOpen, theme)} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{isOpen && <div css={sectionContentStyle}>{crossFiltersIndicators}</div>}
|
||||
{isOpen && <div css={dividerStyle} data-test="cross-filters-divider" />}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { handleKeyboardActivation } from '@superset-ui/core';
|
||||
import { ReactNode, FC, memo } from 'react';
|
||||
import { css } from '@apache-superset/core/theme';
|
||||
|
||||
import { getFilterBarTestId } from '../utils';
|
||||
|
||||
@@ -30,20 +30,15 @@ export const FilterConfigurationLink: FC<FCBProps> = ({
|
||||
onClick,
|
||||
children,
|
||||
}) => (
|
||||
<button
|
||||
type="button"
|
||||
css={css`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
`}
|
||||
<div
|
||||
{...getFilterBarTestId('create-filter')}
|
||||
onClick={onClick}
|
||||
onKeyDown={onClick ? handleKeyboardActivation(onClick) : undefined}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default memo(FilterConfigurationLink);
|
||||
|
||||
@@ -236,10 +236,6 @@ export const DescriptionToolTip = ({
|
||||
whiteSpace: 'normal',
|
||||
}}
|
||||
>
|
||||
{/* Deliberate role="button" on this tooltip-trigger icon (no click
|
||||
handler) — mirrors DeckglLayerVisibilityTooltip below; not a fit
|
||||
for the linter's suggested <button> tag. */}
|
||||
{/* eslint-disable-next-line jsx-a11y/prefer-tag-over-role */}
|
||||
<StyledInfoCircleOutlined className="text-muted" role="button" />
|
||||
</Tooltip>
|
||||
</ToolTipContainer>
|
||||
@@ -253,12 +249,8 @@ export const DeckglLayerVisibilityTooltip = () => (
|
||||
)}
|
||||
placement="right"
|
||||
>
|
||||
{/* Deliberate role="button" on this tooltip-trigger icon (no click
|
||||
handler) — covered by existing test expectations; not a fit for
|
||||
the linter's suggested <button> tag. */}
|
||||
<StyledInfoCircleOutlined
|
||||
className="text-muted"
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="button"
|
||||
data-test="deckgl-layer-visibility-tooltip-icon"
|
||||
/>
|
||||
|
||||
@@ -104,13 +104,7 @@ const SectionContainer = styled.div`
|
||||
margin-bottom: ${({ theme }) => theme.sizeUnit * 3}px;
|
||||
`;
|
||||
|
||||
const SectionHeader = styled.button`
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
const SectionHeader = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -323,9 +317,15 @@ const FilterControls: FC<FilterControlsProps> = ({
|
||||
<SectionContainer>
|
||||
{!hideHeader && (
|
||||
<SectionHeader
|
||||
type="button"
|
||||
aria-expanded={sectionsOpen.filters}
|
||||
onClick={() => toggleSection('filters')}
|
||||
onKeyDown={e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
toggleSection('filters');
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<Title
|
||||
level={5}
|
||||
@@ -361,9 +361,15 @@ const FilterControls: FC<FilterControlsProps> = ({
|
||||
<SectionContainer>
|
||||
{!hideHeader && (
|
||||
<SectionHeader
|
||||
type="button"
|
||||
aria-expanded={sectionsOpen.chartCustomization}
|
||||
onClick={() => toggleSection('chartCustomization')}
|
||||
onKeyDown={e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
toggleSection('chartCustomization');
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<Title
|
||||
level={5}
|
||||
|
||||
@@ -203,11 +203,6 @@ const DescriptionTooltip = ({ description }: { description: string }) => (
|
||||
>
|
||||
<Icons.InfoCircleOutlined
|
||||
className="text-muted"
|
||||
// Deliberate role="button" override on this tooltip-trigger icon
|
||||
// (no click handler; BaseIconComponent would otherwise auto-compute
|
||||
// role="img" since there's no onClick) — matches the same pattern
|
||||
// used by DescriptionToolTip/DeckglLayerVisibilityTooltip.
|
||||
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
||||
role="button"
|
||||
css={theme => ({
|
||||
paddingLeft: `${theme.sizeUnit}px`,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user