mirror of
https://github.com/apache/superset.git
synced 2026-07-07 15:25:36 +00:00
Compare commits
49 Commits
ts_migrate
...
prefer-bin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d32c8834d | ||
|
|
40164300e5 | ||
|
|
c444eed63e | ||
|
|
1df5e59fdf | ||
|
|
77f66e7434 | ||
|
|
2c81eb6c39 | ||
|
|
09c4afc894 | ||
|
|
229d92590a | ||
|
|
f4f516c64c | ||
|
|
fe1fddde05 | ||
|
|
7e67deead7 | ||
|
|
6e02603098 | ||
|
|
4518f6999c | ||
|
|
aff847b3af | ||
|
|
b24aca0304 | ||
|
|
2c453035e4 | ||
|
|
4fe11869fc | ||
|
|
a0a49f9300 | ||
|
|
29d2fac485 | ||
|
|
0c5da6cb5d | ||
|
|
da6947d295 | ||
|
|
2db8f809ba | ||
|
|
5912fad745 | ||
|
|
dc41c45bec | ||
|
|
88ee90c579 | ||
|
|
bbb2279644 | ||
|
|
1958df6b83 | ||
|
|
58bd3bfcf0 | ||
|
|
d6eb6e08d0 | ||
|
|
96cb6030c8 | ||
|
|
94d47113ea | ||
|
|
f756cee01b | ||
|
|
e8926f177d | ||
|
|
16f4516903 | ||
|
|
000d353ef3 | ||
|
|
83b6f672ff | ||
|
|
0dc48e9b41 | ||
|
|
fe9eef9198 | ||
|
|
8a8248b575 | ||
|
|
42d9a78777 | ||
|
|
31a15c5162 | ||
|
|
67b21c45df | ||
|
|
b280ab9e1f | ||
|
|
c42be77c25 | ||
|
|
160917eae8 | ||
|
|
68b84acd93 | ||
|
|
0aa48b6564 | ||
|
|
0fc1955049 | ||
|
|
8a704d293b |
125
.cursor/rules/dev-standard.mdc
Normal file
125
.cursor/rules/dev-standard.mdc
Normal file
@@ -0,0 +1,125 @@
|
||||
---
|
||||
description: Apache Superset development standards and guidelines for Cursor IDE
|
||||
globs: ["**/*.py", "**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.sql", "**/*.md"]
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Apache Superset Development Standards for Cursor IDE
|
||||
|
||||
Apache Superset is a data visualization platform with Flask/Python backend and React/TypeScript frontend.
|
||||
|
||||
## ⚠️ CRITICAL: Ongoing Refactors (What NOT to Do)
|
||||
|
||||
**These migrations are actively happening - avoid deprecated patterns:**
|
||||
|
||||
### Frontend Modernization
|
||||
- **NO `any` types** - Use proper TypeScript types
|
||||
- **NO JavaScript files** - Convert to TypeScript (.ts/.tsx)
|
||||
- **NO Enzyme** - Use React Testing Library/Jest (Enzyme fully removed)
|
||||
- **Use @superset-ui/core** - Don't import Ant Design directly
|
||||
|
||||
### Testing Strategy Migration
|
||||
- **Prefer unit tests** over integration tests
|
||||
- **Prefer integration tests** over Cypress end-to-end tests
|
||||
- **Cypress is last resort** - Actively moving away from Cypress
|
||||
- **Use Jest + React Testing Library** for component testing
|
||||
|
||||
### Backend Type Safety
|
||||
- **Add type hints** - All new Python code needs proper typing
|
||||
- **MyPy compliance** - Run `pre-commit run mypy` to validate
|
||||
- **SQLAlchemy typing** - Use proper model annotations
|
||||
|
||||
## Code Standards
|
||||
|
||||
### TypeScript Frontend
|
||||
- **NO `any` types** - Use proper TypeScript
|
||||
- **Functional components** with hooks
|
||||
- **@superset-ui/core** for UI components (not direct antd)
|
||||
- **Jest** for testing (NO Enzyme)
|
||||
- **Redux** for global state, hooks for local
|
||||
|
||||
### Python Backend
|
||||
- **Type hints required** for all new code
|
||||
- **MyPy compliant** - run `pre-commit run mypy`
|
||||
- **SQLAlchemy models** with proper typing
|
||||
- **pytest** for testing
|
||||
|
||||
### Apache License Headers
|
||||
- **New files require ASF license headers** - When creating new code files, include the standard Apache Software Foundation license header
|
||||
- **LLM instruction files are excluded** - Files like LLMS.md, CLAUDE.md, etc. are in `.rat-excludes` to avoid header token overhead
|
||||
|
||||
## Key Directory Structure
|
||||
|
||||
```
|
||||
superset/
|
||||
├── superset/ # Python backend (Flask, SQLAlchemy)
|
||||
│ ├── views/api/ # REST API endpoints
|
||||
│ ├── models/ # Database models
|
||||
│ └── connectors/ # Database connections
|
||||
├── superset-frontend/src/ # React TypeScript frontend
|
||||
│ ├── components/ # Reusable components
|
||||
│ ├── explore/ # Chart builder
|
||||
│ ├── dashboard/ # Dashboard interface
|
||||
│ └── SqlLab/ # SQL editor
|
||||
├── superset-frontend/packages/
|
||||
│ └── superset-ui-core/ # UI component library (USE THIS)
|
||||
├── tests/ # Python/integration tests
|
||||
├── docs/ # Documentation (UPDATE FOR CHANGES)
|
||||
└── UPDATING.md # Breaking changes log
|
||||
```
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Dataset-Centric Approach
|
||||
Charts built from enriched datasets containing:
|
||||
- Dimension columns with labels/descriptions
|
||||
- Predefined metrics as SQL expressions
|
||||
- Self-service analytics within defined contexts
|
||||
|
||||
### Security & Features
|
||||
- **RBAC**: Role-based access via Flask-AppBuilder
|
||||
- **Feature flags**: Control feature rollouts
|
||||
- **Row-level security**: SQL-based data access control
|
||||
|
||||
## Test Utilities
|
||||
|
||||
### Python Test Helpers
|
||||
- **`SupersetTestCase`** - Base class in `tests/integration_tests/base_tests.py`
|
||||
- **`@with_config`** - Config mocking decorator
|
||||
- **`@with_feature_flags`** - Feature flag testing
|
||||
- **`login_as()`, `login_as_admin()`** - Authentication helpers
|
||||
- **`create_dashboard()`, `create_slice()`** - Data setup utilities
|
||||
|
||||
### TypeScript Test Helpers
|
||||
- **`superset-frontend/spec/helpers/testing-library.tsx`** - Custom render() with providers
|
||||
- **`createWrapper()`** - Redux/Router/Theme wrapper
|
||||
- **`selectOption()`** - Select component helper
|
||||
- **React Testing Library** - NO Enzyme (removed)
|
||||
|
||||
## Pre-commit Validation
|
||||
|
||||
**Use pre-commit hooks for quality validation:**
|
||||
|
||||
```bash
|
||||
# Install hooks
|
||||
pre-commit install
|
||||
|
||||
# Quick validation (faster than --all-files)
|
||||
pre-commit run # Staged files only
|
||||
pre-commit run mypy # Python type checking
|
||||
pre-commit run prettier # Code formatting
|
||||
pre-commit run eslint # Frontend linting
|
||||
```
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
- **Documentation**: Update docs/ for any user-facing changes
|
||||
- **Breaking Changes**: Add to UPDATING.md
|
||||
- **Docstrings**: Required for new functions/classes
|
||||
- **Follow existing patterns**: Mimic code style, use existing libraries and utilities
|
||||
- **Type Safety**: This codebase is actively modernizing toward full TypeScript and type safety
|
||||
- **Always run `pre-commit run`** to validate changes before committing
|
||||
|
||||
---
|
||||
|
||||
**Note**: This codebase is actively modernizing toward full TypeScript and type safety. Always run `pre-commit run` to validate changes. Follow the ongoing refactors section to avoid deprecated patterns.
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -42,7 +42,7 @@ body:
|
||||
options:
|
||||
- master / latest-dev
|
||||
- "5.0.0"
|
||||
- "4.1.2"
|
||||
- "4.1.3"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
|
||||
17
.github/actions/setup-backend/action.yml
vendored
17
.github/actions/setup-backend/action.yml
vendored
@@ -28,7 +28,6 @@ runs:
|
||||
if [ "${{ inputs.python-version }}" = "current" ]; then
|
||||
echo "PYTHON_VERSION=3.11" >> $GITHUB_ENV
|
||||
elif [ "${{ inputs.python-version }}" = "next" ]; then
|
||||
# currently disabled in GHA matrixes because of library compatibility issues
|
||||
echo "PYTHON_VERSION=3.12" >> $GITHUB_ENV
|
||||
elif [ "${{ inputs.python-version }}" = "previous" ]; then
|
||||
echo "PYTHON_VERSION=3.10" >> $GITHUB_ENV
|
||||
@@ -40,7 +39,17 @@ runs:
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
cache: ${{ inputs.cache }}
|
||||
- name: Cache uv packages
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/uv
|
||||
key: uv-${{ runner.os }}-python${{ env.PYTHON_VERSION }}-${{ hashFiles('requirements/development.txt', 'requirements/base.txt') }}
|
||||
restore-keys: |
|
||||
uv-${{ runner.os }}-python${{ env.PYTHON_VERSION }}-
|
||||
- name: Install dependencies
|
||||
env:
|
||||
UV_CACHE_DIR: ~/.cache/uv
|
||||
UV_PREFER_BINARY: "1"
|
||||
run: |
|
||||
if [ "${{ inputs.install-superset }}" = "true" ]; then
|
||||
sudo apt-get update && sudo apt-get -y install libldap2-dev libsasl2-dev
|
||||
@@ -48,11 +57,11 @@ runs:
|
||||
pip install --upgrade pip setuptools wheel uv
|
||||
|
||||
if [ "${{ inputs.requirements-type }}" = "dev" ]; then
|
||||
uv pip install --system -r requirements/development.txt
|
||||
uv pip install --system --prefer-binary -r requirements/development.txt
|
||||
elif [ "${{ inputs.requirements-type }}" = "base" ]; then
|
||||
uv pip install --system -r requirements/base.txt
|
||||
uv pip install --system --prefer-binary -r requirements/base.txt
|
||||
fi
|
||||
|
||||
uv pip install --system -e .
|
||||
uv pip install --system --prefer-binary -e .
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
1
.github/copilot-instructions.md
vendored
Symbolic link
1
.github/copilot-instructions.md
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../LLMS.md
|
||||
82
.github/workflows/claude.yml
vendored
Normal file
82
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
name: Claude PR Assistant
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
check-permissions:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude'))
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
allowed: ${{ steps.check.outputs.allowed }}
|
||||
steps:
|
||||
- name: Check if user is allowed
|
||||
id: check
|
||||
run: |
|
||||
# List of allowed users
|
||||
ALLOWED_USERS="mistercrunch,rusackas"
|
||||
|
||||
# Get the commenter's username
|
||||
COMMENTER="${{ github.event.comment.user.login }}"
|
||||
|
||||
echo "Checking permissions for user: $COMMENTER"
|
||||
|
||||
# Check if user is in allowed list
|
||||
if [[ ",$ALLOWED_USERS," == *",$COMMENTER,"* ]]; then
|
||||
echo "allowed=true" >> $GITHUB_OUTPUT
|
||||
echo "✅ User $COMMENTER is allowed to use Claude"
|
||||
else
|
||||
echo "allowed=false" >> $GITHUB_OUTPUT
|
||||
echo "❌ User $COMMENTER is not allowed to use Claude"
|
||||
fi
|
||||
|
||||
deny-access:
|
||||
needs: check-permissions
|
||||
if: needs.check-permissions.outputs.allowed == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Comment access denied
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const message = `👋 Hi @${{ github.event.comment.user.login || github.event.review.user.login || github.event.issue.user.login }}!
|
||||
|
||||
Thanks for trying to use Claude Code, but currently only certain team members have access to this feature.
|
||||
|
||||
If you believe you should have access, please contact a project maintainer.`;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: message
|
||||
});
|
||||
|
||||
claude-code-action:
|
||||
needs: check-permissions
|
||||
if: needs.check-permissions.outputs.allowed == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude PR Action
|
||||
uses: anthropics/claude-code-action@beta
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
timeout_minutes: "60"
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -92,6 +92,7 @@ scripts/*.zip
|
||||
# IntelliJ
|
||||
*.iml
|
||||
venv
|
||||
.venv
|
||||
@eaDir/
|
||||
|
||||
# PyCharm
|
||||
@@ -126,4 +127,7 @@ docker/*local*
|
||||
# Jest test report
|
||||
test-report.html
|
||||
superset/static/stats/statistics.html
|
||||
|
||||
# LLM-related
|
||||
CLAUDE.local.md
|
||||
.aider*
|
||||
|
||||
@@ -76,3 +76,11 @@ ydb.svg
|
||||
erd.puml
|
||||
erd.svg
|
||||
intro_header.txt
|
||||
|
||||
# for LLMs
|
||||
llm-context.md
|
||||
LLMS.md
|
||||
CLAUDE.md
|
||||
CURSOR.md
|
||||
GEMINI.md
|
||||
GPT.md
|
||||
|
||||
58
CHANGELOG/4.1.3.md
Normal file
58
CHANGELOG/4.1.3.md
Normal file
@@ -0,0 +1,58 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
## Change Log
|
||||
|
||||
### 4.1.3 (Thu May 29 02:31:07 2025 -0500)
|
||||
|
||||
**Database Migrations**
|
||||
|
||||
**Features**
|
||||
|
||||
**Fixes**
|
||||
|
||||
- [#33522](https://github.com/apache/superset/pull/33522) fix(Sqllab): Autocomplete got stuck in UI when open it too fast (@rebenitez1802)
|
||||
- [#33425](https://github.com/apache/superset/pull/33425) fix(table-chart): time shift is not working (@justinpark)
|
||||
- [#32414](https://github.com/apache/superset/pull/32414) fix(api): Added uuid to list api calls (@withnale)
|
||||
- [#33354](https://github.com/apache/superset/pull/33354) fix: loading examples from raw.githubusercontent.com fails with 429 errors (@mistercrunch)
|
||||
- [#32382](https://github.com/apache/superset/pull/32382) fix(pinot): revert join and subquery flags (@yuribogomolov)
|
||||
- [#32473](https://github.com/apache/superset/pull/32473) fix(plugin-chart-echarts): remove erroneous upper bound value (@villebro)
|
||||
- [#33048](https://github.com/apache/superset/pull/33048) fix: improve error type on parse error (@justinpark)
|
||||
- [#32968](https://github.com/apache/superset/pull/32968) fix(pivot-table): Revert "fix(Pivot Table): Fix column width to respect currency config (#31414)" (@justinpark)
|
||||
- [#32795](https://github.com/apache/superset/pull/32795) fix(log): store navigation path to get correct logging path (@justinpark)
|
||||
- [#33216](https://github.com/apache/superset/pull/33216) fix: Downgrade to marshmallow<4 (@amotl)
|
||||
- [#32866](https://github.com/apache/superset/pull/32866) fix: make packages PEP 625 compliant (@sadpandajoe)
|
||||
- [#32035](https://github.com/apache/superset/pull/32035) fix(fe/dashboard-list): display modifier info for `Last modified` data (@hainenber)
|
||||
- [#32708](https://github.com/apache/superset/pull/32708) fix(logging): missing path in event data (@justinpark)
|
||||
- [#32699](https://github.com/apache/superset/pull/32699) fix: Signature of Celery pruner jobs (@michael-s-molina)
|
||||
- [#32681](https://github.com/apache/superset/pull/32681) fix(log): Update recent_activity by event name (@justinpark)
|
||||
- [#32608](https://github.com/apache/superset/pull/32608) fix(welcome): perf on distinct recent activities (@justinpark)
|
||||
- [#32572](https://github.com/apache/superset/pull/32572) fix: Log table retention policy (@michael-s-molina)
|
||||
- [#32406](https://github.com/apache/superset/pull/32406) fix(model/helper): represent RLS filter clause in proper textual SQL string (@hainenber)
|
||||
- [#32240](https://github.com/apache/superset/pull/32240) fix: upgrade to 3.11.11-slim-bookworm to address critical vulnerabilities (@gpchandran)
|
||||
- [#30858](https://github.com/apache/superset/pull/30858) fix(chart data): removing query from /chart/data payload when accessing as guest user (@fisjac)
|
||||
|
||||
**Others**
|
||||
|
||||
- [#33612](https://github.com/apache/superset/pull/33612) chore: update Dockerfile - Upgrade to 3.11.12 (@gpchandran)
|
||||
- [#33435](https://github.com/apache/superset/pull/33435) docs: CVEs fixed on 4.1.2 (@sha174n)
|
||||
- [#33339](https://github.com/apache/superset/pull/33339) chore(🦾): bump python h11 0.14.0 -> 0.16.0 (@github-actions[bot])
|
||||
- [#32745](https://github.com/apache/superset/pull/32745) chore(🦾): bump python sqlglot 26.1.3 -> 26.11.1 (@github-actions[bot])
|
||||
- [#32782](https://github.com/apache/superset/pull/32782) chore: Revert "chore: bump base image in Dockerfile with `ARG PY_VER=3.11.11-slim-bookworm`" (@sadpandajoe)
|
||||
- [#32780](https://github.com/apache/superset/pull/32780) chore: bump base image in Dockerfile with `ARG PY_VER=3.11.11-slim-bookworm` (@gpchandran)
|
||||
@@ -167,7 +167,7 @@ RUN mkdir -p \
|
||||
&& touch superset/static/version_info.json
|
||||
|
||||
# Install Playwright and optionally setup headless browsers
|
||||
ARG INCLUDE_CHROMIUM="true"
|
||||
ARG INCLUDE_CHROMIUM="false"
|
||||
ARG INCLUDE_FIREFOX="false"
|
||||
RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
|
||||
if [ "$INCLUDE_CHROMIUM" = "true" ] || [ "$INCLUDE_FIREFOX" = "true" ]; then \
|
||||
@@ -223,7 +223,7 @@ RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
|
||||
/app/docker/pip-install.sh --requires-build-essential -r requirements/base.txt
|
||||
# Install the superset package
|
||||
RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
|
||||
uv pip install .
|
||||
uv pip install -e .
|
||||
RUN python -m compileall /app/superset
|
||||
|
||||
USER superset
|
||||
@@ -246,7 +246,7 @@ RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
|
||||
/app/docker/pip-install.sh --requires-build-essential -r requirements/development.txt
|
||||
# Install the superset package
|
||||
RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
|
||||
uv pip install .
|
||||
uv pip install -e .
|
||||
|
||||
RUN uv pip install .[postgres]
|
||||
RUN python -m compileall /app/superset
|
||||
|
||||
148
LLMS.md
Normal file
148
LLMS.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# LLM Context Guide for Apache Superset
|
||||
|
||||
Apache Superset is a data visualization platform with Flask/Python backend and React/TypeScript frontend.
|
||||
|
||||
## ⚠️ CRITICAL: Ongoing Refactors (What NOT to Do)
|
||||
|
||||
**These migrations are actively happening - avoid deprecated patterns:**
|
||||
|
||||
### Frontend Modernization
|
||||
- **NO `any` types** - Use proper TypeScript types
|
||||
- **NO JavaScript files** - Convert to TypeScript (.ts/.tsx)
|
||||
- **Use @superset-ui/core** - Don't import Ant Design directly
|
||||
|
||||
### Testing Strategy Migration
|
||||
- **Prefer unit tests** over integration tests
|
||||
- **Prefer integration tests** over Cypress end-to-end tests
|
||||
- **Cypress is last resort** - Actively moving away from Cypress
|
||||
- **Use Jest + React Testing Library** for component testing
|
||||
|
||||
### Backend Type Safety
|
||||
- **Add type hints** - All new Python code needs proper typing
|
||||
- **MyPy compliance** - Run `pre-commit run mypy` to validate
|
||||
- **SQLAlchemy typing** - Use proper model annotations
|
||||
|
||||
## Key Directories
|
||||
|
||||
```
|
||||
superset/
|
||||
├── superset/ # Python backend (Flask, SQLAlchemy)
|
||||
│ ├── views/api/ # REST API endpoints
|
||||
│ ├── models/ # Database models
|
||||
│ └── connectors/ # Database connections
|
||||
├── superset-frontend/src/ # React TypeScript frontend
|
||||
│ ├── components/ # Reusable components
|
||||
│ ├── explore/ # Chart builder
|
||||
│ ├── dashboard/ # Dashboard interface
|
||||
│ └── SqlLab/ # SQL editor
|
||||
├── superset-frontend/packages/
|
||||
│ └── superset-ui-core/ # UI component library (USE THIS)
|
||||
├── tests/ # Python/integration tests
|
||||
├── docs/ # Documentation (UPDATE FOR CHANGES)
|
||||
└── UPDATING.md # Breaking changes log
|
||||
```
|
||||
|
||||
## Code Standards
|
||||
|
||||
### TypeScript Frontend
|
||||
- **Avoid `any` types** - Use proper TypeScript, reuse existing types
|
||||
- **Functional components** with hooks
|
||||
- **@superset-ui/core** for UI components (not direct antd)
|
||||
- **Jest** for testing (NO Enzyme)
|
||||
- **Redux** for global state where it exists, hooks for local
|
||||
|
||||
### Python Backend
|
||||
- **Type hints required** for all new code
|
||||
- **MyPy compliant** - run `pre-commit run mypy`
|
||||
- **SQLAlchemy models** with proper typing
|
||||
- **pytest** for testing
|
||||
|
||||
### Apache License Headers
|
||||
- **New files require ASF license headers** - When creating new code files, include the standard Apache Software Foundation license header
|
||||
- **LLM instruction files are excluded** - Files like LLMS.md, CLAUDE.md, etc. are in `.rat-excludes` to avoid header token overhead
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
- **docs/**: Update for any user-facing changes
|
||||
- **UPDATING.md**: Add breaking changes here
|
||||
- **Docstrings**: Required for new functions/classes
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Security & Features
|
||||
- **RBAC**: Role-based access via Flask-AppBuilder
|
||||
- **Feature flags**: Control feature rollouts
|
||||
- **Row-level security**: SQL-based data access control
|
||||
|
||||
## Test Utilities
|
||||
|
||||
### Python Test Helpers
|
||||
- **`SupersetTestCase`** - Base class in `tests/integration_tests/base_tests.py`
|
||||
- **`@with_config`** - Config mocking decorator
|
||||
- **`@with_feature_flags`** - Feature flag testing
|
||||
- **`login_as()`, `login_as_admin()`** - Authentication helpers
|
||||
- **`create_dashboard()`, `create_slice()`** - Data setup utilities
|
||||
|
||||
### TypeScript Test Helpers
|
||||
- **`superset-frontend/spec/helpers/testing-library.tsx`** - Custom render() with providers
|
||||
- **`createWrapper()`** - Redux/Router/Theme wrapper
|
||||
- **`selectOption()`** - Select component helper
|
||||
- **React Testing Library** - NO Enzyme (removed)
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
# Frontend
|
||||
npm run test # All tests
|
||||
npm run test -- filename.test.tsx # Single file
|
||||
|
||||
# Backend
|
||||
pytest # All tests
|
||||
pytest tests/unit_tests/specific_test.py # Single file
|
||||
pytest tests/unit_tests/ # Directory
|
||||
|
||||
# If pytest fails with database/setup issues, ask the user to run test environment setup
|
||||
```
|
||||
|
||||
## Environment Validation
|
||||
|
||||
**Quick Setup Check (run this first):**
|
||||
|
||||
```bash
|
||||
# Verify Superset is running
|
||||
curl -f http://localhost:8088/health || echo "❌ Setup required - see https://superset.apache.org/docs/contributing/development#working-with-llms"
|
||||
```
|
||||
|
||||
**If health checks fail:**
|
||||
"It appears you aren't set up properly. Please refer to the [Working with LLMs](https://superset.apache.org/docs/contributing/development#working-with-llms) section in the development docs for setup instructions."
|
||||
|
||||
**Key Project Files:**
|
||||
- `superset-frontend/package.json` - Frontend build scripts (`npm run dev` on port 9000, `npm run test`, `npm run lint`)
|
||||
- `pyproject.toml` - Python tooling (ruff, mypy configs)
|
||||
- `requirements/` folder - Python dependencies (base.txt, development.txt)
|
||||
|
||||
## Pre-commit Validation
|
||||
|
||||
**Use pre-commit hooks for quality validation:**
|
||||
|
||||
```bash
|
||||
# Install hooks
|
||||
pre-commit install
|
||||
|
||||
# Quick validation (faster than --all-files)
|
||||
pre-commit run # Staged files only
|
||||
pre-commit run mypy # Python type checking
|
||||
pre-commit run prettier # Code formatting
|
||||
pre-commit run eslint # Frontend linting
|
||||
```
|
||||
|
||||
## Platform-Specific Instructions
|
||||
|
||||
- **[CLAUDE.md](CLAUDE.md)** - For Claude/Anthropic tools
|
||||
- **[.github/copilot-instructions.md](.github/copilot-instructions.md)** - For GitHub Copilot
|
||||
- **[GEMINI.md](GEMINI.md)** - For Google Gemini tools
|
||||
- **[GPT.md](GPT.md)** - For OpenAI/ChatGPT tools
|
||||
- **[.cursor/rules/dev-standard.mdc](.cursor/rules/dev-standard.mdc)** - For Cursor editor
|
||||
|
||||
---
|
||||
|
||||
**LLM Note**: This codebase is actively modernizing toward full TypeScript and type safety. Always run `pre-commit run` to validate changes. Follow the ongoing refactors section to avoid deprecated patterns.
|
||||
@@ -23,7 +23,8 @@ This file documents any backwards-incompatible changes in Superset and
|
||||
assists people when migrating to a new version.
|
||||
|
||||
## Next
|
||||
|
||||
- [34258](https://github.com/apache/superset/pull/34258) changing the default in Dockerfile to INCLUDE_CHROMIUM="false" (from "true") in the past. This ensures the `lean` layer is lean by default, and people can opt-in to the `chromium` layer by setting the build arg `INCLUDE_CHROMIUM=true`. This is a breaking change for anyone using the `lean` layer, as it will no longer include Chromium by default.
|
||||
- [34204](https://github.com/apache/superset/pull/33603) OpenStreetView has been promoted as the new default for Deck.gl visualization since it can be enabled by default without requiring an API key. If you have Mapbox set up and want to disable OpenStreeView in your environment, please follow the steps documented here [https://superset.apache.org/docs/configuration/map-tiles].
|
||||
- [33116](https://github.com/apache/superset/pull/33116) In Echarts Series charts (e.g. Line, Area, Bar, etc.) charts, the `x_axis_sort_series` and `x_axis_sort_series_ascending` form data items have been renamed with `x_axis_sort` and `x_axis_sort_asc`.
|
||||
There's a migration added that can potentially affect a significant number of existing charts.
|
||||
- [32317](https://github.com/apache/superset/pull/32317) The horizontal filter bar feature is now out of testing/beta development and its feature flag `HORIZONTAL_FILTER_BAR` has been removed.
|
||||
|
||||
78
docs/docs/configuration/map-tiles.mdx
Normal file
78
docs/docs/configuration/map-tiles.mdx
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
title: Map Tiles
|
||||
sidebar_position: 12
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Map tiles
|
||||
|
||||
Superset uses OSM and Mapbox tiles by default. OSM is free but you still need setting your MAPBOX_API_KEY if you want to use mapbox maps.
|
||||
|
||||
## Setting map tiles
|
||||
|
||||
Map tiles can be set with `DECKGL_BASE_MAP` in your `superset_config.py` or `superset_config_docker.py`
|
||||
For adding your own map tiles, you can use the following format.
|
||||
|
||||
```python
|
||||
DECKGL_BASE_MAP = [
|
||||
['tile://https://your_personal_url/{z}/{x}/{y}.png', 'MyTile']
|
||||
]
|
||||
```
|
||||
Openstreetmap tiles url can be added without prefix.
|
||||
```python
|
||||
DECKGL_BASE_MAP = [
|
||||
['https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', 'OpenStreetMap']
|
||||
]
|
||||
```
|
||||
|
||||
Default values are:
|
||||
```python
|
||||
DECKGL_BASE_MAP = [
|
||||
['https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'Streets (OSM)'],
|
||||
['https://tile.osm.ch/osm-swiss-style/{z}/{x}/{y}.png', 'Topography (OSM)'],
|
||||
['mapbox://styles/mapbox/streets-v9', 'Streets'],
|
||||
['mapbox://styles/mapbox/dark-v9', 'Dark'],
|
||||
['mapbox://styles/mapbox/light-v9', 'Light'],
|
||||
['mapbox://styles/mapbox/satellite-streets-v9', 'Satellite Streets'],
|
||||
['mapbox://styles/mapbox/satellite-v9', 'Satellite'],
|
||||
['mapbox://styles/mapbox/outdoors-v9', 'Outdoors'],
|
||||
]
|
||||
```
|
||||
|
||||
It is possible to set only mapbox by removing osm tiles and other way around.
|
||||
|
||||
:::warning
|
||||
Setting `DECKGL_BASE_MAP` overwrite default values
|
||||
:::
|
||||
|
||||
After defining your map tiles, set them in these variables:
|
||||
- `CORS_OPTIONS`
|
||||
- `connect-src` of `TALISMAN_CONFIG` and `TALISMAN_CONFIG_DEV` variables.
|
||||
|
||||
```python
|
||||
ENABLE_CORS = True
|
||||
CORS_OPTIONS: dict[Any, Any] = {
|
||||
"origins": [
|
||||
"https://tile.openstreetmap.org",
|
||||
"https://tile.osm.ch",
|
||||
"https://your_personal_url/{z}/{x}/{y}.png",
|
||||
]
|
||||
}
|
||||
|
||||
.
|
||||
.
|
||||
|
||||
TALISMAN_CONFIG = {
|
||||
"content_security_policy": {
|
||||
...
|
||||
"connect-src": [
|
||||
"'self'",
|
||||
"https://api.mapbox.com",
|
||||
"https://events.mapbox.com",
|
||||
"https://tile.openstreetmap.org",
|
||||
"https://tile.osm.ch",
|
||||
"https://your_personal_url/{z}/{x}/{y}.png",
|
||||
],
|
||||
...
|
||||
}
|
||||
```
|
||||
@@ -78,7 +78,7 @@ Affecting the Docker build process:
|
||||
|
||||
- **SUPERSET_BUILD_TARGET (default=dev):** which --target to build, either `lean` or `dev` are commonly used
|
||||
- **INCLUDE_FIREFOX (default=false):** whether to include the Firefox headless browser in the build
|
||||
- **INCLUDE_CHROMIUM (default=false):** whether to include the Firefox headless browser in the build
|
||||
- **INCLUDE_CHROMIUM (default=false):** whether to include the Chromium headless browser in the build
|
||||
- **BUILD_TRANSLATIONS(default=false):** whether to compile the translations from the .po files available
|
||||
- **SUPERSET_LOAD_EXAMPLES (default=yes):** whether to load the examples into the database upon startup,
|
||||
save some precious time on startup by `SUPERSET_LOAD_EXAMPLES=no docker compose up`
|
||||
@@ -194,6 +194,48 @@ You can also run the pre-commit checks manually in various ways:
|
||||
Replace `<hook_id>` with the ID of the specific hook you want to run. You can find the list
|
||||
of available hooks in the `.pre-commit-config.yaml` file.
|
||||
|
||||
## Working with LLMs
|
||||
|
||||
### Environment Setup
|
||||
Ensure Docker Compose is running before starting LLM sessions:
|
||||
```bash
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Validate your environment:
|
||||
```bash
|
||||
curl -f http://localhost:8088/health && echo "✅ Superset ready"
|
||||
```
|
||||
|
||||
### LLM Session Best Practices
|
||||
- Always validate environment setup first using the health checks above
|
||||
- Use focused validation commands: `pre-commit run` (not `--all-files`)
|
||||
- **Read [LLMS.md](https://github.com/apache/superset/blob/master/LLMS.md) first** - Contains comprehensive development guidelines, coding standards, and critical refactor information
|
||||
- **Check platform-specific files** when available:
|
||||
- `CLAUDE.md` - For Claude/Anthropic tools
|
||||
- `CURSOR.md` - For Cursor editor
|
||||
- `GEMINI.md` - For Google Gemini tools
|
||||
- `GPT.md` - For OpenAI/ChatGPT tools
|
||||
- Follow the TypeScript migration guidelines and avoid deprecated patterns listed in LLMS.md
|
||||
|
||||
### Key Development Commands
|
||||
```bash
|
||||
# Frontend development
|
||||
cd superset-frontend
|
||||
npm run dev # Development server on http://localhost:9000
|
||||
npm run test # Run all tests
|
||||
npm run test -- filename.test.tsx # Run single test file
|
||||
npm run lint # Linting and type checking
|
||||
|
||||
# Backend validation
|
||||
pre-commit run mypy # Type checking
|
||||
pytest # Run all tests
|
||||
pytest tests/unit_tests/specific_test.py # Run single test file
|
||||
pytest tests/unit_tests/ # Run all tests in directory
|
||||
```
|
||||
|
||||
For detailed development context, environment setup, and coding guidelines, see [LLMS.md](https://github.com/apache/superset/blob/master/LLMS.md).
|
||||
|
||||
## Alternatives to `docker compose`
|
||||
|
||||
:::caution
|
||||
@@ -614,9 +656,6 @@ act --job test-python-38 --secret GITHUB_TOKEN=$GITHUB_TOKEN --event pull_reques
|
||||
|
||||
There is also a utility script included in the Superset codebase to run Python integration tests. The [readme can be found here](https://github.com/apache/superset/tree/master/scripts/tests).
|
||||
|
||||
There is also a utility script included in the Superset codebase to run python integration tests. The [readme can be
|
||||
found here](https://github.com/apache/superset/tree/master/scripts/tests)
|
||||
|
||||
To run all integration tests, for example, run this script from the root directory:
|
||||
|
||||
```bash
|
||||
|
||||
72
docs/eslint.config.js
Normal file
72
docs/eslint.config.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/* eslint-env node */
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
const typescriptEslintParser = require('@typescript-eslint/parser');
|
||||
const typescriptEslintPlugin = require('@typescript-eslint/eslint-plugin');
|
||||
const eslintConfigPrettier = require('eslint-config-prettier');
|
||||
const prettierEslintPlugin = require('eslint-plugin-prettier');
|
||||
const js = require('@eslint/js');
|
||||
const ts = require('typescript-eslint');
|
||||
const react = require('eslint-plugin-react');
|
||||
const globals = require('globals');
|
||||
const { defineConfig, globalIgnores } = require('eslint/config');
|
||||
|
||||
module.exports = defineConfig([
|
||||
globalIgnores(['build/**/*', '.docusaurus/**/*', 'node_modules/**/*']),
|
||||
js.configs.recommended,
|
||||
...ts.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
{
|
||||
files: ['eslint.config.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
}
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
parser: typescriptEslintParser,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'module',
|
||||
},
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
typescript: typescriptEslintPlugin,
|
||||
react,
|
||||
prettier: prettierEslintPlugin,
|
||||
},
|
||||
rules: {
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'react/prop-types': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
}
|
||||
])
|
||||
@@ -40,15 +40,18 @@
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.8.1",
|
||||
"@docusaurus/tsconfig": "^3.8.1",
|
||||
"@eslint/js": "^9.31.0",
|
||||
"@types/react": "^19.1.8",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"eslint": "^8.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.37.0",
|
||||
"@typescript-eslint/parser": "^8.37.0",
|
||||
"eslint": "^9.31.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-prettier": "^5.5.1",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"prettier": "^2.0.0",
|
||||
"globals": "^16.3.0",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.37.0",
|
||||
"webpack": "^5.99.9"
|
||||
},
|
||||
"browserslist": {
|
||||
|
||||
@@ -111,7 +111,7 @@ const StyledTitleContainer = styled('div')`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Link as React.ComponentType<any>)`
|
||||
const StyledButton = styled(Link)`
|
||||
border-radius: 10px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable no-undef */
|
||||
import { useEffect } from 'react';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
@@ -50,7 +49,9 @@ export default function Root({ children }) {
|
||||
|
||||
// Handle route changes for SPA
|
||||
const handleRouteChange = () => {
|
||||
devMode && console.log('Route changed to:', window.location.pathname);
|
||||
if (devMode) {
|
||||
console.log('Route changed to:', window.location.pathname);
|
||||
}
|
||||
|
||||
// Short timeout to ensure the page has fully rendered
|
||||
setTimeout(() => {
|
||||
@@ -58,11 +59,9 @@ export default function Root({ children }) {
|
||||
const currentTitle = document.title;
|
||||
const currentPath = window.location.pathname;
|
||||
|
||||
devMode &&
|
||||
console.log('Tracking page view:', currentPath, currentTitle);
|
||||
|
||||
// For testing: impersonate real domain - ONLY FOR DEVELOPMENT
|
||||
if (devMode) {
|
||||
console.log('Tracking page view:', currentPath, currentTitle);
|
||||
window._paq.push(['setDomains', ['superset.apache.org']]);
|
||||
window._paq.push([
|
||||
'setCustomUrl',
|
||||
@@ -85,17 +84,22 @@ export default function Root({ children }) {
|
||||
'routeDidUpdate',
|
||||
];
|
||||
|
||||
devMode && console.log('Setting up Docusaurus route listeners');
|
||||
if (devMode) {
|
||||
console.log('Setting up Docusaurus route listeners');
|
||||
}
|
||||
possibleEvents.forEach(eventName => {
|
||||
document.addEventListener(eventName, () => {
|
||||
devMode &&
|
||||
if (devMode) {
|
||||
console.log(`Docusaurus route update detected via ${eventName}`);
|
||||
}
|
||||
handleRouteChange();
|
||||
});
|
||||
});
|
||||
|
||||
// Also set up manual history tracking as fallback
|
||||
devMode && console.log('Setting up manual history tracking as fallback');
|
||||
if (devMode) {
|
||||
console.log('Setting up manual history tracking as fallback');
|
||||
}
|
||||
const originalPushState = window.history.pushState;
|
||||
window.history.pushState = function () {
|
||||
originalPushState.apply(this, arguments);
|
||||
|
||||
482
docs/yarn.lock
482
docs/yarn.lock
@@ -2157,30 +2157,71 @@
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1":
|
||||
"@eslint-community/eslint-utils@^4.7.0":
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a"
|
||||
integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1":
|
||||
version "4.12.1"
|
||||
resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
|
||||
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
|
||||
|
||||
"@eslint/eslintrc@^2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz"
|
||||
integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
|
||||
"@eslint/config-array@^0.21.0":
|
||||
version "0.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.0.tgz#abdbcbd16b124c638081766392a4d6b509f72636"
|
||||
integrity sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==
|
||||
dependencies:
|
||||
"@eslint/object-schema" "^2.1.6"
|
||||
debug "^4.3.1"
|
||||
minimatch "^3.1.2"
|
||||
|
||||
"@eslint/config-helpers@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.3.0.tgz#3e09a90dfb87e0005c7694791e58e97077271286"
|
||||
integrity sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==
|
||||
|
||||
"@eslint/core@^0.15.0", "@eslint/core@^0.15.1":
|
||||
version "0.15.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.15.1.tgz#d530d44209cbfe2f82ef86d6ba08760196dd3b60"
|
||||
integrity sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.15"
|
||||
|
||||
"@eslint/eslintrc@^3.3.1":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964"
|
||||
integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.3.2"
|
||||
espree "^9.6.0"
|
||||
globals "^13.19.0"
|
||||
espree "^10.0.1"
|
||||
globals "^14.0.0"
|
||||
ignore "^5.2.0"
|
||||
import-fresh "^3.2.1"
|
||||
js-yaml "^4.1.0"
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@8.57.1":
|
||||
version "8.57.1"
|
||||
resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz"
|
||||
integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
|
||||
"@eslint/js@9.31.0", "@eslint/js@^9.31.0":
|
||||
version "9.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.31.0.tgz#adb1f39953d8c475c4384b67b67541b0d7206ed8"
|
||||
integrity sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==
|
||||
|
||||
"@eslint/object-schema@^2.1.6":
|
||||
version "2.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f"
|
||||
integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==
|
||||
|
||||
"@eslint/plugin-kit@^0.3.1":
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz#32926b59bd407d58d817941e48b2a7049359b1fd"
|
||||
integrity sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==
|
||||
dependencies:
|
||||
"@eslint/core" "^0.15.1"
|
||||
levn "^0.4.1"
|
||||
|
||||
"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
|
||||
version "9.3.0"
|
||||
@@ -2194,24 +2235,33 @@
|
||||
dependencies:
|
||||
"@hapi/hoek" "^9.0.0"
|
||||
|
||||
"@humanwhocodes/config-array@^0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz"
|
||||
integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==
|
||||
"@humanfs/core@^0.19.1":
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
|
||||
integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
|
||||
|
||||
"@humanfs/node@^0.16.6":
|
||||
version "0.16.6"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
|
||||
integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
|
||||
dependencies:
|
||||
"@humanwhocodes/object-schema" "^2.0.3"
|
||||
debug "^4.3.1"
|
||||
minimatch "^3.0.5"
|
||||
"@humanfs/core" "^0.19.1"
|
||||
"@humanwhocodes/retry" "^0.3.0"
|
||||
|
||||
"@humanwhocodes/module-importer@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz"
|
||||
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
|
||||
|
||||
"@humanwhocodes/object-schema@^2.0.3":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz"
|
||||
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
|
||||
"@humanwhocodes/retry@^0.3.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
|
||||
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
|
||||
|
||||
"@humanwhocodes/retry@^0.4.2":
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba"
|
||||
integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==
|
||||
|
||||
"@iconify/types@^2.0.0":
|
||||
version "2.0.0"
|
||||
@@ -2353,7 +2403,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
|
||||
"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
|
||||
"@nodelib/fs.walk@^1.2.3":
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
|
||||
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
|
||||
@@ -2361,6 +2411,11 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@pkgr/core@^0.2.4":
|
||||
version "0.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.7.tgz#eb5014dfd0b03e7f3ba2eeeff506eed89b028058"
|
||||
integrity sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==
|
||||
|
||||
"@pnpm/config.env-replace@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c"
|
||||
@@ -3599,11 +3654,6 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/semver@^7.3.12":
|
||||
version "7.5.8"
|
||||
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz"
|
||||
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
|
||||
|
||||
"@types/send@*":
|
||||
version "0.17.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a"
|
||||
@@ -3674,91 +3724,105 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.0.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz"
|
||||
integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==
|
||||
"@typescript-eslint/eslint-plugin@8.37.0", "@typescript-eslint/eslint-plugin@^8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz#332392883f936137cd6252c8eb236d298e514e70"
|
||||
integrity sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.4.0"
|
||||
"@typescript-eslint/scope-manager" "5.62.0"
|
||||
"@typescript-eslint/type-utils" "5.62.0"
|
||||
"@typescript-eslint/utils" "5.62.0"
|
||||
debug "^4.3.4"
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.37.0"
|
||||
"@typescript-eslint/type-utils" "8.37.0"
|
||||
"@typescript-eslint/utils" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.2.0"
|
||||
natural-compare-lite "^1.4.0"
|
||||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
ignore "^7.0.0"
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/parser@^5.0.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz"
|
||||
integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==
|
||||
"@typescript-eslint/parser@8.37.0", "@typescript-eslint/parser@^8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.37.0.tgz#b87f6b61e25ad5cc5bbf8baf809b8da889c89804"
|
||||
integrity sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "5.62.0"
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
"@typescript-eslint/typescript-estree" "5.62.0"
|
||||
"@typescript-eslint/scope-manager" "8.37.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/scope-manager@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz"
|
||||
integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==
|
||||
"@typescript-eslint/project-service@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.37.0.tgz#0594352e32a4ac9258591b88af77b5653800cdfe"
|
||||
integrity sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
"@typescript-eslint/visitor-keys" "5.62.0"
|
||||
|
||||
"@typescript-eslint/type-utils@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz"
|
||||
integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "5.62.0"
|
||||
"@typescript-eslint/utils" "5.62.0"
|
||||
"@typescript-eslint/tsconfig-utils" "^8.37.0"
|
||||
"@typescript-eslint/types" "^8.37.0"
|
||||
debug "^4.3.4"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/types@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz"
|
||||
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
|
||||
|
||||
"@typescript-eslint/typescript-estree@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz"
|
||||
integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
|
||||
"@typescript-eslint/scope-manager@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz#a31a3c80ca2ef4ed58de13742debb692e7d4c0a4"
|
||||
integrity sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
"@typescript-eslint/visitor-keys" "5.62.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@8.37.0", "@typescript-eslint/tsconfig-utils@^8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz#47a2760d265c6125f8e7864bc5c8537cad2bd053"
|
||||
integrity sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==
|
||||
|
||||
"@typescript-eslint/type-utils@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz#2a682e4c6ff5886712dad57e9787b5e417124507"
|
||||
integrity sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
"@typescript-eslint/utils" "8.37.0"
|
||||
debug "^4.3.4"
|
||||
globby "^11.1.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/types@8.37.0", "@typescript-eslint/types@^8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.37.0.tgz#09517aa9625eb3c68941dde3ac8835740587b6ff"
|
||||
integrity sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz#a07e4574d8e6e4355a558f61323730c987f5fcbc"
|
||||
integrity sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service" "8.37.0"
|
||||
"@typescript-eslint/tsconfig-utils" "8.37.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
debug "^4.3.4"
|
||||
fast-glob "^3.3.2"
|
||||
is-glob "^4.0.3"
|
||||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
minimatch "^9.0.4"
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/utils@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz"
|
||||
integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
|
||||
"@typescript-eslint/utils@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.37.0.tgz#189ea59b2709f5d898614611f091a776751ee335"
|
||||
integrity sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@types/json-schema" "^7.0.9"
|
||||
"@types/semver" "^7.3.12"
|
||||
"@typescript-eslint/scope-manager" "5.62.0"
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
"@typescript-eslint/typescript-estree" "5.62.0"
|
||||
eslint-scope "^5.1.1"
|
||||
semver "^7.3.7"
|
||||
"@eslint-community/eslint-utils" "^4.7.0"
|
||||
"@typescript-eslint/scope-manager" "8.37.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz"
|
||||
integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==
|
||||
"@typescript-eslint/visitor-keys@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz#cdb6a6bd3e8d6dd69bd70c1bdda36e2d18737455"
|
||||
integrity sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
eslint-visitor-keys "^4.2.1"
|
||||
|
||||
"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0":
|
||||
"@ungap/structured-clone@^1.0.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8"
|
||||
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
|
||||
@@ -3914,11 +3978,16 @@ acorn-walk@^8.0.0:
|
||||
dependencies:
|
||||
acorn "^8.11.0"
|
||||
|
||||
acorn@^8.0.0, acorn@^8.0.4, acorn@^8.11.0, acorn@^8.14.0, acorn@^8.8.2, acorn@^8.9.0:
|
||||
acorn@^8.0.0, acorn@^8.0.4, acorn@^8.11.0, acorn@^8.14.0, acorn@^8.8.2:
|
||||
version "8.14.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb"
|
||||
integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==
|
||||
|
||||
acorn@^8.15.0:
|
||||
version "8.15.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816"
|
||||
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
|
||||
|
||||
address@^1.0.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e"
|
||||
@@ -5006,7 +5075,7 @@ cosmiconfig@^8.1.3, cosmiconfig@^8.3.5:
|
||||
parse-json "^5.2.0"
|
||||
path-type "^4.0.0"
|
||||
|
||||
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
cross-spawn@^7.0.3, cross-spawn@^7.0.6:
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
@@ -5704,13 +5773,6 @@ doctrine@^2.1.0:
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
doctrine@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
|
||||
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
docusaurus-plugin-less@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/docusaurus-plugin-less/-/docusaurus-plugin-less-2.0.2.tgz"
|
||||
@@ -6104,12 +6166,13 @@ eslint-config-prettier@^10.1.5:
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz#00c18d7225043b6fbce6a665697377998d453782"
|
||||
integrity sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==
|
||||
|
||||
eslint-plugin-prettier@^4.0.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz"
|
||||
integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
|
||||
eslint-plugin-prettier@^5.5.1:
|
||||
version "5.5.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz#470820964de9aedb37e9ce62c3266d2d26d08d15"
|
||||
integrity sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==
|
||||
dependencies:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
synckit "^0.11.7"
|
||||
|
||||
eslint-plugin-react@^7.37.5:
|
||||
version "7.37.5"
|
||||
@@ -6135,7 +6198,7 @@ eslint-plugin-react@^7.37.5:
|
||||
string.prototype.matchall "^4.0.12"
|
||||
string.prototype.repeat "^1.0.0"
|
||||
|
||||
eslint-scope@5.1.1, eslint-scope@^5.1.1:
|
||||
eslint-scope@5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
||||
@@ -6143,80 +6206,82 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^7.2.2:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz"
|
||||
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
|
||||
eslint-scope@^8.4.0:
|
||||
version "8.4.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82"
|
||||
integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
|
||||
eslint-visitor-keys@^3.4.3:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint@^8.0.0:
|
||||
version "8.57.1"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
|
||||
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
|
||||
eslint-visitor-keys@^4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1"
|
||||
integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
|
||||
|
||||
eslint@^9.31.0:
|
||||
version "9.31.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.31.0.tgz#9a488e6da75bbe05785cd62e43c5ea99356d21ba"
|
||||
integrity sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.6.1"
|
||||
"@eslint/eslintrc" "^2.1.4"
|
||||
"@eslint/js" "8.57.1"
|
||||
"@humanwhocodes/config-array" "^0.13.0"
|
||||
"@eslint-community/regexpp" "^4.12.1"
|
||||
"@eslint/config-array" "^0.21.0"
|
||||
"@eslint/config-helpers" "^0.3.0"
|
||||
"@eslint/core" "^0.15.0"
|
||||
"@eslint/eslintrc" "^3.3.1"
|
||||
"@eslint/js" "9.31.0"
|
||||
"@eslint/plugin-kit" "^0.3.1"
|
||||
"@humanfs/node" "^0.16.6"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@nodelib/fs.walk" "^1.2.8"
|
||||
"@ungap/structured-clone" "^1.2.0"
|
||||
"@humanwhocodes/retry" "^0.4.2"
|
||||
"@types/estree" "^1.0.6"
|
||||
"@types/json-schema" "^7.0.15"
|
||||
ajv "^6.12.4"
|
||||
chalk "^4.0.0"
|
||||
cross-spawn "^7.0.2"
|
||||
cross-spawn "^7.0.6"
|
||||
debug "^4.3.2"
|
||||
doctrine "^3.0.0"
|
||||
escape-string-regexp "^4.0.0"
|
||||
eslint-scope "^7.2.2"
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
espree "^9.6.1"
|
||||
esquery "^1.4.2"
|
||||
eslint-scope "^8.4.0"
|
||||
eslint-visitor-keys "^4.2.1"
|
||||
espree "^10.4.0"
|
||||
esquery "^1.5.0"
|
||||
esutils "^2.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
file-entry-cache "^6.0.1"
|
||||
file-entry-cache "^8.0.0"
|
||||
find-up "^5.0.0"
|
||||
glob-parent "^6.0.2"
|
||||
globals "^13.19.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.2.0"
|
||||
imurmurhash "^0.1.4"
|
||||
is-glob "^4.0.0"
|
||||
is-path-inside "^3.0.3"
|
||||
js-yaml "^4.1.0"
|
||||
json-stable-stringify-without-jsonify "^1.0.1"
|
||||
levn "^0.4.1"
|
||||
lodash.merge "^4.6.2"
|
||||
minimatch "^3.1.2"
|
||||
natural-compare "^1.4.0"
|
||||
optionator "^0.9.3"
|
||||
strip-ansi "^6.0.1"
|
||||
text-table "^0.2.0"
|
||||
|
||||
espree@^9.6.0, espree@^9.6.1:
|
||||
version "9.6.1"
|
||||
resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz"
|
||||
integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
|
||||
espree@^10.0.1, espree@^10.4.0:
|
||||
version "10.4.0"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837"
|
||||
integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==
|
||||
dependencies:
|
||||
acorn "^8.9.0"
|
||||
acorn "^8.15.0"
|
||||
acorn-jsx "^5.3.2"
|
||||
eslint-visitor-keys "^3.4.1"
|
||||
eslint-visitor-keys "^4.2.1"
|
||||
|
||||
esprima@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||
|
||||
esquery@^1.4.2:
|
||||
esquery@^1.5.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz"
|
||||
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
|
||||
integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
|
||||
dependencies:
|
||||
estraverse "^5.1.0"
|
||||
@@ -6411,7 +6476,7 @@ fast-diff@^1.1.2:
|
||||
resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz"
|
||||
integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
|
||||
|
||||
fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.0:
|
||||
fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
|
||||
integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
|
||||
@@ -6484,12 +6549,12 @@ figures@^3.2.0:
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
|
||||
file-entry-cache@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
|
||||
integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
|
||||
file-entry-cache@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f"
|
||||
integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
|
||||
dependencies:
|
||||
flat-cache "^3.0.4"
|
||||
flat-cache "^4.0.0"
|
||||
|
||||
file-loader@^6.2.0:
|
||||
version "6.2.0"
|
||||
@@ -6548,14 +6613,13 @@ find-up@^6.3.0:
|
||||
locate-path "^7.1.0"
|
||||
path-exists "^5.0.0"
|
||||
|
||||
flat-cache@^3.0.4:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz"
|
||||
integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
|
||||
flat-cache@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c"
|
||||
integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
|
||||
dependencies:
|
||||
flatted "^3.2.9"
|
||||
keyv "^4.5.3"
|
||||
rimraf "^3.0.2"
|
||||
keyv "^4.5.4"
|
||||
|
||||
flat@^5.0.2:
|
||||
version "5.0.2"
|
||||
@@ -6590,12 +6654,14 @@ form-data-encoder@^2.1.2:
|
||||
integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz"
|
||||
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4"
|
||||
integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
es-set-tostringtag "^2.1.0"
|
||||
hasown "^2.0.2"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
format@^0.2.0:
|
||||
@@ -6781,18 +6847,21 @@ globals@^11.1.0:
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
|
||||
|
||||
globals@^13.19.0:
|
||||
version "13.24.0"
|
||||
resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz"
|
||||
integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
|
||||
dependencies:
|
||||
type-fest "^0.20.2"
|
||||
globals@^14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
|
||||
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
|
||||
|
||||
globals@^15.14.0:
|
||||
version "15.15.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8"
|
||||
integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==
|
||||
|
||||
globals@^16.3.0:
|
||||
version "16.3.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-16.3.0.tgz#66118e765ddaf9e2d880f7e17658543f93f1f667"
|
||||
integrity sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==
|
||||
|
||||
globalthis@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz"
|
||||
@@ -7285,6 +7354,11 @@ ignore@^5.2.0, ignore@^5.2.4:
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
|
||||
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
|
||||
|
||||
ignore@^7.0.0:
|
||||
version "7.0.5"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9"
|
||||
integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==
|
||||
|
||||
image-size@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/image-size/-/image-size-2.0.2.tgz#84a7b43704db5736f364bf0d1b029821299b4bdc"
|
||||
@@ -7619,7 +7693,7 @@ is-obj@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
|
||||
integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
|
||||
|
||||
is-path-inside@^3.0.2, is-path-inside@^3.0.3:
|
||||
is-path-inside@^3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
|
||||
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
|
||||
@@ -7921,7 +7995,7 @@ katex@^0.16.9:
|
||||
dependencies:
|
||||
commander "^8.3.0"
|
||||
|
||||
keyv@^4.5.3:
|
||||
keyv@^4.5.3, keyv@^4.5.4:
|
||||
version "4.5.4"
|
||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
|
||||
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
|
||||
@@ -8949,7 +9023,7 @@ minimalistic-assert@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
|
||||
|
||||
minimatch@3.1.2, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
minimatch@3.1.2, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
@@ -8963,6 +9037,13 @@ minimatch@^7.4.3:
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimatch@^9.0.4:
|
||||
version "9.0.5"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
|
||||
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
@@ -9011,11 +9092,6 @@ nanoid@^3.3.11, nanoid@^3.3.8:
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
|
||||
integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
|
||||
|
||||
natural-compare-lite@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz"
|
||||
integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
|
||||
|
||||
natural-compare@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
|
||||
@@ -10165,10 +10241,10 @@ prettier-linter-helpers@^1.0.0:
|
||||
dependencies:
|
||||
fast-diff "^1.1.2"
|
||||
|
||||
prettier@^2.0.0:
|
||||
version "2.8.8"
|
||||
resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz"
|
||||
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
|
||||
prettier@^3.6.2:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393"
|
||||
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
|
||||
|
||||
pretty-error@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -11438,6 +11514,11 @@ semver@^7.3.5, semver@^7.3.7, semver@^7.5.4:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f"
|
||||
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
|
||||
|
||||
semver@^7.6.0:
|
||||
version "7.7.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
|
||||
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
|
||||
|
||||
send@0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
|
||||
@@ -12058,6 +12139,13 @@ swagger-ui-react@^5.26.0:
|
||||
xml-but-prettier "^1.0.1"
|
||||
zenscroll "^4.0.2"
|
||||
|
||||
synckit@^0.11.7:
|
||||
version "0.11.8"
|
||||
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457"
|
||||
integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==
|
||||
dependencies:
|
||||
"@pkgr/core" "^0.2.4"
|
||||
|
||||
tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
|
||||
@@ -12084,11 +12172,6 @@ terser@^5.10.0, terser@^5.15.1, terser@^5.31.1:
|
||||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
||||
|
||||
throttle-debounce@^5.0.0, throttle-debounce@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz"
|
||||
@@ -12180,6 +12263,11 @@ trough@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f"
|
||||
integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==
|
||||
|
||||
ts-api-utils@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91"
|
||||
integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
|
||||
|
||||
ts-dedent@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
|
||||
@@ -12195,23 +12283,11 @@ ts-toolbelt@^9.6.0:
|
||||
resolved "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz"
|
||||
integrity sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==
|
||||
|
||||
tslib@^1.8.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.3, tslib@^2.3.0, tslib@^2.6.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"
|
||||
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
|
||||
@@ -12306,6 +12382,16 @@ types-ramda@^0.30.0:
|
||||
dependencies:
|
||||
ts-toolbelt "^9.6.0"
|
||||
|
||||
typescript-eslint@^8.37.0:
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.37.0.tgz#2235ddfa40cdbdadb1afb05f8bda688a2294b4c2"
|
||||
integrity sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "8.37.0"
|
||||
"@typescript-eslint/parser" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
"@typescript-eslint/utils" "8.37.0"
|
||||
|
||||
typescript@~5.8.3:
|
||||
version "5.8.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
|
||||
|
||||
@@ -29,7 +29,7 @@ maintainers:
|
||||
- name: craig-rueda
|
||||
email: craig@craigrueda.com
|
||||
url: https://github.com/craig-rueda
|
||||
version: 0.14.2
|
||||
version: 0.14.3
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
version: 13.4.4
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ metadata:
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.init.jobAnnotations }}
|
||||
annotations: {{- toYaml .Values.init.jobAnnotations | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -44,10 +44,10 @@ spec:
|
||||
{{- if or .Values.extraLabels .Values.init.podLabels }}
|
||||
labels:
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
{{- toYaml .Values.extraLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.init.podLabels }}
|
||||
{{- toYaml .Values.init.podLabels | nindent 8 }}
|
||||
{{- toYaml .Values.init.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{{- with .Values.supersetCeleryBeat.podDisruptionBudget }}
|
||||
{{- if .enabled -}}
|
||||
{{- if and .minAvailable .maxUnavailable }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- end}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
@@ -35,12 +35,12 @@ metadata:
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "supersetCeleryBeat.selectorLabels" $ | nindent 6 }}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{{- with .Values.supersetCeleryFlower.podDisruptionBudget }}
|
||||
{{- if .enabled -}}
|
||||
{{- if and .minAvailable .maxUnavailable }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- end}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
@@ -35,12 +35,12 @@ metadata:
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "supersetCeleryFlower.selectorLabels" $ | nindent 6 }}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{{- with .Values.supersetWorker.podDisruptionBudget }}
|
||||
{{- if .enabled -}}
|
||||
{{- if and .minAvailable .maxUnavailable }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- end}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
@@ -35,12 +35,12 @@ metadata:
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "supersetWorker.selectorLabels" $ | nindent 6 }}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{{- with .Values.supersetWebsockets.podDisruptionBudget }}
|
||||
{{- if .enabled -}}
|
||||
{{- if and .minAvailable .maxUnavailable }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- end}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
@@ -35,12 +35,12 @@ metadata:
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "supersetWebsockets.selectorLabels" $ | nindent 6 }}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{{- with .Values.supersetNode.podDisruptionBudget }}
|
||||
{{- if .enabled -}}
|
||||
{{- if and .minAvailable .maxUnavailable }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- end}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
@@ -35,12 +35,12 @@ metadata:
|
||||
{{- toYaml $.Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "supersetNode.selectorLabels" $ | nindent 6 }}
|
||||
|
||||
360
superset-embedded-sdk/package-lock.json
generated
360
superset-embedded-sdk/package-lock.json
generated
@@ -3251,20 +3251,6 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-jest": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
|
||||
@@ -3658,6 +3644,19 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -4064,6 +4063,20 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.19",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.19.tgz",
|
||||
@@ -4124,12 +4137,57 @@
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
|
||||
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
|
||||
@@ -4590,6 +4648,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-readdir-recursive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
|
||||
@@ -4617,10 +4691,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
@@ -4640,6 +4717,30 @@
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-package-type": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
|
||||
@@ -4649,6 +4750,19 @@
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||
@@ -4711,6 +4825,18 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
@@ -4739,6 +4865,45 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/html-escaper": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||
@@ -6927,6 +7092,15 @@
|
||||
"tmpl": "1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
@@ -10565,19 +10739,6 @@
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-jest": {
|
||||
@@ -10862,6 +11023,16 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -11140,6 +11311,17 @@
|
||||
"integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
|
||||
"dev": true
|
||||
},
|
||||
"dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.5.19",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.19.tgz",
|
||||
@@ -11183,12 +11365,45 @@
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"dev": true
|
||||
},
|
||||
"es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true
|
||||
},
|
||||
"es-module-lexer": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
|
||||
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
|
||||
"dev": true
|
||||
},
|
||||
"es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
|
||||
@@ -11503,6 +11718,19 @@
|
||||
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||
"dev": true
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"fs-readdir-recursive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
|
||||
@@ -11523,9 +11751,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true
|
||||
},
|
||||
"gensync": {
|
||||
@@ -11540,12 +11768,40 @@
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"get-package-type": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
|
||||
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||
@@ -11588,6 +11844,12 @@
|
||||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
|
||||
"dev": true
|
||||
},
|
||||
"gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"dev": true
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
@@ -11609,6 +11871,30 @@
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-symbols": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"html-escaper": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||
@@ -13219,6 +13505,12 @@
|
||||
"tmpl": "1.0.5"
|
||||
}
|
||||
},
|
||||
"math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"dev": true
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
||||
@@ -56,7 +56,7 @@ module.exports = {
|
||||
],
|
||||
coverageReporters: ['lcov', 'json-summary', 'html', 'text'],
|
||||
transformIgnorePatterns: [
|
||||
'node_modules/(?!d3-(interpolate|color|time)|remark-gfm|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|@rjsf/*.|sinon|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|react-error-boundary|react-json-tree|react-base16-styling|lodash-es)',
|
||||
'node_modules/(?!d3-(interpolate|color|time|scale)|@mapbox/tiny-sdf|remark-gfm|(?!@ngrx|(?!deck.gl)|d3-scale)|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|@rjsf/*.|sinon|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|react-error-boundary|react-json-tree|react-base16-styling|lodash-es)',
|
||||
],
|
||||
preset: 'ts-jest',
|
||||
transform: {
|
||||
|
||||
1405
superset-frontend/package-lock.json
generated
1405
superset-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -104,12 +104,12 @@
|
||||
"@superset-ui/legacy-plugin-chart-world-map": "file:./plugins/legacy-plugin-chart-world-map",
|
||||
"@superset-ui/legacy-preset-chart-deckgl": "file:./plugins/legacy-preset-chart-deckgl",
|
||||
"@superset-ui/legacy-preset-chart-nvd3": "file:./plugins/legacy-preset-chart-nvd3",
|
||||
"@superset-ui/plugin-chart-ag-grid-table": "file:./plugins/plugin-chart-ag-grid-table",
|
||||
"@superset-ui/plugin-chart-cartodiagram": "file:./plugins/plugin-chart-cartodiagram",
|
||||
"@superset-ui/plugin-chart-echarts": "file:./plugins/plugin-chart-echarts",
|
||||
"@superset-ui/plugin-chart-handlebars": "file:./plugins/plugin-chart-handlebars",
|
||||
"@superset-ui/plugin-chart-pivot-table": "file:./plugins/plugin-chart-pivot-table",
|
||||
"@superset-ui/plugin-chart-table": "file:./plugins/plugin-chart-table",
|
||||
"@superset-ui/plugin-chart-ag-grid-table": "file:./plugins/plugin-chart-ag-grid-table",
|
||||
"@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud",
|
||||
"@superset-ui/switchboard": "file:./packages/superset-ui-switchboard",
|
||||
"@types/d3-format": "^3.0.1",
|
||||
@@ -203,6 +203,7 @@
|
||||
"use-event-callback": "^0.1.0",
|
||||
"use-immer": "^0.9.0",
|
||||
"use-query-params": "^1.1.9",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -90,6 +90,7 @@ export interface Dataset {
|
||||
database?: Record<string, unknown>;
|
||||
normalize_columns?: boolean;
|
||||
always_filter_main_dttm?: boolean;
|
||||
extra?: object | string;
|
||||
}
|
||||
|
||||
export interface ControlPanelState {
|
||||
|
||||
@@ -202,7 +202,7 @@ export function AsyncAceEditor(
|
||||
|
||||
/* Basic editor styles with dark mode support */
|
||||
.ace_editor.ace-github,
|
||||
.ace_editor.ace-textmate {
|
||||
.ace_editor.ace-tm {
|
||||
background-color: ${token.colorBgContainer} !important;
|
||||
color: ${token.colorText} !important;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ export function Button(props: ButtonProps) {
|
||||
if (!buttonStyle || buttonStyle === 'primary') {
|
||||
variant = 'solid';
|
||||
antdType = 'primary';
|
||||
color = 'primary';
|
||||
} else if (buttonStyle === 'secondary') {
|
||||
variant = 'filled';
|
||||
color = 'primary';
|
||||
@@ -78,7 +77,6 @@ export function Button(props: ButtonProps) {
|
||||
variant = 'outlined';
|
||||
color = 'default';
|
||||
} else if (buttonStyle === 'dashed') {
|
||||
color = 'primary';
|
||||
variant = 'dashed';
|
||||
antdType = 'dashed';
|
||||
} else if (buttonStyle === 'danger') {
|
||||
@@ -134,6 +132,11 @@ export function Button(props: ButtonProps) {
|
||||
'& > span > :first-of-type': {
|
||||
marginRight: firstChildMargin,
|
||||
},
|
||||
':not(:hover)': effectiveButtonStyle === 'secondary' && {
|
||||
// NOTE: This is the best we can do contrast wise for the secondary button using antd tokens
|
||||
// and abusing the semantics. Should be revisited when possible. https://github.com/apache/superset/pull/34253#issuecomment-3104834692
|
||||
color: `${theme.colorPrimaryTextHover} !important`,
|
||||
},
|
||||
}}
|
||||
icon={icon}
|
||||
{...restProps}
|
||||
|
||||
@@ -31,11 +31,6 @@ const StyledDiv = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const DescriptionContainer = styled.div`
|
||||
line-height: ${({ theme }) => theme.sizeUnit * 4}px;
|
||||
padding-top: 16px;
|
||||
`;
|
||||
|
||||
export function DeleteModal({
|
||||
description,
|
||||
onConfirm,
|
||||
@@ -81,12 +76,12 @@ export function DeleteModal({
|
||||
onHide={hide}
|
||||
onHandledPrimaryAction={confirm}
|
||||
primaryButtonName={t('Delete')}
|
||||
primaryButtonType="danger"
|
||||
primaryButtonStyle="danger"
|
||||
show={open}
|
||||
title={title}
|
||||
centered
|
||||
>
|
||||
<DescriptionContainer>{description}</DescriptionContainer>
|
||||
{description}
|
||||
<StyledDiv>
|
||||
<FormLabel htmlFor="delete">
|
||||
{t('Type "%s" to confirm', t('DELETE'))}
|
||||
|
||||
@@ -33,7 +33,7 @@ export const InteractiveModal = (props: ModalProps) => (
|
||||
InteractiveModal.args = {
|
||||
disablePrimaryButton: false,
|
||||
primaryButtonName: 'Danger',
|
||||
primaryButtonType: 'danger',
|
||||
primaryButtonStyle: 'danger',
|
||||
show: true,
|
||||
title: "I'm a modal!",
|
||||
resizable: false,
|
||||
|
||||
@@ -77,7 +77,7 @@ export const StyledModal = styled(BaseModal)<StyledModalProps>`
|
||||
.ant-modal-header {
|
||||
flex: 0 0 auto;
|
||||
border-radius: ${theme.borderRadius}px ${theme.borderRadius}px 0 0;
|
||||
padding: ${theme.sizeUnit * 4}px ${theme.sizeUnit * 6}px;
|
||||
padding: ${theme.sizeUnit * 4}px ${theme.sizeUnit * 4}px;
|
||||
|
||||
.ant-modal-title {
|
||||
font-weight: ${theme.fontWeightStrong};
|
||||
@@ -122,6 +122,7 @@ export const StyledModal = styled(BaseModal)<StyledModalProps>`
|
||||
.ant-modal-body {
|
||||
flex: 0 1 auto;
|
||||
padding: ${theme.sizeUnit * 4}px;
|
||||
padding-bottom: ${theme.sizeUnit * 2}px;
|
||||
overflow: auto;
|
||||
${!resizable && height && `height: ${height};`}
|
||||
}
|
||||
@@ -208,7 +209,7 @@ const CustomModal = ({
|
||||
onHide,
|
||||
onHandledPrimaryAction,
|
||||
primaryButtonName = t('OK'),
|
||||
primaryButtonType = 'primary',
|
||||
primaryButtonStyle = 'primary',
|
||||
show,
|
||||
name,
|
||||
title,
|
||||
@@ -261,7 +262,7 @@ const CustomModal = ({
|
||||
</Button>,
|
||||
<Button
|
||||
key="submit"
|
||||
buttonStyle={primaryButtonType}
|
||||
buttonStyle={primaryButtonStyle}
|
||||
disabled={disablePrimaryButton}
|
||||
tooltip={primaryTooltipMessage}
|
||||
loading={primaryButtonLoading}
|
||||
|
||||
@@ -20,6 +20,7 @@ import type { CSSProperties, ReactNode } from 'react';
|
||||
import type { ModalFuncProps } from 'antd';
|
||||
import type { ResizableProps } from 're-resizable';
|
||||
import type { DraggableProps } from 'react-draggable';
|
||||
import { ButtonStyle } from '../Button/types';
|
||||
|
||||
export interface ModalProps {
|
||||
className?: string;
|
||||
@@ -30,7 +31,7 @@ export interface ModalProps {
|
||||
onHide: () => void;
|
||||
onHandledPrimaryAction?: () => void;
|
||||
primaryButtonName?: string;
|
||||
primaryButtonType?: 'primary' | 'danger';
|
||||
primaryButtonStyle?: ButtonStyle;
|
||||
show: boolean;
|
||||
name?: string;
|
||||
title: ReactNode;
|
||||
|
||||
@@ -45,7 +45,7 @@ interface HandleSelectProps {
|
||||
}
|
||||
|
||||
const menuItemStyles = (theme: any) => css`
|
||||
&.antd5-menu-item {
|
||||
&.ant-menu-item {
|
||||
height: auto;
|
||||
line-height: 1.4;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
import {
|
||||
Radio as Antd5Radio,
|
||||
Radio as AntRadio,
|
||||
type CheckboxOptionType,
|
||||
type RadioGroupProps,
|
||||
} from 'antd';
|
||||
@@ -40,19 +40,19 @@ const RadioGroup = ({
|
||||
...props
|
||||
}: RadioGroupWrapperProps) => {
|
||||
const content = options.map((option: CheckboxOptionType) => (
|
||||
<Antd5Radio key={option.value} value={option.value}>
|
||||
<AntRadio key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</Antd5Radio>
|
||||
</AntRadio>
|
||||
));
|
||||
return (
|
||||
<Antd5Radio.Group {...props}>
|
||||
<AntRadio.Group {...props}>
|
||||
{spaceConfig ? <Space {...spaceConfig}>{content}</Space> : content}
|
||||
</Antd5Radio.Group>
|
||||
</AntRadio.Group>
|
||||
);
|
||||
};
|
||||
export const Radio = Object.assign(Antd5Radio, {
|
||||
export const Radio = Object.assign(AntRadio, {
|
||||
GroupWrapper: RadioGroup,
|
||||
Button: Antd5Radio.Button,
|
||||
Button: AntRadio.Button,
|
||||
});
|
||||
export type {
|
||||
RadioChangeEvent,
|
||||
|
||||
@@ -19,28 +19,28 @@
|
||||
import { Tooltip } from 'antd';
|
||||
import { Dropdown, Icons } from '@superset-ui/core/components';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { ThemeMode } from '../../theme/types';
|
||||
import { ThemeAlgorithm, ThemeMode } from '../../theme/types';
|
||||
|
||||
export interface ThemeSelectProps {
|
||||
changeThemeMode: (newMode: ThemeMode) => void;
|
||||
setThemeMode: (newMode: ThemeMode) => void;
|
||||
tooltipTitle?: string;
|
||||
themeMode: ThemeMode;
|
||||
}
|
||||
|
||||
const ThemeSelect: React.FC<ThemeSelectProps> = ({
|
||||
changeThemeMode,
|
||||
setThemeMode,
|
||||
tooltipTitle = 'Select theme',
|
||||
themeMode,
|
||||
}) => {
|
||||
const handleSelect = (mode: ThemeMode) => {
|
||||
changeThemeMode(mode);
|
||||
setThemeMode(mode);
|
||||
};
|
||||
|
||||
const themeIconMap: Record<ThemeMode, React.ReactNode> = {
|
||||
[ThemeMode.LIGHT]: <Icons.SunOutlined />,
|
||||
[ThemeMode.DARK]: <Icons.MoonOutlined />,
|
||||
const themeIconMap: Record<ThemeAlgorithm | ThemeMode, React.ReactNode> = {
|
||||
[ThemeAlgorithm.DEFAULT]: <Icons.SunOutlined />,
|
||||
[ThemeAlgorithm.DARK]: <Icons.MoonOutlined />,
|
||||
[ThemeMode.SYSTEM]: <Icons.FormatPainterOutlined />,
|
||||
[ThemeMode.COMPACT]: <Icons.CompressOutlined />,
|
||||
[ThemeAlgorithm.COMPACT]: <Icons.CompressOutlined />,
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -49,9 +49,9 @@ const ThemeSelect: React.FC<ThemeSelectProps> = ({
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
key: ThemeMode.LIGHT,
|
||||
key: ThemeMode.DEFAULT,
|
||||
label: t('Light'),
|
||||
onClick: () => handleSelect(ThemeMode.LIGHT),
|
||||
onClick: () => handleSelect(ThemeMode.DEFAULT),
|
||||
icon: <Icons.SunOutlined />,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
import { theme as antdThemeImport } from 'antd';
|
||||
import { Theme } from './Theme';
|
||||
import { AnyThemeConfig } from './types';
|
||||
import { AnyThemeConfig, ThemeAlgorithm } from './types';
|
||||
|
||||
// Mock emotion's cache to avoid actual DOM operations
|
||||
jest.mock('@emotion/cache', () => ({
|
||||
@@ -44,7 +44,7 @@ describe('Theme', () => {
|
||||
const parsedJson = JSON.parse(jsonString);
|
||||
|
||||
expect(parsedJson.token?.colorPrimary).toBe('#ff0000');
|
||||
expect(parsedJson.algorithm).toBe('dark');
|
||||
expect(parsedJson.algorithm).toBe(ThemeAlgorithm.DARK);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -91,7 +91,7 @@ describe('Theme', () => {
|
||||
|
||||
// Verify dark mode by using the serialized config from the public method
|
||||
const serialized = theme.toSerializedConfig();
|
||||
expect(serialized.algorithm).toBe('dark');
|
||||
expect(serialized.algorithm).toBe(ThemeAlgorithm.DARK);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -137,7 +137,7 @@ describe('Theme', () => {
|
||||
|
||||
// Verify the algorithm was updated
|
||||
const serialized = theme.toSerializedConfig();
|
||||
expect(serialized.algorithm).toBe('dark');
|
||||
expect(serialized.algorithm).toBe(ThemeAlgorithm.DARK);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -150,7 +150,7 @@ describe('Theme', () => {
|
||||
|
||||
// Verify dark algorithm is used
|
||||
const serialized = theme.toSerializedConfig();
|
||||
expect(serialized.algorithm).toBe('dark');
|
||||
expect(serialized.algorithm).toBe(ThemeAlgorithm.DARK);
|
||||
});
|
||||
|
||||
it('switches to default algorithm when toggling dark mode off', () => {
|
||||
@@ -164,7 +164,7 @@ describe('Theme', () => {
|
||||
|
||||
// Verify default algorithm is used
|
||||
const serialized = theme.toSerializedConfig();
|
||||
expect(serialized.algorithm).toBe('default');
|
||||
expect(serialized.algorithm).toBe(ThemeAlgorithm.DEFAULT);
|
||||
});
|
||||
|
||||
it('preserves other algorithms when toggling dark mode', () => {
|
||||
@@ -181,10 +181,11 @@ describe('Theme', () => {
|
||||
|
||||
// Verify default algorithm replaces dark but compact is preserved
|
||||
const serialized = theme.toSerializedConfig();
|
||||
|
||||
expect(Array.isArray(serialized.algorithm)).toBe(true);
|
||||
expect(serialized.algorithm).toContain('default');
|
||||
expect(serialized.algorithm).toContain('compact');
|
||||
expect(serialized.algorithm).not.toContain('dark');
|
||||
expect(serialized.algorithm).toContain(ThemeAlgorithm.DEFAULT);
|
||||
expect(serialized.algorithm).toContain(ThemeAlgorithm.COMPACT);
|
||||
expect(serialized.algorithm).not.toContain(ThemeAlgorithm.DARK);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -218,7 +219,7 @@ describe('Theme', () => {
|
||||
const serialized = theme.toSerializedConfig();
|
||||
|
||||
expect(serialized.token?.colorPrimary).toBe('#ff0000');
|
||||
expect(serialized.algorithm).toBe('dark');
|
||||
expect(serialized.algorithm).toBe(ThemeAlgorithm.DARK);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable theme-colors/no-literal-colors */
|
||||
import { SerializableThemeConfig } from './types';
|
||||
import { type SerializableThemeConfig, ThemeAlgorithm } from './types';
|
||||
|
||||
const exampleThemes: Record<string, SerializableThemeConfig> = {
|
||||
superset: {
|
||||
@@ -27,11 +27,11 @@ const exampleThemes: Record<string, SerializableThemeConfig> = {
|
||||
},
|
||||
supersetDark: {
|
||||
token: {},
|
||||
algorithm: 'dark',
|
||||
algorithm: ThemeAlgorithm.DARK,
|
||||
},
|
||||
supersetCompact: {
|
||||
token: {},
|
||||
algorithm: 'compact',
|
||||
algorithm: ThemeAlgorithm.COMPACT,
|
||||
},
|
||||
funky: {
|
||||
token: {
|
||||
@@ -43,7 +43,7 @@ const exampleThemes: Record<string, SerializableThemeConfig> = {
|
||||
borderRadius: 12,
|
||||
fontFamily: 'Comic Sans MS, cursive',
|
||||
},
|
||||
algorithm: 'default',
|
||||
algorithm: ThemeAlgorithm.DEFAULT,
|
||||
},
|
||||
funkyDark: {
|
||||
token: {
|
||||
@@ -55,7 +55,7 @@ const exampleThemes: Record<string, SerializableThemeConfig> = {
|
||||
borderRadius: 12,
|
||||
fontFamily: 'Comic Sans MS, cursive',
|
||||
},
|
||||
algorithm: 'dark',
|
||||
algorithm: ThemeAlgorithm.DARK,
|
||||
},
|
||||
};
|
||||
export default exampleThemes;
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import emotionStyled from '@emotion/styled';
|
||||
import emotionStyled, { CreateStyled } from '@emotion/styled';
|
||||
import { useTheme as useThemeBasic } from '@emotion/react';
|
||||
// import { theme as antdThemeImport } from 'antd';
|
||||
import { Theme } from './Theme';
|
||||
import type {
|
||||
SupersetTheme,
|
||||
SerializableThemeConfig,
|
||||
AnyThemeConfig,
|
||||
ThemeStorage,
|
||||
ThemeControllerOptions,
|
||||
ThemeContextType,
|
||||
import {
|
||||
type SupersetTheme,
|
||||
type SerializableThemeConfig,
|
||||
type AnyThemeConfig,
|
||||
type ThemeStorage,
|
||||
type ThemeControllerOptions,
|
||||
type ThemeContextType,
|
||||
ThemeAlgorithm,
|
||||
} from './types';
|
||||
|
||||
export {
|
||||
@@ -56,10 +56,12 @@ export function useTheme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
const styled = emotionStyled;
|
||||
const styled: CreateStyled = emotionStyled;
|
||||
|
||||
// launching in in dark mode for now while iterating
|
||||
const themeObject = Theme.fromConfig({ algorithm: 'default' });
|
||||
const themeObject: Theme = Theme.fromConfig({
|
||||
algorithm: ThemeAlgorithm.DEFAULT,
|
||||
});
|
||||
|
||||
const { theme } = themeObject;
|
||||
const supersetTheme = theme;
|
||||
|
||||
@@ -33,6 +33,41 @@ import { Theme } from '.';
|
||||
export type AntdTokens = ReturnType<typeof antdThemeImport.getDesignToken>;
|
||||
export type AntdThemeConfig = ThemeConfig;
|
||||
|
||||
/**
|
||||
* Theme algorithms supported by Antd.
|
||||
* They can be used individually or in combination.
|
||||
* - DEFAULT: Default light theme
|
||||
* - DARK: Dark theme
|
||||
* - COMPACT: Compact theme (smaller spacing)
|
||||
*/
|
||||
export enum ThemeAlgorithm {
|
||||
DEFAULT = 'default',
|
||||
DARK = 'dark',
|
||||
COMPACT = 'compact',
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the current theme mode of the app.
|
||||
* It can be one of the following:
|
||||
* - DEFAULT: Light theme
|
||||
* - DARK: Dark theme
|
||||
* - SYSTEM: System theme (auto-detects based on system settings)
|
||||
*/
|
||||
export enum ThemeMode {
|
||||
DEFAULT = 'default',
|
||||
DARK = 'dark',
|
||||
SYSTEM = 'system',
|
||||
}
|
||||
|
||||
/**
|
||||
* All valid algorithm values that can be used in theme config.
|
||||
*/
|
||||
export type ThemeAlgorithmOption =
|
||||
| ThemeAlgorithm.DEFAULT
|
||||
| ThemeAlgorithm.DARK
|
||||
| ThemeAlgorithm.COMPACT
|
||||
| ThemeAlgorithm[];
|
||||
|
||||
/**
|
||||
* A serializable version of Ant Design's ThemeConfig
|
||||
* Compatible with theme editor exports
|
||||
@@ -40,11 +75,7 @@ export type AntdThemeConfig = ThemeConfig;
|
||||
export type SerializableThemeConfig = {
|
||||
token?: Record<string, any>;
|
||||
components?: Record<string, any>;
|
||||
algorithm?:
|
||||
| 'default'
|
||||
| 'dark'
|
||||
| 'compact'
|
||||
| ('default' | 'dark' | 'compact')[];
|
||||
algorithm?: ThemeAlgorithmOption;
|
||||
hashed?: boolean;
|
||||
inherit?: boolean;
|
||||
};
|
||||
@@ -358,13 +389,6 @@ export type AllowedAntdTokenKeys = Extract<
|
||||
keyof AntdTokens
|
||||
>;
|
||||
|
||||
export enum ThemeMode {
|
||||
LIGHT = 'light',
|
||||
DARK = 'dark',
|
||||
SYSTEM = 'system',
|
||||
COMPACT = 'compact',
|
||||
}
|
||||
|
||||
export type SharedAntdTokens = Pick<AntdTokens, AllowedAntdTokenKeys>;
|
||||
|
||||
/** The final shape for our custom theme object, combining old theme + shared antd + superset specifics. */
|
||||
@@ -379,7 +403,7 @@ export interface ThemeStorage {
|
||||
}
|
||||
|
||||
export interface ThemeControllerOptions {
|
||||
themeObject: Theme;
|
||||
themeObject?: Theme;
|
||||
storage?: ThemeStorage;
|
||||
storageKey?: string;
|
||||
modeStorageKey?: string;
|
||||
@@ -393,6 +417,6 @@ export interface ThemeContextType {
|
||||
theme: Theme;
|
||||
themeMode: ThemeMode;
|
||||
setTheme: (config: AnyThemeConfig) => void;
|
||||
changeThemeMode: (newMode: ThemeMode) => void;
|
||||
setThemeMode: (newMode: ThemeMode) => void;
|
||||
resetTheme: () => void;
|
||||
}
|
||||
|
||||
@@ -28,9 +28,10 @@ import {
|
||||
genDeprecatedColorVariations,
|
||||
} from './utils';
|
||||
import {
|
||||
AnyThemeConfig,
|
||||
SerializableThemeConfig,
|
||||
AntdThemeConfig,
|
||||
type AnyThemeConfig,
|
||||
type SerializableThemeConfig,
|
||||
type AntdThemeConfig,
|
||||
ThemeAlgorithm,
|
||||
} from './types';
|
||||
|
||||
// Mock tinycolor2 for consistent testing
|
||||
@@ -50,22 +51,25 @@ describe('Theme utilities', () => {
|
||||
const config: AnyThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
};
|
||||
|
||||
expect(isSerializableConfig(config)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when algorithm is a string', () => {
|
||||
const config: AnyThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: 'dark',
|
||||
algorithm: ThemeAlgorithm.DARK,
|
||||
};
|
||||
|
||||
expect(isSerializableConfig(config)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when algorithm is an array of strings', () => {
|
||||
const config: AnyThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: ['dark', 'compact'],
|
||||
algorithm: [ThemeAlgorithm.DARK, ThemeAlgorithm.COMPACT],
|
||||
};
|
||||
|
||||
expect(isSerializableConfig(config)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -74,15 +78,19 @@ describe('Theme utilities', () => {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: antdThemeImport.darkAlgorithm,
|
||||
};
|
||||
|
||||
expect(isSerializableConfig(config)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when algorithm is an array containing a function', () => {
|
||||
const config: AnyThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
// @ts-ignore
|
||||
algorithm: [antdThemeImport.darkAlgorithm, 'compact'],
|
||||
algorithm: [
|
||||
antdThemeImport.darkAlgorithm,
|
||||
antdThemeImport.compactAlgorithm,
|
||||
],
|
||||
};
|
||||
|
||||
expect(isSerializableConfig(config)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -91,18 +99,22 @@ describe('Theme utilities', () => {
|
||||
it('converts string algorithm to function reference', () => {
|
||||
const config: SerializableThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: 'dark',
|
||||
algorithm: ThemeAlgorithm.DARK,
|
||||
};
|
||||
|
||||
const result = deserializeThemeConfig(config);
|
||||
|
||||
expect(result.algorithm).toBe(antdThemeImport.darkAlgorithm);
|
||||
});
|
||||
|
||||
it('converts array of string algorithms to function references', () => {
|
||||
const config: SerializableThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: ['dark', 'compact'],
|
||||
algorithm: [ThemeAlgorithm.DARK, ThemeAlgorithm.COMPACT],
|
||||
};
|
||||
|
||||
const result = deserializeThemeConfig(config);
|
||||
|
||||
expect(Array.isArray(result.algorithm)).toBe(true);
|
||||
expect(result.algorithm).toContain(antdThemeImport.darkAlgorithm);
|
||||
expect(result.algorithm).toContain(antdThemeImport.compactAlgorithm);
|
||||
@@ -111,10 +123,12 @@ describe('Theme utilities', () => {
|
||||
it('preserves other configuration properties', () => {
|
||||
const config: SerializableThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: 'dark',
|
||||
algorithm: ThemeAlgorithm.DARK,
|
||||
hashed: true,
|
||||
};
|
||||
|
||||
const result = deserializeThemeConfig(config);
|
||||
|
||||
expect(result.token).toEqual({ colorPrimary: '#ff0000' });
|
||||
expect(result.hashed).toBe(true);
|
||||
});
|
||||
@@ -123,25 +137,31 @@ describe('Theme utilities', () => {
|
||||
const config: SerializableThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
};
|
||||
|
||||
const result = deserializeThemeConfig(config);
|
||||
expect(result.algorithm).toBeUndefined();
|
||||
|
||||
expect(result.algorithm).toBe(antdThemeImport.defaultAlgorithm);
|
||||
});
|
||||
|
||||
it('converts default algorithm string to function reference', () => {
|
||||
const config: SerializableThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: 'default',
|
||||
algorithm: ThemeAlgorithm.DEFAULT,
|
||||
};
|
||||
|
||||
const result = deserializeThemeConfig(config);
|
||||
|
||||
expect(result.algorithm).toBe(antdThemeImport.defaultAlgorithm);
|
||||
});
|
||||
|
||||
it('converts compact algorithm string to function reference', () => {
|
||||
const config: SerializableThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: 'compact',
|
||||
algorithm: ThemeAlgorithm.COMPACT,
|
||||
};
|
||||
|
||||
const result = deserializeThemeConfig(config);
|
||||
|
||||
expect(result.algorithm).toBe(antdThemeImport.compactAlgorithm);
|
||||
});
|
||||
});
|
||||
@@ -152,8 +172,10 @@ describe('Theme utilities', () => {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: antdThemeImport.darkAlgorithm,
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
expect(result.algorithm).toBe('dark');
|
||||
|
||||
expect(result.algorithm).toBe(ThemeAlgorithm.DARK);
|
||||
});
|
||||
|
||||
it('converts array of function algorithms to strings', () => {
|
||||
@@ -164,10 +186,12 @@ describe('Theme utilities', () => {
|
||||
antdThemeImport.compactAlgorithm,
|
||||
],
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
|
||||
expect(Array.isArray(result.algorithm)).toBe(true);
|
||||
expect(result.algorithm).toContain('dark');
|
||||
expect(result.algorithm).toContain('compact');
|
||||
expect(result.algorithm).toContain(ThemeAlgorithm.DARK);
|
||||
expect(result.algorithm).toContain(ThemeAlgorithm.COMPACT);
|
||||
});
|
||||
|
||||
it('preserves other configuration properties', () => {
|
||||
@@ -176,7 +200,9 @@ describe('Theme utilities', () => {
|
||||
algorithm: antdThemeImport.darkAlgorithm,
|
||||
hashed: true,
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
|
||||
expect(result.token).toEqual({ colorPrimary: '#ff0000' });
|
||||
expect(result.hashed).toBe(true);
|
||||
});
|
||||
@@ -185,7 +211,9 @@ describe('Theme utilities', () => {
|
||||
const config: AntdThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
|
||||
expect(result.algorithm).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -196,8 +224,10 @@ describe('Theme utilities', () => {
|
||||
// @ts-ignore
|
||||
algorithm: unknownAlgorithm,
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
expect(result.algorithm).toBe('default');
|
||||
|
||||
expect(result.algorithm).toBe(ThemeAlgorithm.DEFAULT);
|
||||
});
|
||||
|
||||
it('converts default algorithm function to string', () => {
|
||||
@@ -205,8 +235,10 @@ describe('Theme utilities', () => {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: antdThemeImport.defaultAlgorithm,
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
expect(result.algorithm).toBe('default');
|
||||
|
||||
expect(result.algorithm).toBe(ThemeAlgorithm.DEFAULT);
|
||||
});
|
||||
|
||||
it('converts compact algorithm function to string', () => {
|
||||
@@ -214,8 +246,10 @@ describe('Theme utilities', () => {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: antdThemeImport.compactAlgorithm,
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
expect(result.algorithm).toBe('compact');
|
||||
|
||||
expect(result.algorithm).toBe(ThemeAlgorithm.COMPACT);
|
||||
});
|
||||
|
||||
it('defaults each unknown algorithm in array to "default"', () => {
|
||||
@@ -225,9 +259,14 @@ describe('Theme utilities', () => {
|
||||
// @ts-ignore
|
||||
algorithm: [antdThemeImport.darkAlgorithm, unknownAlgorithm],
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
|
||||
expect(Array.isArray(result.algorithm)).toBe(true);
|
||||
expect(result.algorithm).toEqual(['dark', 'default']);
|
||||
expect(result.algorithm).toEqual([
|
||||
ThemeAlgorithm.DARK,
|
||||
ThemeAlgorithm.DEFAULT,
|
||||
]);
|
||||
});
|
||||
|
||||
it('handles mixed known and unknown algorithms in array', () => {
|
||||
@@ -244,13 +283,15 @@ describe('Theme utilities', () => {
|
||||
unknownAlgorithm2,
|
||||
],
|
||||
};
|
||||
|
||||
const result = serializeThemeConfig(config);
|
||||
|
||||
expect(Array.isArray(result.algorithm)).toBe(true);
|
||||
expect(result.algorithm).toEqual([
|
||||
'dark',
|
||||
'default',
|
||||
'compact',
|
||||
'default',
|
||||
ThemeAlgorithm.DARK,
|
||||
ThemeAlgorithm.DEFAULT,
|
||||
ThemeAlgorithm.COMPACT,
|
||||
ThemeAlgorithm.DEFAULT,
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -261,16 +302,20 @@ describe('Theme utilities', () => {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: antdThemeImport.darkAlgorithm,
|
||||
};
|
||||
|
||||
const result = normalizeThemeConfig(config);
|
||||
|
||||
expect(result).toBe(config);
|
||||
});
|
||||
|
||||
it('deserializes serializable configs', () => {
|
||||
const config: SerializableThemeConfig = {
|
||||
token: { colorPrimary: '#ff0000' },
|
||||
algorithm: 'dark',
|
||||
algorithm: ThemeAlgorithm.DARK,
|
||||
};
|
||||
|
||||
const result = normalizeThemeConfig(config);
|
||||
|
||||
expect(result.algorithm).toBe(antdThemeImport.darkAlgorithm);
|
||||
});
|
||||
});
|
||||
@@ -278,14 +323,18 @@ describe('Theme utilities', () => {
|
||||
describe('getAntdConfig', () => {
|
||||
it('returns config with default algorithm for light mode', () => {
|
||||
const seed = { colorPrimary: '#ff0000' };
|
||||
|
||||
const result = getAntdConfig(seed, false);
|
||||
|
||||
expect(result.token).toBe(seed);
|
||||
expect(result.algorithm).toBe(antdThemeImport.defaultAlgorithm);
|
||||
});
|
||||
|
||||
it('returns config with dark algorithm for dark mode', () => {
|
||||
const seed = { colorPrimary: '#ff0000' };
|
||||
|
||||
const result = getAntdConfig(seed, true);
|
||||
|
||||
expect(result.token).toBe(seed);
|
||||
expect(result.algorithm).toBe(antdThemeImport.darkAlgorithm);
|
||||
});
|
||||
@@ -301,7 +350,9 @@ describe('Theme utilities', () => {
|
||||
colorInfo: '#info',
|
||||
otherToken: 'ignore-me',
|
||||
};
|
||||
|
||||
const result = getSystemColors(tokens);
|
||||
|
||||
expect(result).toEqual({
|
||||
colorPrimary: '#primary',
|
||||
colorError: '#error',
|
||||
@@ -315,6 +366,7 @@ describe('Theme utilities', () => {
|
||||
describe('genDeprecatedColorVariations', () => {
|
||||
it('generates color variations for light mode', () => {
|
||||
const result = genDeprecatedColorVariations('#base-color', false);
|
||||
|
||||
expect(result.base).toBe('#base-color');
|
||||
expect(result.light1).toBe('#mixed-color');
|
||||
expect(result.dark1).toBe('#mixed-color');
|
||||
@@ -322,6 +374,7 @@ describe('Theme utilities', () => {
|
||||
|
||||
it('generates color variations for dark mode', () => {
|
||||
const result = genDeprecatedColorVariations('#base-color', true);
|
||||
|
||||
expect(result.base).toBe('#base-color');
|
||||
expect(result.light1).toBe('#mixed-color');
|
||||
expect(result.dark1).toBe('#mixed-color');
|
||||
@@ -337,7 +390,9 @@ describe('Theme utilities', () => {
|
||||
colorSuccess: '#success',
|
||||
colorInfo: '#info',
|
||||
};
|
||||
|
||||
const result = getDeprecatedColors(systemColors, false);
|
||||
|
||||
expect(result.primary.base).toBe('#primary');
|
||||
expect(result.error.base).toBe('#error');
|
||||
expect(result.warning.base).toBe('#warning');
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
import { theme as antdThemeImport } from 'antd';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import {
|
||||
AntdThemeConfig,
|
||||
AnyThemeConfig,
|
||||
SerializableThemeConfig,
|
||||
DeprecatedColorVariations,
|
||||
DeprecatedThemeColors,
|
||||
SystemColors,
|
||||
SupersetTheme,
|
||||
type AntdThemeConfig,
|
||||
type AnyThemeConfig,
|
||||
type SerializableThemeConfig,
|
||||
type DeprecatedColorVariations,
|
||||
type DeprecatedThemeColors,
|
||||
type SystemColors,
|
||||
type SupersetTheme,
|
||||
ThemeAlgorithm,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
@@ -38,9 +39,8 @@ export function isSerializableConfig(
|
||||
|
||||
if (algorithm === undefined) return true;
|
||||
|
||||
if (Array.isArray(algorithm)) {
|
||||
if (Array.isArray(algorithm))
|
||||
return (algorithm as unknown[]).every(alg => typeof alg === 'string');
|
||||
}
|
||||
|
||||
return typeof algorithm === 'string';
|
||||
}
|
||||
@@ -60,9 +60,21 @@ export function deserializeThemeConfig(
|
||||
|
||||
let resolvedAlgorithm;
|
||||
if (Array.isArray(algorithm)) {
|
||||
resolvedAlgorithm = algorithm.map(alg => algorithmMap[alg]);
|
||||
} else if (algorithm) {
|
||||
const validAlgorithms = algorithm
|
||||
.map((alg: ThemeAlgorithm) => algorithmMap[alg])
|
||||
.filter(Boolean);
|
||||
|
||||
// If we have valid algorithms, use them; otherwise fallback to default
|
||||
if (validAlgorithms.length > 0) {
|
||||
resolvedAlgorithm =
|
||||
validAlgorithms.length === 1 ? validAlgorithms[0] : validAlgorithms;
|
||||
} else {
|
||||
resolvedAlgorithm = antdThemeImport.defaultAlgorithm;
|
||||
}
|
||||
} else if (algorithm && algorithmMap[algorithm]) {
|
||||
resolvedAlgorithm = algorithmMap[algorithm];
|
||||
} else {
|
||||
resolvedAlgorithm = antdThemeImport.defaultAlgorithm;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -83,19 +95,21 @@ export function serializeThemeConfig(
|
||||
|
||||
if (Array.isArray(algorithm)) {
|
||||
serializedAlgorithm = algorithm.map(alg => {
|
||||
if (alg === antdThemeImport.defaultAlgorithm) return 'default';
|
||||
if (alg === antdThemeImport.darkAlgorithm) return 'dark';
|
||||
if (alg === antdThemeImport.compactAlgorithm) return 'compact';
|
||||
return 'default'; // Fallback
|
||||
}) as ('default' | 'dark' | 'compact')[];
|
||||
if (alg === antdThemeImport.defaultAlgorithm)
|
||||
return ThemeAlgorithm.DEFAULT;
|
||||
if (alg === antdThemeImport.darkAlgorithm) return ThemeAlgorithm.DARK;
|
||||
if (alg === antdThemeImport.compactAlgorithm)
|
||||
return ThemeAlgorithm.COMPACT;
|
||||
return ThemeAlgorithm.DEFAULT; // Fallback
|
||||
}) as ThemeAlgorithm[];
|
||||
} else if (algorithm) {
|
||||
if (algorithm === antdThemeImport.defaultAlgorithm)
|
||||
serializedAlgorithm = 'default';
|
||||
serializedAlgorithm = ThemeAlgorithm.DEFAULT;
|
||||
else if (algorithm === antdThemeImport.darkAlgorithm)
|
||||
serializedAlgorithm = 'dark';
|
||||
serializedAlgorithm = ThemeAlgorithm.DARK;
|
||||
else if (algorithm === antdThemeImport.compactAlgorithm)
|
||||
serializedAlgorithm = 'compact';
|
||||
else serializedAlgorithm = 'default'; // Fallback
|
||||
serializedAlgorithm = ThemeAlgorithm.COMPACT;
|
||||
else serializedAlgorithm = ThemeAlgorithm.DEFAULT; // Fallback
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -109,9 +123,8 @@ export function serializeThemeConfig(
|
||||
* This automatically detects and converts serializable configs
|
||||
*/
|
||||
export function normalizeThemeConfig(config: AnyThemeConfig): AntdThemeConfig {
|
||||
if (isSerializableConfig(config)) {
|
||||
return deserializeThemeConfig(config);
|
||||
}
|
||||
if (isSerializableConfig(config)) return deserializeThemeConfig(config);
|
||||
|
||||
return config as AntdThemeConfig;
|
||||
}
|
||||
|
||||
@@ -164,7 +177,7 @@ export function getDeprecatedColors(
|
||||
systemColors: SystemColors,
|
||||
isDark: boolean,
|
||||
): DeprecatedThemeColors {
|
||||
const sc = systemColors;
|
||||
const sc: SystemColors = systemColors;
|
||||
return {
|
||||
primary: genDeprecatedColorVariations(sc.colorPrimary, isDark),
|
||||
error: genDeprecatedColorVariations(sc.colorError, isDark),
|
||||
|
||||
@@ -86,20 +86,33 @@ export default class Translator {
|
||||
}
|
||||
|
||||
translate(input: string, ...args: unknown[]): string {
|
||||
return this.i18n.translate(input).fetch(...args);
|
||||
try {
|
||||
return this.i18n.translate(input).fetch(...args);
|
||||
} catch (err) {
|
||||
logging.warn(`Translation failed for key "${input}" with args:`, args);
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
translateWithNumber(key: string, ...args: unknown[]): string {
|
||||
const [plural, num, ...rest] = args;
|
||||
if (typeof plural === 'number') {
|
||||
try {
|
||||
const [plural, num, ...rest] = args;
|
||||
if (typeof plural === 'number') {
|
||||
return this.i18n
|
||||
.translate(key)
|
||||
.ifPlural(plural, key)
|
||||
.fetch(plural, num, ...rest);
|
||||
}
|
||||
return this.i18n
|
||||
.translate(key)
|
||||
.ifPlural(plural, key)
|
||||
.fetch(plural, num, ...args);
|
||||
.ifPlural(num as number, plural as string)
|
||||
.fetch(...rest);
|
||||
} catch (err) {
|
||||
logging.warn(
|
||||
`Plural translation failed for key "${key}" with args:`,
|
||||
args,
|
||||
);
|
||||
}
|
||||
return this.i18n
|
||||
.translate(key)
|
||||
.ifPlural(num as number, plural as string)
|
||||
.fetch(...rest);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ export enum FeatureFlag {
|
||||
EnableTemplateProcessing = 'ENABLE_TEMPLATE_PROCESSING',
|
||||
EscapeMarkdownHtml = 'ESCAPE_MARKDOWN_HTML',
|
||||
EstimateQueryCost = 'ESTIMATE_QUERY_COST',
|
||||
FilterBarClosedByDefault = 'FILTERBAR_CLOSED_BY_DEFAULT',
|
||||
GlobalAsyncQueries = 'GLOBAL_ASYNC_QUERIES',
|
||||
ListviewsDefaultCardView = 'LISTVIEWS_DEFAULT_CARD_VIEW',
|
||||
ScheduledQueries = 'SCHEDULED_QUERIES',
|
||||
|
||||
@@ -19,18 +19,27 @@
|
||||
|
||||
import { t } from '../translation';
|
||||
|
||||
const VALIDE_OSM_URLS = ['https://tile.osm', 'https://tile.openstreetmap'];
|
||||
|
||||
/**
|
||||
* Validate a [Mapbox styles URL](https://docs.mapbox.com/help/glossary/style-url/)
|
||||
* @param v
|
||||
*/
|
||||
export default function validateMapboxStylesUrl(v: unknown) {
|
||||
if (
|
||||
typeof v === 'string' &&
|
||||
v.trim().length > 0 &&
|
||||
v.trim().startsWith('mapbox://styles/')
|
||||
) {
|
||||
return false;
|
||||
if (typeof v === 'string') {
|
||||
const trimmed_v = v.trim();
|
||||
if (
|
||||
typeof v === 'string' &&
|
||||
trimmed_v.length > 0 &&
|
||||
(trimmed_v.startsWith('mapbox://styles/') ||
|
||||
trimmed_v.startsWith('tile://http') ||
|
||||
VALIDE_OSM_URLS.some(s => trimmed_v.startsWith(s)))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return t('is expected to be a Mapbox URL');
|
||||
return t(
|
||||
'is expected to be a Mapbox/OSM URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ describe('validateMapboxStylesUrl', () => {
|
||||
'mapbox://styles/foobar/clp2dr5r4008a01pcg4ad45m8',
|
||||
),
|
||||
).toEqual(false);
|
||||
expect(
|
||||
validateMapboxStylesUrl(
|
||||
'tile://https://c.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
),
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
[
|
||||
@@ -40,7 +45,7 @@ describe('validateMapboxStylesUrl', () => {
|
||||
].forEach(value => {
|
||||
it(`should not validate ${value}`, () => {
|
||||
expect(validateMapboxStylesUrl(value)).toEqual(
|
||||
'is expected to be a Mapbox URL',
|
||||
'is expected to be a Mapbox/OSM URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -42,4 +42,8 @@ export default styled(WorldMapComponent)`
|
||||
background-color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||
}
|
||||
}
|
||||
.hoverinfo {
|
||||
background-color: ${({ theme }) => theme.colorBgElevated};
|
||||
color: ${({ theme }) => theme.colorTextSecondary};
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
getSequentialSchemeRegistry,
|
||||
CategoricalColorNamespace,
|
||||
} from '@superset-ui/core';
|
||||
import Datamap from 'datamaps/dist/datamaps.world.min';
|
||||
import Datamap from 'datamaps/dist/datamaps.all.min';
|
||||
import { ColorBy } from './utils';
|
||||
|
||||
const propTypes = {
|
||||
|
||||
@@ -24,10 +24,17 @@
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"@deck.gl/aggregation-layers": "^9.0.38",
|
||||
"@deck.gl/core": "^9.0.37",
|
||||
"@deck.gl/layers": "^9.0.38",
|
||||
"@deck.gl/react": "^9.1.4",
|
||||
"@deck.gl/aggregation-layers": "^9.1.13",
|
||||
"@deck.gl/core": "^9.1.13",
|
||||
"@deck.gl/geo-layers": "^9.1.13",
|
||||
"@deck.gl/layers": "^9.1.13",
|
||||
"@deck.gl/react": "^9.1.13",
|
||||
"@luma.gl/constants": "^9.1.9",
|
||||
"@luma.gl/core": "^9.1.9",
|
||||
"@luma.gl/engine": "^9.1.9",
|
||||
"@luma.gl/shadertools": "^9.1.9",
|
||||
"@luma.gl/webgl": "^9.1.9",
|
||||
"@mapbox/tiny-sdf": "^2.0.6",
|
||||
"@mapbox/geojson-extent": "^1.0.1",
|
||||
"@math.gl/web-mercator": "^4.1.0",
|
||||
"@types/d3-array": "^2.0.0",
|
||||
|
||||
@@ -39,6 +39,12 @@ import { JsonObject, JsonValue, styled, usePrevious } from '@superset-ui/core';
|
||||
import Tooltip, { TooltipProps } from './components/Tooltip';
|
||||
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||
import { Viewport } from './utils/fitViewport';
|
||||
import {
|
||||
MAPBOX_LAYER_PREFIX,
|
||||
OSM_LAYER_KEYWORDS,
|
||||
TILE_LAYER_PREFIX,
|
||||
buildTileLayer,
|
||||
} from './utils';
|
||||
|
||||
const TICK = 250; // milliseconds
|
||||
|
||||
@@ -102,6 +108,20 @@ export const DeckGLContainer = memo(
|
||||
);
|
||||
|
||||
const layers = useCallback(() => {
|
||||
if (
|
||||
(props.mapStyle?.startsWith(TILE_LAYER_PREFIX) ||
|
||||
OSM_LAYER_KEYWORDS.some(tilek => props.mapStyle?.includes(tilek))) &&
|
||||
props.layers.some(
|
||||
l => typeof l !== 'function' && l?.id === 'tile-layer',
|
||||
) === false
|
||||
) {
|
||||
props.layers.unshift(
|
||||
buildTileLayer(
|
||||
(props.mapStyle ?? '').replace(TILE_LAYER_PREFIX, ''),
|
||||
'tile-layer',
|
||||
),
|
||||
);
|
||||
}
|
||||
// Support for layer factory
|
||||
if (props.layers.some(l => typeof l === 'function')) {
|
||||
return props.layers.map(l =>
|
||||
@@ -110,7 +130,7 @@ export const DeckGLContainer = memo(
|
||||
}
|
||||
|
||||
return props.layers as Layer[];
|
||||
}, [props.layers]);
|
||||
}, [props.layers, props.mapStyle]);
|
||||
|
||||
const { children = null, height, width } = props;
|
||||
|
||||
@@ -134,11 +154,13 @@ export const DeckGLContainer = memo(
|
||||
glContextRef.current = context.gl;
|
||||
}}
|
||||
>
|
||||
<StaticMap
|
||||
preserveDrawingBuffer
|
||||
mapStyle={props.mapStyle || 'light'}
|
||||
mapboxApiAccessToken={props.mapboxApiAccessToken}
|
||||
/>
|
||||
{props.mapStyle?.startsWith(MAPBOX_LAYER_PREFIX) && (
|
||||
<StaticMap
|
||||
preserveDrawingBuffer
|
||||
mapStyle={props.mapStyle || 'light'}
|
||||
mapboxApiAccessToken={props.mapboxApiAccessToken}
|
||||
/>
|
||||
)}
|
||||
</DeckGL>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -48,6 +48,30 @@ const sequentialSchemeRegistry = getSequentialSchemeRegistry();
|
||||
|
||||
export const DEFAULT_DECKGL_COLOR = { r: 158, g: 158, b: 158, a: 1 };
|
||||
|
||||
let deckglTiles: string[][];
|
||||
|
||||
export const DEFAULT_DECKGL_TILES = [
|
||||
['https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'Streets (OSM)'],
|
||||
['https://tile.osm.ch/osm-swiss-style/{z}/{x}/{y}.png', 'Topography (OSM)'],
|
||||
['mapbox://styles/mapbox/streets-v9', 'Streets (Mapbox)'],
|
||||
['mapbox://styles/mapbox/dark-v9', 'Dark (Mapbox)'],
|
||||
['mapbox://styles/mapbox/light-v9', 'Light (Mapbox)'],
|
||||
['mapbox://styles/mapbox/satellite-streets-v9', 'Satellite Streets (Mapbox)'],
|
||||
['mapbox://styles/mapbox/satellite-v9', 'Satellite (Mapbox)'],
|
||||
['mapbox://styles/mapbox/outdoors-v9', 'Outdoors (Mapbox)'],
|
||||
];
|
||||
|
||||
const getDeckGLTiles = () => {
|
||||
if (!deckglTiles) {
|
||||
const appContainer = document.getElementById('app');
|
||||
const { common } = JSON.parse(
|
||||
appContainer?.getAttribute('data-bootstrap') || '{}',
|
||||
);
|
||||
deckglTiles = common?.deckgl_tiles ?? DEFAULT_DECKGL_TILES;
|
||||
}
|
||||
return deckglTiles;
|
||||
};
|
||||
|
||||
const DEFAULT_VIEWPORT = {
|
||||
longitude: 6.85236157047845,
|
||||
latitude: 31.222656842808707,
|
||||
@@ -395,17 +419,11 @@ export const mapboxStyle = {
|
||||
renderTrigger: true,
|
||||
freeForm: true,
|
||||
validators: [validateMapboxStylesUrl],
|
||||
choices: [
|
||||
['mapbox://styles/mapbox/streets-v9', t('Streets')],
|
||||
['mapbox://styles/mapbox/dark-v9', t('Dark')],
|
||||
['mapbox://styles/mapbox/light-v9', t('Light')],
|
||||
['mapbox://styles/mapbox/satellite-streets-v9', t('Satellite Streets')],
|
||||
['mapbox://styles/mapbox/satellite-v9', t('Satellite')],
|
||||
['mapbox://styles/mapbox/outdoors-v9', t('Outdoors')],
|
||||
],
|
||||
default: 'mapbox://styles/mapbox/light-v9',
|
||||
choices: getDeckGLTiles(),
|
||||
default: getDeckGLTiles()[0][0],
|
||||
description: t(
|
||||
'Base layer map style. See Mapbox documentation: %s',
|
||||
'Mapbox base layer map style (see Mapbox documentation: %s) or tile server URL.',
|
||||
'https://docs.mapbox.com/help/glossary/style-url/',
|
||||
),
|
||||
},
|
||||
|
||||
@@ -26,11 +26,17 @@ import {
|
||||
SequentialScheme,
|
||||
} from '@superset-ui/core';
|
||||
import { Color } from '@deck.gl/core';
|
||||
import { GeoBoundingBox, TileLayer } from '@deck.gl/geo-layers';
|
||||
import { BitmapLayer, PathLayer } from '@deck.gl/layers';
|
||||
import { hexToRGB } from './utils/colors';
|
||||
import { ColorBreakpointType } from './types';
|
||||
|
||||
const DEFAULT_NUM_BUCKETS = 10;
|
||||
|
||||
export const MAPBOX_LAYER_PREFIX = 'mapbox://';
|
||||
export const TILE_LAYER_PREFIX = 'tile://';
|
||||
export const OSM_LAYER_KEYWORDS = ['openstreetmap', 'osm'];
|
||||
|
||||
export type Buckets = {
|
||||
break_points: string[];
|
||||
num_buckets: string;
|
||||
@@ -215,3 +221,42 @@ export function getColorBreakpointsBuckets(
|
||||
|
||||
return buckets;
|
||||
}
|
||||
|
||||
export function buildTileLayer(url: string, id: string) {
|
||||
interface TileLayerProps {
|
||||
id: string;
|
||||
data: string;
|
||||
minZoom: number;
|
||||
maxZoom: number;
|
||||
tileSize: number;
|
||||
renderSubLayers: (props: any) => (BitmapLayer | PathLayer)[];
|
||||
}
|
||||
|
||||
interface RenderSubLayerProps {
|
||||
tile: {
|
||||
bbox: GeoBoundingBox;
|
||||
};
|
||||
data: any;
|
||||
}
|
||||
|
||||
return new TileLayer({
|
||||
data: url,
|
||||
id,
|
||||
minZoom: 0,
|
||||
maxZoom: 19,
|
||||
tileSize: 256,
|
||||
|
||||
renderSubLayers: (props: RenderSubLayerProps): BitmapLayer[] => {
|
||||
const { west, north, east, south } = props.tile.bbox as GeoBoundingBox;
|
||||
|
||||
// Ajouter une BitmapLayer
|
||||
const bitmapLayer = new BitmapLayer(props, {
|
||||
data: undefined,
|
||||
image: props.data,
|
||||
bounds: [west, south, east, north],
|
||||
});
|
||||
|
||||
return [bitmapLayer];
|
||||
},
|
||||
} as TileLayerProps);
|
||||
}
|
||||
|
||||
@@ -209,12 +209,18 @@ export default function EchartsTimeseries({
|
||||
}),
|
||||
);
|
||||
groupBy.forEach((dimension, i) => {
|
||||
const val = labelMap[seriesName][i];
|
||||
const dimensionValues = labelMap[seriesName] ?? [];
|
||||
|
||||
// Skip the metric values at the beginning and get the actual dimension value
|
||||
// If we have multiple metrics, they come first, then the dimension values
|
||||
const metricsCount = dimensionValues.length - groupBy.length;
|
||||
const val = dimensionValues[metricsCount + i];
|
||||
|
||||
drillByFilters.push({
|
||||
col: dimension,
|
||||
op: '==',
|
||||
val,
|
||||
formattedVal: formatSeriesName(values[i], {
|
||||
formattedVal: formatSeriesName(val, {
|
||||
timeFormatter: getTimeFormatter(formData.dateFormat),
|
||||
numberFormatter: getNumberFormatter(formData.numberFormat),
|
||||
coltype: coltypeMapping?.[getColumnLabel(dimension)],
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
set -e
|
||||
|
||||
export NODE_NO_WARNINGS=1
|
||||
|
||||
for file in $( find ../superset/translations/** -name '*.po' );
|
||||
do
|
||||
extension=${file##*.}
|
||||
@@ -29,7 +31,7 @@ do
|
||||
if [ $extension == "po" ]
|
||||
then
|
||||
echo "po2json --domain superset --format jed1.x $file $filename.json"
|
||||
po2json --domain superset --format jed1.x $file $filename.json
|
||||
po2json --domain superset --format jed1.x --fuzzy $file $filename.json
|
||||
prettier --write $filename.json
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
SaveDatasetModal,
|
||||
ISaveableDatasource,
|
||||
} from 'src/SqlLab/components/SaveDatasetModal';
|
||||
import { getDatasourceAsSaveableDataset } from 'src/utils/datasourceUtils';
|
||||
import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor';
|
||||
import { QueryEditor } from 'src/SqlLab/types';
|
||||
import useLogAction from 'src/logger/useLogAction';
|
||||
@@ -214,15 +215,7 @@ const SaveQuery = ({
|
||||
onHide={() => setShowSaveDatasetModal(false)}
|
||||
buttonTextOnSave={t('Save & Explore')}
|
||||
buttonTextOnOverwrite={t('Overwrite & Explore')}
|
||||
datasource={{
|
||||
columns,
|
||||
name: query.name || query.description || t('Undefined'),
|
||||
dbId: query.dbId || 0,
|
||||
sql: query.sql || '',
|
||||
catalog: query.catalog,
|
||||
schema: query.schema,
|
||||
templateParams: query.templateParams,
|
||||
}}
|
||||
datasource={getDatasourceAsSaveableDataset(query)}
|
||||
/>
|
||||
<Modal
|
||||
className="save-query-modal"
|
||||
|
||||
@@ -926,7 +926,7 @@ const SqlEditor: FC<Props> = ({
|
||||
css={css`
|
||||
margin-bottom: ${theme.sizeUnit * 2}px;
|
||||
padding-top: ${theme.sizeUnit * 4}px;
|
||||
.antd5-alert-action {
|
||||
.ant-alert-action {
|
||||
align-self: center;
|
||||
}
|
||||
`}
|
||||
|
||||
@@ -353,7 +353,7 @@ test('Sends the correct db when changing the database', async () => {
|
||||
await waitFor(() =>
|
||||
expect(props.onDbChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
id: `mysql-test-mysql-2`,
|
||||
value: 2,
|
||||
database_name: 'test-mysql',
|
||||
backend: 'mysql',
|
||||
}),
|
||||
|
||||
@@ -319,11 +319,14 @@ export function DatabaseSelector({
|
||||
value: { label: string; value: number },
|
||||
database: DatabaseValue,
|
||||
) {
|
||||
setCurrentDb(database);
|
||||
// the database id is actually stored in the value property; the ID is used
|
||||
// for the DOM, so it can't be an integer
|
||||
const databaseWithId = { ...database, id: database.value };
|
||||
setCurrentDb(databaseWithId);
|
||||
setCurrentCatalog(undefined);
|
||||
setCurrentSchema(undefined);
|
||||
if (onDbChange) {
|
||||
onDbChange(database);
|
||||
onDbChange(databaseWithId);
|
||||
}
|
||||
if (onCatalogChange) {
|
||||
onCatalogChange(undefined);
|
||||
|
||||
@@ -717,7 +717,9 @@ class DatasourceEditor extends PureComponent {
|
||||
}
|
||||
|
||||
onDatasourceTypeChange(datasourceType) {
|
||||
this.setState({ datasourceType });
|
||||
// Call onChange after setting datasourceType to ensure
|
||||
// SQL is cleared when switching to a physical dataset
|
||||
this.setState({ datasourceType }, this.onChange);
|
||||
}
|
||||
|
||||
setColumns(obj) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
screen,
|
||||
waitFor,
|
||||
userEvent,
|
||||
cleanup,
|
||||
} from 'spec/helpers/testing-library';
|
||||
import mockDatasource from 'spec/fixtures/mockDatasource';
|
||||
import { isFeatureEnabled } from '@superset-ui/core';
|
||||
@@ -244,4 +245,36 @@ describe('DatasourceEditor Source Tab', () => {
|
||||
expect(physicalRadioBtn).toBeDisabled();
|
||||
expect(virtualRadioBtn).toBeDisabled();
|
||||
});
|
||||
|
||||
it('calls onChange with empty SQL when switching to physical dataset', async () => {
|
||||
// Clean previous render
|
||||
cleanup();
|
||||
|
||||
props.onChange.mockClear();
|
||||
|
||||
await asyncRender({
|
||||
...props,
|
||||
datasource: {
|
||||
...props.datasource,
|
||||
table_name: 'Vehicle Sales +',
|
||||
datasourceType: 'virtual',
|
||||
sql: 'SELECT * FROM users',
|
||||
},
|
||||
});
|
||||
|
||||
// Enable edit mode
|
||||
const getLockBtn = screen.getByRole('img', { name: /lock/i });
|
||||
await userEvent.click(getLockBtn);
|
||||
|
||||
// Switch to physical dataset
|
||||
const physicalRadioBtn = screen.getByRole('radio', {
|
||||
name: /physical \(table or view\)/i,
|
||||
});
|
||||
await userEvent.click(physicalRadioBtn);
|
||||
|
||||
// Assert that the latest onChange call has empty SQL
|
||||
expect(props.onChange).toHaveBeenCalled();
|
||||
const updatedDatasource = props.onChange.mock.calls[0];
|
||||
expect(updatedDatasource[0].sql).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -54,7 +54,8 @@ export function ErrorMessageWithStackTrace({
|
||||
// Check if a custom error message component was registered for this message
|
||||
if (error) {
|
||||
const ErrorMessageComponent = getErrorMessageComponentRegistry().get(
|
||||
error.error_type,
|
||||
// @ts-ignore: plan to modify this part so that all errors in Superset 6.0 are standardized as Superset API error types
|
||||
error.errorType ?? error.error_type,
|
||||
);
|
||||
if (ErrorMessageComponent) {
|
||||
return (
|
||||
|
||||
@@ -92,7 +92,7 @@ export function MarshmallowErrorMessage({
|
||||
children: (
|
||||
<JSONTree
|
||||
data={extra.messages}
|
||||
shouldExpandNode={() => true}
|
||||
shouldExpandNodeInitially={() => true}
|
||||
hideRoot
|
||||
theme={jsonTreeTheme}
|
||||
/>
|
||||
|
||||
@@ -362,7 +362,7 @@ export const ImportModal: FunctionComponent<ImportModelsModalProps> = ({
|
||||
onHandledPrimaryAction={onUpload}
|
||||
onHide={hide}
|
||||
primaryButtonName={needsOverwriteConfirm ? t('Overwrite') : t('Import')}
|
||||
primaryButtonType={needsOverwriteConfirm ? 'danger' : 'primary'}
|
||||
primaryButtonStyle={needsOverwriteConfirm ? 'danger' : 'primary'}
|
||||
width="750px"
|
||||
show={show}
|
||||
title={<h4>{t('Import %s', resourceLabel)}</h4>}
|
||||
|
||||
@@ -39,3 +39,10 @@ export interface TagType {
|
||||
css?: SerializedStyles;
|
||||
closable?: boolean;
|
||||
}
|
||||
|
||||
export enum TagTypeEnum {
|
||||
Custom = 1,
|
||||
Type = 2,
|
||||
Owner = 3,
|
||||
FavoritedBy = 4,
|
||||
}
|
||||
|
||||
@@ -47,6 +47,15 @@ export const TagsList = ({
|
||||
onDelete,
|
||||
maxTags,
|
||||
}: TagsListProps) => {
|
||||
const sortedTags = useMemo(
|
||||
() =>
|
||||
tags.toSorted((a, b) => {
|
||||
const nameA = a.name ?? '';
|
||||
const nameB = b.name ?? '';
|
||||
return nameA.localeCompare(nameB);
|
||||
}),
|
||||
[tags],
|
||||
);
|
||||
const [tempMaxTags, setTempMaxTags] = useState<number | undefined>(maxTags);
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
@@ -58,21 +67,23 @@ export const TagsList = ({
|
||||
const collapse = () => setTempMaxTags(maxTags);
|
||||
|
||||
const tagsIsLong: boolean | null = useMemo(
|
||||
() => (tempMaxTags ? tags.length > tempMaxTags : null),
|
||||
[tags.length, tempMaxTags],
|
||||
() => (tempMaxTags ? sortedTags.length > tempMaxTags : null),
|
||||
[sortedTags.length, tempMaxTags],
|
||||
);
|
||||
|
||||
const extraTags: number | null = useMemo(
|
||||
() =>
|
||||
typeof tempMaxTags === 'number' ? tags.length - tempMaxTags + 1 : null,
|
||||
[tagsIsLong, tags.length, tempMaxTags],
|
||||
typeof tempMaxTags === 'number'
|
||||
? sortedTags.length - tempMaxTags + 1
|
||||
: null,
|
||||
[tagsIsLong, sortedTags.length, tempMaxTags],
|
||||
);
|
||||
|
||||
return (
|
||||
<TagsDiv className="tag-list">
|
||||
{tagsIsLong && typeof tempMaxTags === 'number' ? (
|
||||
<>
|
||||
{tags.slice(0, tempMaxTags - 1).map((tag: TagType, index) => (
|
||||
{sortedTags.slice(0, tempMaxTags - 1).map((tag: TagType, index) => (
|
||||
<Tag
|
||||
id={tag.id}
|
||||
key={tag.id}
|
||||
@@ -82,17 +93,17 @@ export const TagsList = ({
|
||||
editable={editable}
|
||||
/>
|
||||
))}
|
||||
{tags.length > tempMaxTags ? (
|
||||
{sortedTags.length > tempMaxTags ? (
|
||||
<Tag
|
||||
name={`+${extraTags}...`}
|
||||
onClick={expand}
|
||||
toolTipTitle={tags.map(t => t.name).join(', ')}
|
||||
toolTipTitle={sortedTags.map(t => t.name).join(', ')}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{tags.map((tag: TagType, index) => (
|
||||
{sortedTags.map((tag: TagType, index) => (
|
||||
<Tag
|
||||
id={tag.id}
|
||||
key={tag.id}
|
||||
@@ -103,7 +114,7 @@ export const TagsList = ({
|
||||
/>
|
||||
))}
|
||||
{maxTags ? (
|
||||
tags.length > maxTags ? (
|
||||
sortedTags.length > maxTags ? (
|
||||
<Tag name="..." onClick={collapse} />
|
||||
) : null
|
||||
) : null}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
* under the License.
|
||||
*/
|
||||
import { DEFAULT_D3_FORMAT, DEFAULT_D3_TIME_FORMAT } from '@superset-ui/core';
|
||||
|
||||
import { BootstrapData, CommonBootstrapData } from './types/bootstrapTypes';
|
||||
|
||||
export const DATETIME_WITH_TIME_ZONE = 'YYYY-MM-DD HH:mm:ssZ';
|
||||
@@ -141,7 +140,11 @@ export const DEFAULT_COMMON_BOOTSTRAP_DATA: CommonBootstrapData = {
|
||||
},
|
||||
extra_categorical_color_schemes: [],
|
||||
extra_sequential_color_schemes: [],
|
||||
theme: {},
|
||||
theme: {
|
||||
default: {},
|
||||
dark: {},
|
||||
settings: {},
|
||||
},
|
||||
menu_data: {
|
||||
menu: [],
|
||||
brand: {
|
||||
|
||||
@@ -294,6 +294,7 @@ export function saveDashboardRequest(data, id, saveType) {
|
||||
owners,
|
||||
roles,
|
||||
slug,
|
||||
tags,
|
||||
} = data;
|
||||
|
||||
const hasId = item => item.id !== undefined;
|
||||
@@ -315,6 +316,9 @@ export function saveDashboardRequest(data, id, saveType) {
|
||||
? undefined
|
||||
: ensureIsArray(roles).map(r => (hasId(r) ? r.id : r)),
|
||||
slug: slug || null,
|
||||
tags: !isFeatureEnabled(FeatureFlag.TaggingSystem)
|
||||
? undefined
|
||||
: ensureIsArray(tags || []).map(r => (hasId(r) ? r.id : r)),
|
||||
metadata: {
|
||||
...data.metadata,
|
||||
color_namespace: getColorNamespace(data.metadata?.color_namespace),
|
||||
@@ -445,6 +449,7 @@ export function saveDashboardRequest(data, id, saveType) {
|
||||
slug: cleanedData.slug,
|
||||
owners: cleanedData.owners,
|
||||
roles: cleanedData.roles,
|
||||
tags: cleanedData.tags || [],
|
||||
json_metadata: safeStringify({
|
||||
...(cleanedData?.metadata || {}),
|
||||
default_filters: safeStringify(serializedFilters),
|
||||
|
||||
@@ -23,6 +23,11 @@ import {
|
||||
within,
|
||||
screen,
|
||||
} from 'spec/helpers/testing-library';
|
||||
import { FeatureFlag } from '@superset-ui/core';
|
||||
import {
|
||||
OPEN_FILTER_BAR_WIDTH,
|
||||
CLOSED_FILTER_BAR_WIDTH,
|
||||
} from 'src/dashboard/constants';
|
||||
import DashboardBuilder from 'src/dashboard/components/DashboardBuilder/DashboardBuilder';
|
||||
import useStoredSidebarWidth from 'src/components/ResizableSidebar/useStoredSidebarWidth';
|
||||
import {
|
||||
@@ -268,6 +273,46 @@ describe('DashboardBuilder', () => {
|
||||
expect(filterbar).toHaveStyleRule('width', `${expectedValue}px`);
|
||||
});
|
||||
|
||||
it('filter panel state when featureflag is true', () => {
|
||||
window.featureFlags = {
|
||||
[FeatureFlag.FilterBarClosedByDefault]: true,
|
||||
};
|
||||
const setter = jest.fn();
|
||||
(useStoredSidebarWidth as jest.Mock).mockImplementation(() => [
|
||||
CLOSED_FILTER_BAR_WIDTH,
|
||||
setter,
|
||||
]);
|
||||
const { getByTestId } = setup({
|
||||
dashboardInfo: {
|
||||
...mockState.dashboardInfo,
|
||||
dash_edit_perm: true,
|
||||
},
|
||||
});
|
||||
|
||||
const filterbar = getByTestId('dashboard-filters-panel');
|
||||
expect(filterbar).toHaveStyleRule('width', `${CLOSED_FILTER_BAR_WIDTH}px`);
|
||||
});
|
||||
|
||||
it('filter panel state when featureflag is false', () => {
|
||||
window.featureFlags = {
|
||||
[FeatureFlag.FilterBarClosedByDefault]: false,
|
||||
};
|
||||
const setter = jest.fn();
|
||||
(useStoredSidebarWidth as jest.Mock).mockImplementation(() => [
|
||||
OPEN_FILTER_BAR_WIDTH,
|
||||
setter,
|
||||
]);
|
||||
const { getByTestId } = setup({
|
||||
dashboardInfo: {
|
||||
...mockState.dashboardInfo,
|
||||
dash_edit_perm: true,
|
||||
},
|
||||
});
|
||||
|
||||
const filterbar = getByTestId('dashboard-filters-panel');
|
||||
expect(filterbar).toHaveStyleRule('width', `${OPEN_FILTER_BAR_WIDTH}px`);
|
||||
});
|
||||
|
||||
it('should not render the filter bar when nativeFiltersEnabled is false', () => {
|
||||
jest.spyOn(useNativeFiltersModule, 'useNativeFilters').mockReturnValue({
|
||||
showDashboard: true,
|
||||
|
||||
@@ -21,6 +21,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { URL_PARAMS } from 'src/constants';
|
||||
import { getUrlParam } from 'src/utils/urlUtils';
|
||||
import { RootState } from 'src/dashboard/types';
|
||||
import { isFeatureEnabled, FeatureFlag } from '@superset-ui/core';
|
||||
import {
|
||||
useFilters,
|
||||
useNativeFiltersDataMask,
|
||||
@@ -71,6 +72,8 @@ export const useNativeFilters = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
(isFeatureEnabled(FeatureFlag.FilterBarClosedByDefault) &&
|
||||
expandFilters === null) ||
|
||||
expandFilters === false ||
|
||||
(filterValues.length === 0 && nativeFiltersEnabled)
|
||||
) {
|
||||
|
||||
@@ -53,6 +53,7 @@ import {
|
||||
DASHBOARD_POSITION_DATA_LIMIT,
|
||||
DASHBOARD_HEADER_ID,
|
||||
} from 'src/dashboard/util/constants';
|
||||
import { TagTypeEnum } from 'src/components/Tag/TagType';
|
||||
import setPeriodicRunner, {
|
||||
stopPeriodicRender,
|
||||
} from 'src/dashboard/util/setPeriodicRunner';
|
||||
@@ -415,6 +416,9 @@ const Header = () => {
|
||||
owners: dashboardInfo.owners,
|
||||
roles: dashboardInfo.roles,
|
||||
slug,
|
||||
tags: (dashboardInfo.tags || []).filter(
|
||||
item => item.type === TagTypeEnum.Custom || !item.type,
|
||||
),
|
||||
metadata: {
|
||||
...dashboardInfo?.metadata,
|
||||
color_namespace: currentColorNamespace,
|
||||
@@ -459,6 +463,7 @@ const Header = () => {
|
||||
dashboardInfo.metadata,
|
||||
dashboardInfo.owners,
|
||||
dashboardInfo.roles,
|
||||
dashboardInfo.tags,
|
||||
dashboardTitle,
|
||||
layout,
|
||||
refreshFrequency,
|
||||
@@ -525,6 +530,7 @@ const Header = () => {
|
||||
certification_details: updates.certificationDetails,
|
||||
owners: updates.owners,
|
||||
roles: updates.roles,
|
||||
tags: updates.tags,
|
||||
});
|
||||
boundActionCreators.setUnsavedChanges(true);
|
||||
boundActionCreators.dashboardTitleChanged(updates.title);
|
||||
|
||||
@@ -383,7 +383,7 @@ const PropertiesModal = ({
|
||||
|
||||
currentJsonMetadata = jsonStringify(metadata);
|
||||
|
||||
const moreOnSubmitProps: { roles?: Roles } = {};
|
||||
const moreOnSubmitProps: { roles?: Roles; tags?: TagType[] } = {};
|
||||
const morePutProps: {
|
||||
roles?: number[];
|
||||
tags?: (string | number | undefined)[];
|
||||
@@ -393,6 +393,7 @@ const PropertiesModal = ({
|
||||
morePutProps.roles = (roles || []).map(r => r.id);
|
||||
}
|
||||
if (isFeatureEnabled(FeatureFlag.TaggingSystem)) {
|
||||
moreOnSubmitProps.tags = tags;
|
||||
morePutProps.tags = tags.map(tag => tag.id);
|
||||
}
|
||||
const onSubmitProps = {
|
||||
@@ -600,6 +601,10 @@ const PropertiesModal = ({
|
||||
setTags(parsedTags);
|
||||
};
|
||||
|
||||
const handleClearTags = () => {
|
||||
setTags([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
show={show}
|
||||
@@ -725,6 +730,7 @@ const PropertiesModal = ({
|
||||
value={tagsAsSelectValues}
|
||||
options={loadTags}
|
||||
onChange={handleChangeTags}
|
||||
onClear={handleClearTags}
|
||||
allowClear
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
@@ -59,6 +59,7 @@ type SliceHeaderProps = SliceHeaderControlsProps & {
|
||||
formData: object;
|
||||
width: number;
|
||||
height: number;
|
||||
exportPivotExcel?: (arg0: string) => void;
|
||||
};
|
||||
|
||||
const annotationsLoading = t('Annotation layers are still loading.');
|
||||
@@ -167,6 +168,7 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
|
||||
formData,
|
||||
width,
|
||||
height,
|
||||
exportPivotExcel = () => ({}),
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
@@ -344,6 +346,7 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
|
||||
formData={formData}
|
||||
exploreUrl={exploreUrl}
|
||||
crossFiltersEnabled={isCrossFiltersEnabled}
|
||||
exportPivotExcel={exportPivotExcel}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -33,6 +33,7 @@ const createProps = (viz_type = VizType.Sunburst) =>
|
||||
exportFullCSV: jest.fn(),
|
||||
exportXLSX: jest.fn(),
|
||||
exportFullXLSX: jest.fn(),
|
||||
exportPivotExcel: jest.fn(),
|
||||
forceRefresh: jest.fn(),
|
||||
handleToggleFullSize: jest.fn(),
|
||||
toggleExpandSlice: jest.fn(),
|
||||
@@ -254,6 +255,20 @@ test('Should not show export full Excel if report is not table', async () => {
|
||||
expect(screen.queryByText('Export to full Excel')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Should export to pivoted Excel if report is pivot table', async () => {
|
||||
const props = createProps(VizType.PivotTable);
|
||||
renderWrapper(props);
|
||||
openMenu();
|
||||
expect(props.exportPivotExcel).toHaveBeenCalledTimes(0);
|
||||
userEvent.hover(screen.getByText('Download'));
|
||||
userEvent.click(await screen.findByText('Export to Pivoted Excel'));
|
||||
expect(props.exportPivotExcel).toHaveBeenCalledTimes(1);
|
||||
expect(props.exportPivotExcel).toHaveBeenCalledWith(
|
||||
'.pvtTable',
|
||||
props.slice.slice_name,
|
||||
);
|
||||
});
|
||||
|
||||
test('Should "Show chart description"', () => {
|
||||
const props = createProps();
|
||||
renderWrapper(props);
|
||||
|
||||
@@ -128,6 +128,7 @@ export interface SliceHeaderControlsProps {
|
||||
exportXLSX?: (sliceId: number) => void;
|
||||
exportFullXLSX?: (sliceId: number) => void;
|
||||
handleToggleFullSize: () => void;
|
||||
exportPivotExcel?: (tableSelector: string, sliceName: string) => void;
|
||||
|
||||
addDangerToast: (message: string) => void;
|
||||
addSuccessToast: (message: string) => void;
|
||||
@@ -255,6 +256,10 @@ const SliceHeaderControls = (
|
||||
});
|
||||
break;
|
||||
}
|
||||
case MenuKeys.ExportPivotXlsx: {
|
||||
props.exportPivotExcel?.('.pvtTable', props.slice.slice_name);
|
||||
break;
|
||||
}
|
||||
case MenuKeys.CrossFilterScoping: {
|
||||
openScopingModal();
|
||||
break;
|
||||
@@ -468,6 +473,15 @@ const SliceHeaderControls = (
|
||||
{t('Export to Excel')}
|
||||
</Menu.Item>
|
||||
|
||||
{isPivotTable && (
|
||||
<Menu.Item
|
||||
key={MenuKeys.ExportPivotXlsx}
|
||||
icon={<Icons.FileOutlined css={dropdownIconsStyles} />}
|
||||
>
|
||||
{t('Export to Pivoted Excel')}
|
||||
</Menu.Item>
|
||||
)}
|
||||
|
||||
{isFeatureEnabled(FeatureFlag.AllowFullCsvExport) &&
|
||||
props.supersetCanCSV &&
|
||||
isTable && (
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
import { postFormData } from 'src/explore/exploreUtils/formData';
|
||||
import { URL_PARAMS } from 'src/constants';
|
||||
import { enforceSharedLabelsColorsArray } from 'src/utils/colorScheme';
|
||||
import exportPivotExcel from 'src/utils/downloadAsPivotExcel';
|
||||
|
||||
import SliceHeader from '../SliceHeader';
|
||||
import MissingChart from '../MissingChart';
|
||||
@@ -128,6 +129,9 @@ const Chart = props => {
|
||||
);
|
||||
|
||||
const chart = useSelector(state => state.charts[props.id] || EMPTY_OBJECT);
|
||||
const { queriesResponse, chartUpdateEndTime, chartStatus, annotationQuery } =
|
||||
chart;
|
||||
|
||||
const slice = useSelector(
|
||||
state => state.sliceEntities.slices[props.id] || EMPTY_OBJECT,
|
||||
);
|
||||
@@ -162,6 +166,12 @@ const Chart = props => {
|
||||
);
|
||||
const dashboardInfo = useSelector(state => state.dashboardInfo);
|
||||
|
||||
const isCached = useMemo(
|
||||
// eslint-disable-next-line camelcase
|
||||
() => queriesResponse?.map(({ is_cached }) => is_cached) || [],
|
||||
[queriesResponse],
|
||||
);
|
||||
|
||||
const [descriptionHeight, setDescriptionHeight] = useState(0);
|
||||
const [height, setHeight] = useState(props.height);
|
||||
const [width, setWidth] = useState(props.width);
|
||||
@@ -213,11 +223,15 @@ const Chart = props => {
|
||||
|
||||
const getHeaderHeight = useCallback(() => {
|
||||
if (headerRef.current) {
|
||||
const computedStyle = getComputedStyle(
|
||||
const computedMarginBottom = getComputedStyle(
|
||||
headerRef.current,
|
||||
).getPropertyValue('margin-bottom');
|
||||
const marginBottom = parseInt(computedStyle, 10) || 0;
|
||||
return headerRef.current.offsetHeight + marginBottom;
|
||||
const marginBottom = parseInt(computedMarginBottom, 10) || 0;
|
||||
const computedHeight = getComputedStyle(
|
||||
headerRef.current,
|
||||
).getPropertyValue('height');
|
||||
const height = parseInt(computedHeight, 10) || DEFAULT_HEADER_HEIGHT;
|
||||
return height + marginBottom;
|
||||
}
|
||||
return DEFAULT_HEADER_HEIGHT;
|
||||
}, [headerRef]);
|
||||
@@ -244,9 +258,9 @@ const Chart = props => {
|
||||
const logExploreChart = useCallback(() => {
|
||||
boundActionCreators.logEvent(LOG_ACTIONS_EXPLORE_DASHBOARD_CHART, {
|
||||
slice_id: slice.slice_id,
|
||||
is_cached: props.isCached,
|
||||
is_cached: isCached,
|
||||
});
|
||||
}, [boundActionCreators.logEvent, slice.slice_id, props.isCached]);
|
||||
}, [boundActionCreators.logEvent, slice.slice_id, isCached]);
|
||||
|
||||
const chartConfiguration = useSelector(
|
||||
state => state.dashboardInfo.metadata?.chart_configuration,
|
||||
@@ -360,22 +374,22 @@ const Chart = props => {
|
||||
: LOG_ACTIONS_EXPORT_XLSX_DASHBOARD_CHART;
|
||||
boundActionCreators.logEvent(logAction, {
|
||||
slice_id: slice.slice_id,
|
||||
is_cached: props.isCached,
|
||||
is_cached: isCached,
|
||||
});
|
||||
exportChart({
|
||||
formData: isFullCSV ? { ...formData, row_limit: maxRows } : formData,
|
||||
resultType: isPivot ? 'post_processed' : 'full',
|
||||
resultFormat: format,
|
||||
force: true,
|
||||
ownState: props.ownState,
|
||||
ownState: dataMask[props.id]?.ownState,
|
||||
});
|
||||
},
|
||||
[
|
||||
slice.slice_id,
|
||||
props.isCached,
|
||||
isCached,
|
||||
formData,
|
||||
props.maxRows,
|
||||
props.ownState,
|
||||
dataMask[props.id]?.ownState,
|
||||
boundActionCreators.logEvent,
|
||||
],
|
||||
);
|
||||
@@ -403,7 +417,7 @@ const Chart = props => {
|
||||
const forceRefresh = useCallback(() => {
|
||||
boundActionCreators.logEvent(LOG_ACTIONS_FORCE_REFRESH_CHART, {
|
||||
slice_id: slice.slice_id,
|
||||
is_cached: props.isCached,
|
||||
is_cached: isCached,
|
||||
});
|
||||
return boundActionCreators.refreshChart(chart.id, true, props.dashboardId);
|
||||
}, [
|
||||
@@ -411,7 +425,7 @@ const Chart = props => {
|
||||
chart.id,
|
||||
props.dashboardId,
|
||||
slice.slice_id,
|
||||
props.isCached,
|
||||
isCached,
|
||||
boundActionCreators.logEvent,
|
||||
]);
|
||||
|
||||
@@ -419,11 +433,7 @@ const Chart = props => {
|
||||
return <MissingChart height={getChartHeight()} />;
|
||||
}
|
||||
|
||||
const { queriesResponse, chartUpdateEndTime, chartStatus, annotationQuery } =
|
||||
chart;
|
||||
const isLoading = chartStatus === 'loading';
|
||||
// eslint-disable-next-line camelcase
|
||||
const isCached = queriesResponse?.map(({ is_cached }) => is_cached) || [];
|
||||
const cachedDttm =
|
||||
// eslint-disable-next-line camelcase
|
||||
queriesResponse?.map(({ cached_dttm }) => cached_dttm) || [];
|
||||
@@ -471,6 +481,7 @@ const Chart = props => {
|
||||
formData={formData}
|
||||
width={width}
|
||||
height={getHeaderHeight()}
|
||||
exportPivotExcel={exportPivotExcel}
|
||||
/>
|
||||
|
||||
{/*
|
||||
|
||||
@@ -27,6 +27,7 @@ export default function DownloadAsImage({
|
||||
text,
|
||||
logEvent,
|
||||
dashboardTitle,
|
||||
...props
|
||||
}: {
|
||||
text: string;
|
||||
dashboardTitle: string;
|
||||
@@ -50,6 +51,7 @@ export default function DownloadAsImage({
|
||||
onClick={e => {
|
||||
onDownloadImage(e.domEvent);
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{text}
|
||||
</Menu.Item>
|
||||
|
||||
@@ -27,6 +27,7 @@ export default function DownloadAsPdf({
|
||||
text,
|
||||
logEvent,
|
||||
dashboardTitle,
|
||||
...props
|
||||
}: {
|
||||
text: string;
|
||||
dashboardTitle: string;
|
||||
@@ -50,6 +51,7 @@ export default function DownloadAsPdf({
|
||||
onClick={e => {
|
||||
onDownloadPdf(e.domEvent);
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{text}
|
||||
</Menu.Item>
|
||||
|
||||
@@ -46,7 +46,7 @@ const containerStyle = (theme: SupersetTheme) => css`
|
||||
display: flex;
|
||||
|
||||
&& > .filter-clear-all-button {
|
||||
color: ${theme.colors.grayscale.base};
|
||||
color: ${theme.colorTextSecondary};
|
||||
margin-left: 0;
|
||||
&:hover {
|
||||
color: ${theme.colorPrimaryText};
|
||||
@@ -54,7 +54,7 @@ const containerStyle = (theme: SupersetTheme) => css`
|
||||
|
||||
&[disabled],
|
||||
&[disabled]:hover {
|
||||
color: ${theme.colors.grayscale.light1};
|
||||
color: ${theme.colorTextDisabled};
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -62,7 +62,6 @@ const containerStyle = (theme: SupersetTheme) => css`
|
||||
const verticalStyle = (theme: SupersetTheme, width: number) => css`
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
|
||||
@@ -74,14 +73,10 @@ const verticalStyle = (theme: SupersetTheme, width: number) => css`
|
||||
padding-top: ${theme.sizeUnit * 6}px;
|
||||
|
||||
background: linear-gradient(
|
||||
${rgba(theme.colors.grayscale.light5, 0)},
|
||||
${theme.colors.grayscale.light5} 60%
|
||||
${rgba(theme.colorBgLayout, 0)},
|
||||
${theme.colorBgElevated} 20%
|
||||
);
|
||||
|
||||
& > button {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
& > .filter-apply-button {
|
||||
margin-bottom: ${theme.sizeUnit * 3}px;
|
||||
}
|
||||
@@ -94,13 +89,6 @@ const horizontalStyle = (theme: SupersetTheme) => css`
|
||||
text-transform: capitalize;
|
||||
font-weight: ${theme.fontWeightNormal};
|
||||
}
|
||||
& > .filter-apply-button {
|
||||
&[disabled],
|
||||
&[disabled]:hover {
|
||||
color: ${theme.colors.grayscale.light1};
|
||||
background: ${theme.colors.grayscale.light3};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ButtonsContainer = styled.div<{ isVertical: boolean; width: number }>`
|
||||
|
||||
@@ -289,4 +289,5 @@ export enum MenuKeys {
|
||||
ToggleFullscreen = 'toggle_fullscreen',
|
||||
ManageEmbedded = 'manage_embedded',
|
||||
ManageEmailReports = 'manage_email_reports',
|
||||
ExportPivotXlsx = 'export_pivot_xlsx',
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export const CopyToClipboardButton = ({
|
||||
}) => (
|
||||
<CopyToClipboard
|
||||
text={
|
||||
data && columns ? prepareCopyToClipboardTabularData([data], columns) : ''
|
||||
data && columns ? prepareCopyToClipboardTabularData(data, columns) : ''
|
||||
}
|
||||
wrapped={false}
|
||||
copyNode={
|
||||
|
||||
@@ -62,8 +62,7 @@ export const TableControls = ({
|
||||
name &&
|
||||
!originalTimeColumns.includes(name),
|
||||
)
|
||||
.map(([colname]) => colname)
|
||||
.filter((colname): colname is string => colname !== undefined);
|
||||
.map(([colname]) => colname);
|
||||
const formattedData = useMemo(
|
||||
() => applyFormattingToTabularData(data, formattedTimeColumns),
|
||||
[data, formattedTimeColumns],
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import { Tooltip } from '@superset-ui/core/components/Tooltip';
|
||||
import { Typography } from '@superset-ui/core/components';
|
||||
import DatasourcePanelDragOption from './DatasourcePanelDragOption';
|
||||
import { DndItemType } from '../DndItemType';
|
||||
import { DndItemValue, FlattenedItem, Folder } from './types';
|
||||
@@ -94,7 +95,7 @@ const SectionHeaderTextContainer = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const SectionHeader = styled.span`
|
||||
const SectionHeader = styled(Typography.Text)`
|
||||
${({ theme }) => css`
|
||||
font-size: ${theme.fontSize}px;
|
||||
font-weight: ${theme.fontWeightStrong};
|
||||
|
||||
@@ -46,6 +46,7 @@ import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import Chart, { Slice } from 'src/types/Chart';
|
||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
||||
import { type TagType } from 'src/components';
|
||||
import { TagTypeEnum } from 'src/components/Tag/TagType';
|
||||
import { loadTags } from 'src/components/Tag/utils';
|
||||
|
||||
export type PropertiesModalProps = {
|
||||
@@ -125,7 +126,7 @@ function PropertiesModal({
|
||||
);
|
||||
if (isFeatureEnabled(FeatureFlag.TaggingSystem)) {
|
||||
const customTags = chart.tags?.filter(
|
||||
(tag: TagType) => tag.type === 1,
|
||||
(tag: TagType) => tag.type === TagTypeEnum.Custom,
|
||||
);
|
||||
setTags(customTags);
|
||||
}
|
||||
|
||||
@@ -479,3 +479,30 @@ test('should show missing dataset state', () => {
|
||||
),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('should show forbidden dataset state', () => {
|
||||
// @ts-ignore
|
||||
delete window.location;
|
||||
// @ts-ignore
|
||||
window.location = { search: '?slice_id=152' };
|
||||
const error = {
|
||||
error_type: 'TABLE_SECURITY_ACCESS_ERROR',
|
||||
statusText: 'FORBIDDEN',
|
||||
message: 'You do not have access to the following tables: blocked_table',
|
||||
extra: {
|
||||
datasource: 152,
|
||||
datasource_name: 'forbidden dataset',
|
||||
},
|
||||
};
|
||||
const props = createProps({
|
||||
datasource: {
|
||||
...fallbackExploreInitialData.dataset,
|
||||
extra: {
|
||||
error,
|
||||
},
|
||||
},
|
||||
});
|
||||
render(<DatasourceControl {...props} />, { useRedux: true, useRouter: true });
|
||||
expect(screen.getByText(error.message)).toBeInTheDocument();
|
||||
expect(screen.getByText(error.statusText)).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
userHasPermission,
|
||||
isUserAdmin,
|
||||
} from 'src/dashboard/util/permissionUtils';
|
||||
import { ErrorMessageWithStackTrace } from 'src/components/ErrorMessage/ErrorMessageWithStackTrace';
|
||||
import ViewQueryModalFooter from 'src/explore/components/controls/ViewQueryModalFooter';
|
||||
import ViewQuery from 'src/explore/components/controls/ViewQuery';
|
||||
import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal';
|
||||
@@ -94,6 +95,7 @@ const Styles = styled.div`
|
||||
}
|
||||
.error-alert {
|
||||
margin: ${({ theme }) => 2 * theme.sizeUnit}px;
|
||||
min-height: 150px;
|
||||
}
|
||||
.ant-dropdown-trigger {
|
||||
margin-left: ${({ theme }) => 2 * theme.sizeUnit}px;
|
||||
@@ -281,7 +283,17 @@ class DatasourceControl extends PureComponent {
|
||||
showSaveDatasetModal,
|
||||
} = this.state;
|
||||
const { datasource, onChange, theme } = this.props;
|
||||
const isMissingDatasource = !datasource?.id;
|
||||
let extra;
|
||||
if (datasource?.extra) {
|
||||
if (typeof datasource.extra === 'string') {
|
||||
try {
|
||||
extra = JSON.parse(datasource.extra);
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
} else {
|
||||
extra = datasource.extra; // eslint-disable-line prefer-destructuring
|
||||
}
|
||||
}
|
||||
const isMissingDatasource = !datasource?.id || Boolean(extra?.error);
|
||||
let isMissingParams = false;
|
||||
if (isMissingDatasource) {
|
||||
const datasourceId = getUrlParam(URL_PARAMS.datasourceId);
|
||||
@@ -386,20 +398,10 @@ class DatasourceControl extends PureComponent {
|
||||
|
||||
const { health_check_message: healthCheckMessage } = datasource;
|
||||
|
||||
let extra;
|
||||
if (datasource?.extra) {
|
||||
if (typeof datasource.extra === 'string') {
|
||||
try {
|
||||
extra = JSON.parse(datasource.extra);
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
} else {
|
||||
extra = datasource.extra; // eslint-disable-line prefer-destructuring
|
||||
}
|
||||
}
|
||||
|
||||
const titleText = isMissingDatasource
|
||||
? t('Missing dataset')
|
||||
: getDatasourceTitle(datasource);
|
||||
const titleText =
|
||||
isMissingDatasource && !datasource.name
|
||||
? t('Missing dataset')
|
||||
: getDatasourceTitle(datasource);
|
||||
|
||||
const tooltip = titleText;
|
||||
|
||||
@@ -452,31 +454,42 @@ class DatasourceControl extends PureComponent {
|
||||
)}
|
||||
{isMissingDatasource && !isMissingParams && (
|
||||
<div className="error-alert">
|
||||
<ErrorAlert
|
||||
type="warning"
|
||||
errorType={t('Missing dataset')}
|
||||
descriptionPre={false}
|
||||
descriptionDetailsCollapsed={false}
|
||||
descriptionDetails={
|
||||
<>
|
||||
<p>
|
||||
{t(
|
||||
'The dataset linked to this chart may have been deleted.',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
<Button
|
||||
buttonStyle="warning"
|
||||
onClick={() =>
|
||||
this.handleMenuItemClick({ key: CHANGE_DATASET })
|
||||
}
|
||||
>
|
||||
{t('Swap dataset')}
|
||||
</Button>
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
{extra?.error ? (
|
||||
<ErrorMessageWithStackTrace
|
||||
title={extra.error.statusText || extra.error.message}
|
||||
subtitle={
|
||||
extra.error.statusText ? extra.error.message : undefined
|
||||
}
|
||||
error={extra.error}
|
||||
source="explore"
|
||||
/>
|
||||
) : (
|
||||
<ErrorAlert
|
||||
type="warning"
|
||||
errorType={t('Missing dataset')}
|
||||
descriptionPre={false}
|
||||
descriptionDetailsCollapsed={false}
|
||||
descriptionDetails={
|
||||
<>
|
||||
<p>
|
||||
{t(
|
||||
'The dataset linked to this chart may have been deleted.',
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
<Button
|
||||
buttonStyle="warning"
|
||||
onClick={() =>
|
||||
this.handleMenuItemClick({ key: CHANGE_DATASET })
|
||||
}
|
||||
>
|
||||
{t('Swap dataset')}
|
||||
</Button>
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{showEditDatasourceModal && (
|
||||
|
||||
@@ -90,7 +90,10 @@ const DndFilterSelect = (props: DndFilterSelectProps) => {
|
||||
let extra = {};
|
||||
if (datasource?.extra) {
|
||||
try {
|
||||
extra = JSON.parse(datasource.extra);
|
||||
extra =
|
||||
typeof datasource.extra === 'string'
|
||||
? JSON.parse(datasource.extra)
|
||||
: datasource.extra;
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
}
|
||||
return extra;
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
LOG_ACTIONS_CHART_DOWNLOAD_AS_CSV_PIVOTED,
|
||||
LOG_ACTIONS_CHART_DOWNLOAD_AS_XLS,
|
||||
} from 'src/logger/LogUtils';
|
||||
import exportPivotExcel from 'src/utils/downloadAsPivotExcel';
|
||||
import ViewQueryModal from '../controls/ViewQueryModal';
|
||||
import EmbedCodeContent from '../EmbedCodeContent';
|
||||
import DashboardsSubMenu from './DashboardsSubMenu';
|
||||
@@ -67,6 +68,7 @@ const MENU_KEYS = {
|
||||
DELETE_REPORT: 'delete_report',
|
||||
VIEW_QUERY: 'view_query',
|
||||
RUN_IN_SQL_LAB: 'run_in_sql_lab',
|
||||
EXPORT_TO_PIVOT_XLSX: 'export_to_pivot_xlsx',
|
||||
};
|
||||
|
||||
const VIZ_TYPES_PIVOTABLE = [VizType.PivotTable];
|
||||
@@ -248,6 +250,16 @@ export const useExploreAdditionalActionsMenu = (
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case MENU_KEYS.EXPORT_TO_PIVOT_XLSX:
|
||||
exportPivotExcel('.pvtTable', slice?.slice_name ?? t('pivoted_xlsx'));
|
||||
setIsDropdownVisible(false);
|
||||
dispatch(
|
||||
logEvent(LOG_ACTIONS_CHART_DOWNLOAD_AS_XLS, {
|
||||
chartId: slice?.slice_id,
|
||||
chartName: slice?.slice_name,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case MENU_KEYS.DOWNLOAD_AS_IMAGE:
|
||||
downloadAsImage(
|
||||
'.panel-body .chart-container',
|
||||
@@ -365,6 +377,13 @@ export const useExploreAdditionalActionsMenu = (
|
||||
>
|
||||
{t('Export to Excel')}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key={MENU_KEYS.EXPORT_TO_PIVOT_XLSX}
|
||||
icon={<Icons.FileOutlined />}
|
||||
disabled={!canDownloadCSV}
|
||||
>
|
||||
{t('Export to Pivoted Excel')}
|
||||
</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
<Menu.SubMenu title={t('Share')} key={MENU_KEYS.SHARE_SUBMENU}>
|
||||
<Menu.Item key={MENU_KEYS.COPY_PERMALINK}>
|
||||
|
||||
@@ -159,8 +159,8 @@ export const fallbackExploreInitialData: ExplorePageInitialData = {
|
||||
verbose_map: {},
|
||||
main_dttm_col: '',
|
||||
owners: [],
|
||||
datasource_name: 'missing_datasource',
|
||||
name: 'missing_datasource',
|
||||
datasource_name: '',
|
||||
name: '',
|
||||
description: null,
|
||||
},
|
||||
slice: null,
|
||||
|
||||
@@ -69,7 +69,7 @@ export type Datasource = Dataset & {
|
||||
catalog?: string | null;
|
||||
schema?: string;
|
||||
is_sqllab_view?: boolean;
|
||||
extra?: string;
|
||||
extra?: string | object;
|
||||
};
|
||||
|
||||
export interface ExplorePageInitialData {
|
||||
|
||||
@@ -191,4 +191,32 @@ describe('ExtraOptions Component', () => {
|
||||
fireEvent.change(input, { target: { value: '1000' } });
|
||||
expect(onExtraInputChange).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders the collaps tab correctly and resets to default tab after closing', () => {
|
||||
const { rerender } = renderComponent();
|
||||
const sqlLabTab = screen.getByRole('tab', {
|
||||
name: /SQL Lab./i,
|
||||
});
|
||||
|
||||
expect(sqlLabTab).toHaveAttribute('aria-expanded', 'false');
|
||||
fireEvent.click(sqlLabTab);
|
||||
expect(sqlLabTab).toHaveAttribute('aria-expanded', 'true');
|
||||
const customDb = {
|
||||
...defaultDb,
|
||||
expose_in_sqllab: false,
|
||||
};
|
||||
|
||||
rerender(
|
||||
<ExtraOptions
|
||||
db={customDb as unknown as DatabaseObject}
|
||||
onInputChange={onInputChange}
|
||||
onTextChange={onTextChange}
|
||||
onEditorChange={onEditorChange}
|
||||
onExtraInputChange={onExtraInputChange}
|
||||
onExtraEditorChange={onExtraEditorChange}
|
||||
extraExtension={undefined}
|
||||
/>,
|
||||
);
|
||||
expect(sqlLabTab).toHaveAttribute('aria-expanded', 'false');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { ChangeEvent, EventHandler } from 'react';
|
||||
import { ChangeEvent, EventHandler, useState, useEffect } from 'react';
|
||||
import cx from 'classnames';
|
||||
import {
|
||||
t,
|
||||
@@ -88,12 +88,21 @@ const ExtraOptions = ({
|
||||
const isAllowRunAsyncDisabled = isFeatureEnabled(
|
||||
FeatureFlag.ForceSqlLabRunAsync,
|
||||
);
|
||||
const [activeKey, setActiveKey] = useState<string[] | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!expandableModalIsOpen && activeKey !== undefined) {
|
||||
setActiveKey(undefined);
|
||||
}
|
||||
}, [expandableModalIsOpen, activeKey]);
|
||||
|
||||
return (
|
||||
<Collapse
|
||||
expandIconPosition="end"
|
||||
accordion
|
||||
modalMode
|
||||
activeKey={activeKey}
|
||||
onChange={key => setActiveKey(key)}
|
||||
items={[
|
||||
{
|
||||
key: 'sql-lab',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user