Compare commits

..
Author SHA1 Message Date
yousoph ea3ba12ebf Update transformProps.ts 2025-07-17 14:45:06 -07:00
yousoph 268d8e8fee update test 2025-07-17 13:53:09 -07:00
yousoph ae71b837ff update tests 2025-07-17 13:48:59 -07:00
yousoph 12dd4a712e Update controlPanel.tsx 2025-07-17 10:22:32 -07:00
yousoph 04714b83c2 Update controlPanel.tsx 2025-07-17 00:07:57 -07:00
yousoph 6070e84944 Update transformProps.ts 2025-07-17 00:07:09 -07:00
yousoph 1cd939e612 Update transformProps.ts 2025-07-16 23:52:00 -07:00
yousoph e71a19a19e Update types.ts 2025-07-16 23:39:10 -07:00
yousoph e50e378d8b Update controlPanel.tsx 2025-07-16 23:31:23 -07:00
103 changed files with 1002 additions and 3677 deletions
-125
View File
@@ -1,125 +0,0 @@
---
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.
+1 -1
View File
@@ -42,7 +42,7 @@ body:
options:
- master / latest-dev
- "5.0.0"
- "4.1.3"
- "4.1.2"
validations:
required: true
- type: dropdown
+4 -13
View File
@@ -28,6 +28,7 @@ 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
@@ -39,17 +40,7 @@ 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
@@ -57,11 +48,11 @@ runs:
pip install --upgrade pip setuptools wheel uv
if [ "${{ inputs.requirements-type }}" = "dev" ]; then
uv pip install --system --prefer-binary -r requirements/development.txt
uv pip install --system -r requirements/development.txt
elif [ "${{ inputs.requirements-type }}" = "base" ]; then
uv pip install --system --prefer-binary -r requirements/base.txt
uv pip install --system -r requirements/base.txt
fi
uv pip install --system --prefer-binary -e .
uv pip install --system -e .
fi
shell: bash
-1
View File
@@ -1 +0,0 @@
../LLMS.md
-82
View File
@@ -1,82 +0,0 @@
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
View File
@@ -92,7 +92,6 @@ scripts/*.zip
# IntelliJ
*.iml
venv
.venv
@eaDir/
# PyCharm
@@ -127,7 +126,4 @@ docker/*local*
# Jest test report
test-report.html
superset/static/stats/statistics.html
# LLM-related
CLAUDE.local.md
.aider*
-8
View File
@@ -76,11 +76,3 @@ 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
View File
@@ -1,58 +0,0 @@
<!--
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)
-1
View File
@@ -1 +0,0 @@
LLMS.md
+3 -3
View File
@@ -167,7 +167,7 @@ RUN mkdir -p \
&& touch superset/static/version_info.json
# Install Playwright and optionally setup headless browsers
ARG INCLUDE_CHROMIUM="false"
ARG INCLUDE_CHROMIUM="true"
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 -e .
uv pip install .
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 -e .
uv pip install .
RUN uv pip install .[postgres]
RUN python -m compileall /app/superset
-1
View File
@@ -1 +0,0 @@
LLMS.md
-1
View File
@@ -1 +0,0 @@
LLMS.md
-148
View File
@@ -1,148 +0,0 @@
# 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.
+1 -2
View File
@@ -23,8 +23,7 @@ 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.
@@ -1,3 +1,4 @@
/* eslint-env node */
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -16,13 +17,31 @@
* specific language governing permissions and limitations
* under the License.
*/
import { utils, writeFile } from 'xlsx';
export default function exportPivotExcel(
tableSelector: string,
fileName: string,
) {
const table = document.querySelector(tableSelector);
const workbook = utils.table_to_book(table);
writeFile(workbook, `${fileName}.xlsx`);
}
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:prettier/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2020,
sourceType: 'module',
},
plugins: ['@typescript-eslint', 'react', 'prettier'],
rules: {
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
settings: {
react: {
version: 'detect',
},
},
ignorePatterns: ['build/**/*', '.docusaurus/**/*', 'node_modules/**/*'],
};
-78
View File
@@ -1,78 +0,0 @@
---
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",
],
...
}
```
-42
View File
@@ -194,48 +194,6 @@ 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
-72
View File
@@ -1,72 +0,0 @@
/* 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',
},
},
}
])
+5 -8
View File
@@ -40,18 +40,15 @@
"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": "^8.37.0",
"@typescript-eslint/parser": "^8.37.0",
"eslint": "^9.31.0",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.0",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-prettier": "^5.5.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.37.5",
"globals": "^16.3.0",
"prettier": "^3.6.2",
"prettier": "^2.0.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.37.0",
"webpack": "^5.99.9"
},
"browserslist": {
+1 -1
View File
@@ -111,7 +111,7 @@ const StyledTitleContainer = styled('div')`
}
`;
const StyledButton = styled(Link)`
const StyledButton = styled(Link as React.ComponentType<any>)`
border-radius: 10px;
font-size: 20px;
font-weight: bold;
+8 -12
View File
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
/* eslint-disable no-undef */
import { useEffect } from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
@@ -49,9 +50,7 @@ export default function Root({ children }) {
// Handle route changes for SPA
const handleRouteChange = () => {
if (devMode) {
console.log('Route changed to:', window.location.pathname);
}
devMode && console.log('Route changed to:', window.location.pathname);
// Short timeout to ensure the page has fully rendered
setTimeout(() => {
@@ -59,9 +58,11 @@ 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',
@@ -84,22 +85,17 @@ export default function Root({ children }) {
'routeDidUpdate',
];
if (devMode) {
console.log('Setting up Docusaurus route listeners');
}
devMode && console.log('Setting up Docusaurus route listeners');
possibleEvents.forEach(eventName => {
document.addEventListener(eventName, () => {
if (devMode) {
devMode &&
console.log(`Docusaurus route update detected via ${eventName}`);
}
handleRouteChange();
});
});
// Also set up manual history tracking as fallback
if (devMode) {
console.log('Setting up manual history tracking as fallback');
}
devMode && console.log('Setting up manual history tracking as fallback');
const originalPushState = window.history.pushState;
window.history.pushState = function () {
originalPushState.apply(this, arguments);
+198 -284
View File
@@ -2157,71 +2157,30 @@
dependencies:
eslint-visitor-keys "^3.4.3"
"@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":
"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1":
version "4.12.1"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz"
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
"@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==
"@eslint/eslintrc@^2.1.4":
version "2.1.4"
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz"
integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^10.0.1"
globals "^14.0.0"
espree "^9.6.0"
globals "^13.19.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@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"
"@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==
"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
version "9.3.0"
@@ -2235,33 +2194,24 @@
dependencies:
"@hapi/hoek" "^9.0.0"
"@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==
"@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==
dependencies:
"@humanfs/core" "^0.19.1"
"@humanwhocodes/retry" "^0.3.0"
"@humanwhocodes/object-schema" "^2.0.3"
debug "^4.3.1"
minimatch "^3.0.5"
"@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/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==
"@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==
"@iconify/types@^2.0.0":
version "2.0.0"
@@ -2403,7 +2353,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.3", "@nodelib/fs.walk@^1.2.8":
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==
@@ -2411,11 +2361,6 @@
"@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"
@@ -3654,6 +3599,11 @@
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"
@@ -3724,105 +3674,91 @@
dependencies:
"@types/yargs-parser" "*"
"@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==
"@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==
dependencies:
"@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"
"@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"
graphemer "^1.4.0"
ignore "^7.0.0"
natural-compare "^1.4.0"
ts-api-utils "^2.1.0"
ignore "^5.2.0"
natural-compare-lite "^1.4.0"
semver "^7.3.7"
tsutils "^3.21.0"
"@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==
"@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==
dependencies:
"@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"
"@typescript-eslint/scope-manager" "5.62.0"
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/typescript-estree" "5.62.0"
debug "^4.3.4"
"@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==
"@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==
dependencies:
"@typescript-eslint/tsconfig-utils" "^8.37.0"
"@typescript-eslint/types" "^8.37.0"
"@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"
debug "^4.3.4"
tsutils "^3.21.0"
"@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==
"@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==
dependencies:
"@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"
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/visitor-keys" "5.62.0"
debug "^4.3.4"
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"
globby "^11.1.0"
is-glob "^4.0.3"
minimatch "^9.0.4"
semver "^7.6.0"
ts-api-utils "^2.1.0"
semver "^7.3.7"
tsutils "^3.21.0"
"@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==
"@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==
dependencies:
"@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"
"@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"
"@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==
"@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==
dependencies:
"@typescript-eslint/types" "8.37.0"
eslint-visitor-keys "^4.2.1"
"@typescript-eslint/types" "5.62.0"
eslint-visitor-keys "^3.3.0"
"@ungap/structured-clone@^1.0.0":
"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8"
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
@@ -3978,16 +3914,11 @@ 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.0.0, acorn@^8.0.4, acorn@^8.11.0, acorn@^8.14.0, acorn@^8.8.2, acorn@^8.9.0:
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"
@@ -5075,7 +5006,7 @@ cosmiconfig@^8.1.3, cosmiconfig@^8.3.5:
parse-json "^5.2.0"
path-type "^4.0.0"
cross-spawn@^7.0.3, cross-spawn@^7.0.6:
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
@@ -5773,6 +5704,13 @@ 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"
@@ -6166,13 +6104,12 @@ 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@^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==
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==
dependencies:
prettier-linter-helpers "^1.0.0"
synckit "^0.11.7"
eslint-plugin-react@^7.37.5:
version "7.37.5"
@@ -6198,7 +6135,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==
@@ -6206,82 +6143,80 @@ eslint-scope@5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
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==
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==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^3.4.3:
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, 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-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==
eslint@^8.0.0:
version "8.57.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.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"
"@eslint-community/regexpp" "^4.6.1"
"@eslint/eslintrc" "^2.1.4"
"@eslint/js" "8.57.1"
"@humanwhocodes/config-array" "^0.13.0"
"@humanwhocodes/module-importer" "^1.0.1"
"@humanwhocodes/retry" "^0.4.2"
"@types/estree" "^1.0.6"
"@types/json-schema" "^7.0.15"
"@nodelib/fs.walk" "^1.2.8"
"@ungap/structured-clone" "^1.2.0"
ajv "^6.12.4"
chalk "^4.0.0"
cross-spawn "^7.0.6"
cross-spawn "^7.0.2"
debug "^4.3.2"
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
eslint-scope "^8.4.0"
eslint-visitor-keys "^4.2.1"
espree "^10.4.0"
esquery "^1.5.0"
eslint-scope "^7.2.2"
eslint-visitor-keys "^3.4.3"
espree "^9.6.1"
esquery "^1.4.2"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^8.0.0"
file-entry-cache "^6.0.1"
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@^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==
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==
dependencies:
acorn "^8.15.0"
acorn "^8.9.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^4.2.1"
eslint-visitor-keys "^3.4.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.5.0:
esquery@^1.4.2:
version "1.6.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz"
integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
dependencies:
estraverse "^5.1.0"
@@ -6476,7 +6411,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.3.2:
fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.0:
version "3.3.3"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
@@ -6549,12 +6484,12 @@ figures@^3.2.0:
dependencies:
escape-string-regexp "^1.0.5"
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==
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==
dependencies:
flat-cache "^4.0.0"
flat-cache "^3.0.4"
file-loader@^6.2.0:
version "6.2.0"
@@ -6613,13 +6548,14 @@ find-up@^6.3.0:
locate-path "^7.1.0"
path-exists "^5.0.0"
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==
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==
dependencies:
flatted "^3.2.9"
keyv "^4.5.4"
keyv "^4.5.3"
rimraf "^3.0.2"
flat@^5.0.2:
version "5.0.2"
@@ -6654,14 +6590,12 @@ form-data-encoder@^2.1.2:
integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==
form-data@^4.0.0:
version "4.0.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4"
integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==
version "4.0.0"
resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
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:
@@ -6847,21 +6781,18 @@ 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@^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@^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@^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"
@@ -7354,11 +7285,6 @@ 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"
@@ -7693,7 +7619,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.2, is-path-inside@^3.0.3:
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==
@@ -7995,7 +7921,7 @@ katex@^0.16.9:
dependencies:
commander "^8.3.0"
keyv@^4.5.3, keyv@^4.5.4:
keyv@^4.5.3:
version "4.5.4"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
@@ -9023,7 +8949,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.1.1, minimatch@^3.1.2:
minimatch@3.1.2, minimatch@^3.0.5, 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==
@@ -9037,13 +8963,6 @@ 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"
@@ -9092,6 +9011,11 @@ 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"
@@ -10241,10 +10165,10 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
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==
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==
pretty-error@^4.0.0:
version "4.0.0"
@@ -11514,11 +11438,6 @@ 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"
@@ -12139,13 +12058,6 @@ 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"
@@ -12172,6 +12084,11 @@ 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"
@@ -12263,11 +12180,6 @@ 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"
@@ -12283,11 +12195,23 @@ 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"
@@ -12382,16 +12306,6 @@ 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"
+1 -1
View File
@@ -29,7 +29,7 @@ maintainers:
- name: craig-rueda
email: craig@craigrueda.com
url: https://github.com/craig-rueda
version: 0.14.3
version: 0.14.2
dependencies:
- name: postgresql
version: 13.4.4
+1 -1
View File
@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
# superset
![Version: 0.14.3](https://img.shields.io/badge/Version-0.14.3-informational?style=flat-square)
![Version: 0.14.2](https://img.shields.io/badge/Version-0.14.2-informational?style=flat-square)
Apache Superset is a modern, enterprise-ready business intelligence web application
+5 -5
View File
@@ -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:
+5 -5
View File
@@ -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 }}
+5 -5
View File
@@ -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 }}
+5 -5
View File
@@ -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 }}
+5 -5
View File
@@ -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 }}
+5 -5
View File
@@ -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 }}
+34 -326
View File
@@ -3251,6 +3251,20 @@
"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",
@@ -3644,19 +3658,6 @@
"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",
@@ -4063,20 +4064,6 @@
"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",
@@ -4137,57 +4124,12 @@
"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",
@@ -4648,22 +4590,6 @@
}
}
},
"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",
@@ -4691,13 +4617,10 @@
}
},
"node_modules/function-bind": {
"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"
}
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
@@ -4717,30 +4640,6 @@
"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",
@@ -4750,19 +4649,6 @@
"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",
@@ -4825,18 +4711,6 @@
"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",
@@ -4865,45 +4739,6 @@
"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",
@@ -7092,15 +6927,6 @@
"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",
@@ -10739,6 +10565,19 @@
"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": {
@@ -11023,16 +10862,6 @@
"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",
@@ -11311,17 +11140,6 @@
"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",
@@ -11365,45 +11183,12 @@
"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",
@@ -11718,19 +11503,6 @@
"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",
@@ -11751,9 +11523,9 @@
"optional": true
},
"function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"gensync": {
@@ -11768,40 +11540,12 @@
"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",
@@ -11844,12 +11588,6 @@
"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",
@@ -11871,30 +11609,6 @@
"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",
@@ -13505,12 +13219,6 @@
"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",
+1 -1
View File
@@ -56,7 +56,7 @@ module.exports = {
],
coverageReporters: ['lcov', 'json-summary', 'html', 'text'],
transformIgnorePatterns: [
'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)',
'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)',
],
preset: 'ts-jest',
transform: {
+72 -1331
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -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,7 +203,6 @@
"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": {
@@ -202,7 +202,7 @@ export function AsyncAceEditor(
/* Basic editor styles with dark mode support */
.ace_editor.ace-github,
.ace_editor.ace-tm {
.ace_editor.ace-textmate {
background-color: ${token.colorBgContainer} !important;
color: ${token.colorText} !important;
}
@@ -70,6 +70,7 @@ export function Button(props: ButtonProps) {
if (!buttonStyle || buttonStyle === 'primary') {
variant = 'solid';
antdType = 'primary';
color = 'primary';
} else if (buttonStyle === 'secondary') {
variant = 'filled';
color = 'primary';
@@ -77,6 +78,7 @@ export function Button(props: ButtonProps) {
variant = 'outlined';
color = 'default';
} else if (buttonStyle === 'dashed') {
color = 'primary';
variant = 'dashed';
antdType = 'dashed';
} else if (buttonStyle === 'danger') {
@@ -132,11 +134,6 @@ 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,6 +31,11 @@ const StyledDiv = styled.div`
}
`;
const DescriptionContainer = styled.div`
line-height: ${({ theme }) => theme.sizeUnit * 4}px;
padding-top: 16px;
`;
export function DeleteModal({
description,
onConfirm,
@@ -76,12 +81,12 @@ export function DeleteModal({
onHide={hide}
onHandledPrimaryAction={confirm}
primaryButtonName={t('Delete')}
primaryButtonStyle="danger"
primaryButtonType="danger"
show={open}
title={title}
centered
>
{description}
<DescriptionContainer>{description}</DescriptionContainer>
<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',
primaryButtonStyle: 'danger',
primaryButtonType: '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 * 4}px;
padding: ${theme.sizeUnit * 4}px ${theme.sizeUnit * 6}px;
.ant-modal-title {
font-weight: ${theme.fontWeightStrong};
@@ -122,7 +122,6 @@ 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};`}
}
@@ -209,7 +208,7 @@ const CustomModal = ({
onHide,
onHandledPrimaryAction,
primaryButtonName = t('OK'),
primaryButtonStyle = 'primary',
primaryButtonType = 'primary',
show,
name,
title,
@@ -262,7 +261,7 @@ const CustomModal = ({
</Button>,
<Button
key="submit"
buttonStyle={primaryButtonStyle}
buttonStyle={primaryButtonType}
disabled={disablePrimaryButton}
tooltip={primaryTooltipMessage}
loading={primaryButtonLoading}
@@ -20,7 +20,6 @@ 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;
@@ -31,7 +30,7 @@ export interface ModalProps {
onHide: () => void;
onHandledPrimaryAction?: () => void;
primaryButtonName?: string;
primaryButtonStyle?: ButtonStyle;
primaryButtonType?: 'primary' | 'danger';
show: boolean;
name?: string;
title: ReactNode;
@@ -19,27 +19,18 @@
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') {
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;
}
if (
typeof v === 'string' &&
v.trim().length > 0 &&
v.trim().startsWith('mapbox://styles/')
) {
return false;
}
return t(
'is expected to be a Mapbox/OSM URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
);
return t('is expected to be a Mapbox URL');
}
@@ -29,11 +29,6 @@ describe('validateMapboxStylesUrl', () => {
'mapbox://styles/foobar/clp2dr5r4008a01pcg4ad45m8',
),
).toEqual(false);
expect(
validateMapboxStylesUrl(
'tile://https://c.tile.openstreetmap.org/{z}/{x}/{y}.png',
),
).toEqual(false);
});
[
@@ -45,7 +40,7 @@ describe('validateMapboxStylesUrl', () => {
].forEach(value => {
it(`should not validate ${value}`, () => {
expect(validateMapboxStylesUrl(value)).toEqual(
'is expected to be a Mapbox/OSM URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
'is expected to be a Mapbox URL',
);
});
});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -42,8 +42,4 @@ 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.all.min';
import Datamap from 'datamaps/dist/datamaps.world.min';
import { ColorBy } from './utils';
const propTypes = {
@@ -24,17 +24,10 @@
"lib"
],
"dependencies": {
"@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",
"@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",
"@mapbox/geojson-extent": "^1.0.1",
"@math.gl/web-mercator": "^4.1.0",
"@types/d3-array": "^2.0.0",
@@ -39,12 +39,6 @@ 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
@@ -108,20 +102,6 @@ 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 =>
@@ -130,7 +110,7 @@ export const DeckGLContainer = memo(
}
return props.layers as Layer[];
}, [props.layers, props.mapStyle]);
}, [props.layers]);
const { children = null, height, width } = props;
@@ -154,13 +134,11 @@ export const DeckGLContainer = memo(
glContextRef.current = context.gl;
}}
>
{props.mapStyle?.startsWith(MAPBOX_LAYER_PREFIX) && (
<StaticMap
preserveDrawingBuffer
mapStyle={props.mapStyle || 'light'}
mapboxApiAccessToken={props.mapboxApiAccessToken}
/>
)}
<StaticMap
preserveDrawingBuffer
mapStyle={props.mapStyle || 'light'}
mapboxApiAccessToken={props.mapboxApiAccessToken}
/>
</DeckGL>
{children}
</div>
@@ -48,30 +48,6 @@ 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,
@@ -419,11 +395,17 @@ export const mapboxStyle = {
renderTrigger: true,
freeForm: true,
validators: [validateMapboxStylesUrl],
choices: getDeckGLTiles(),
default: getDeckGLTiles()[0][0],
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',
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,17 +26,11 @@ 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;
@@ -221,42 +215,3 @@ 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);
}
@@ -359,6 +359,22 @@ const config: ControlPanelConfig = {
[xAxisLabelRotation],
[xAxisLabelInterval],
...richTooltipSection,
[
{
name: 'show_query_identifiers',
config: {
type: 'CheckboxControl',
label: t('Show query identifiers'),
description: t(
'Adds Query A and Query B identifiers to help differentiate series',
),
default: false,
renderTrigger: true,
visibility: ({ controls }) =>
Boolean(controls?.rich_tooltip?.value),
},
},
],
// eslint-disable-next-line react/jsx-key
[<ControlSubSectionHeader>{t('Y Axis')}</ControlSubSectionHeader>],
[
@@ -212,6 +212,7 @@ export default function transformProps(
sortSeriesAscendingB,
timeGrainSqla,
percentageThreshold,
show_query_identifiers = false,
metrics = [],
metricsB = [],
}: EchartsMixedTimeseriesFormData = { ...DEFAULT_FORM_DATA, ...formData };
@@ -395,10 +396,19 @@ export default function transformProps(
const seriesName = inverted[entryName] || entryName;
const colorScaleKey = getOriginalSeries(seriesName, array);
let displayName = `${entryName} (Query A)`;
let displayName: string;
if (groupby.length > 0) {
displayName = `${MetricDisplayNameA} (Query A), ${entryName}`;
// When we have groupby, format as "metric, dimension"
const metricPart = show_query_identifiers
? `${MetricDisplayNameA} (Query A)`
: MetricDisplayNameA;
displayName = `${metricPart}, ${entryName}`;
} else {
// When no groupby, format as just the entry name with optional query identifier
displayName = show_query_identifiers
? `${entryName} (Query A)`
: entryName;
}
const seriesFormatter = getFormatter(
@@ -453,10 +463,19 @@ export default function transformProps(
const seriesName = `${seriesEntry} (1)`;
const colorScaleKey = getOriginalSeries(seriesEntry, array);
let displayName = `${entryName} (Query B)`;
let displayName: string;
if (groupbyB.length > 0) {
displayName = `${MetricDisplayNameB} (Query B), ${entryName}`;
// When we have groupby, format as "metric, dimension"
const metricPart = show_query_identifiers
? `${MetricDisplayNameB} (Query B)`
: MetricDisplayNameB;
displayName = `${metricPart}, ${entryName}`;
} else {
// When no groupby, format as just the entry name with optional query identifier
displayName = show_query_identifiers
? `${entryName} (Query B)`
: entryName;
}
const seriesFormatter = getFormatter(
@@ -60,6 +60,7 @@ export type EchartsMixedTimeseriesFormData = QueryFormData & {
tooltipTimeFormat?: string;
zoomable: boolean;
richTooltip: boolean;
show_query_identifiers?: boolean;
xAxisLabelRotation: number;
xAxisLabelInterval?: number | string;
colorScheme?: string;
@@ -133,6 +134,7 @@ export const DEFAULT_FORM_DATA: EchartsMixedTimeseriesFormData = {
groupbyB: [],
zoomable: TIMESERIES_DEFAULTS.zoomable,
richTooltip: TIMESERIES_DEFAULTS.richTooltip,
show_query_identifiers: false,
xAxisLabelRotation: TIMESERIES_DEFAULTS.xAxisLabelRotation,
xAxisLabelInterval: TIMESERIES_DEFAULTS.xAxisLabelInterval,
...DEFAULT_TITLE_FORM_DATA,
@@ -28,7 +28,7 @@ import {
EchartsMixedTimeseriesProps,
} from '../../src/MixedTimeseries/types';
const formData: EchartsMixedTimeseriesFormData = {
const baseFormData: EchartsMixedTimeseriesFormData = {
annotationLayers: [],
area: false,
areaB: false,
@@ -81,6 +81,7 @@ const formData: EchartsMixedTimeseriesFormData = {
forecastPeriods: [],
forecastInterval: 0,
forecastSeasonalityDaily: 0,
show_query_identifiers: false,
};
const queriesData = [
@@ -108,57 +109,118 @@ const queriesData = [
},
];
const chartPropsConfig = {
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
};
describe('MixedTimeseries transformProps', () => {
it('should transform chart props for viz with query identifiers disabled', () => {
const formData = { ...baseFormData, show_query_identifiers: false };
const chartPropsConfig = {
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
};
const chartProps = new ChartProps({ ...chartPropsConfig, formData });
const transformed = transformProps(
chartProps as EchartsMixedTimeseriesProps,
);
it('should transform chart props for viz', () => {
const chartProps = new ChartProps(chartPropsConfig);
const transformed = transformProps(chartProps as EchartsMixedTimeseriesProps);
expect(transformed).toEqual(
expect.objectContaining({
echartOptions: expect.objectContaining({
series: expect.arrayContaining([
expect.objectContaining({
data: [
[599616000000, 1],
[599916000000, 3],
],
id: 'sum__num (Query A), boy',
stack: 'obs\na',
}),
expect.objectContaining({
data: [
[599616000000, 2],
[599916000000, 4],
],
id: 'sum__num (Query A), girl',
stack: 'obs\na',
}),
// Query B — Bar series
expect.objectContaining({
data: [
[599616000000, 1],
[599916000000, 3],
],
id: 'sum__num (Query B), boy',
stack: 'obs\nb',
}),
expect.objectContaining({
data: [
[599616000000, 2],
[599916000000, 4],
],
id: 'sum__num (Query B), girl',
stack: 'obs\nb',
}),
]),
expect(transformed).toEqual(
expect.objectContaining({
echartOptions: expect.objectContaining({
series: expect.arrayContaining([
expect.objectContaining({
data: [
[599616000000, 1],
[599916000000, 3],
],
id: 'sum__num, boy',
stack: 'obs\na',
}),
expect.objectContaining({
data: [
[599616000000, 2],
[599916000000, 4],
],
id: 'sum__num, girl',
stack: 'obs\na',
}),
// Query B — Bar series
expect.objectContaining({
data: [
[599616000000, 1],
[599916000000, 3],
],
id: 'sum__num, boy',
stack: 'obs\nb',
}),
expect.objectContaining({
data: [
[599616000000, 2],
[599916000000, 4],
],
id: 'sum__num, girl',
stack: 'obs\nb',
}),
]),
}),
}),
}),
);
);
});
it('should transform chart props for viz with query identifiers enabled', () => {
const formData = { ...baseFormData, show_query_identifiers: true };
const chartPropsConfig = {
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
};
const chartProps = new ChartProps({ ...chartPropsConfig, formData });
const transformed = transformProps(
chartProps as EchartsMixedTimeseriesProps,
);
expect(transformed).toEqual(
expect.objectContaining({
echartOptions: expect.objectContaining({
series: expect.arrayContaining([
expect.objectContaining({
data: [
[599616000000, 1],
[599916000000, 3],
],
id: 'sum__num (Query A), boy',
stack: 'obs\na',
}),
expect.objectContaining({
data: [
[599616000000, 2],
[599916000000, 4],
],
id: 'sum__num (Query A), girl',
stack: 'obs\na',
}),
// Query B — Bar series
expect.objectContaining({
data: [
[599616000000, 1],
[599916000000, 3],
],
id: 'sum__num (Query B), boy',
stack: 'obs\nb',
}),
expect.objectContaining({
data: [
[599616000000, 2],
[599916000000, 4],
],
id: 'sum__num (Query B), girl',
stack: 'obs\nb',
}),
]),
}),
}),
);
});
});
@@ -54,8 +54,7 @@ export function ErrorMessageWithStackTrace({
// Check if a custom error message component was registered for this message
if (error) {
const ErrorMessageComponent = getErrorMessageComponentRegistry().get(
// @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,
error.error_type,
);
if (ErrorMessageComponent) {
return (
@@ -362,7 +362,7 @@ export const ImportModal: FunctionComponent<ImportModelsModalProps> = ({
onHandledPrimaryAction={onUpload}
onHide={hide}
primaryButtonName={needsOverwriteConfirm ? t('Overwrite') : t('Import')}
primaryButtonStyle={needsOverwriteConfirm ? 'danger' : 'primary'}
primaryButtonType={needsOverwriteConfirm ? 'danger' : 'primary'}
width="750px"
show={show}
title={<h4>{t('Import %s', resourceLabel)}</h4>}
@@ -39,10 +39,3 @@ export interface TagType {
css?: SerializedStyles;
closable?: boolean;
}
export enum TagTypeEnum {
Custom = 1,
Type = 2,
Owner = 3,
FavoritedBy = 4,
}
@@ -53,7 +53,6 @@ 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';
@@ -416,9 +415,7 @@ const Header = () => {
owners: dashboardInfo.owners,
roles: dashboardInfo.roles,
slug,
tags: (dashboardInfo.tags || []).filter(
item => item.type === TagTypeEnum.Custom || !item.type,
),
tags: dashboardInfo.tags,
metadata: {
...dashboardInfo?.metadata,
color_namespace: currentColorNamespace,
@@ -463,7 +460,6 @@ const Header = () => {
dashboardInfo.metadata,
dashboardInfo.owners,
dashboardInfo.roles,
dashboardInfo.tags,
dashboardTitle,
layout,
refreshFrequency,
@@ -59,7 +59,6 @@ type SliceHeaderProps = SliceHeaderControlsProps & {
formData: object;
width: number;
height: number;
exportPivotExcel?: (arg0: string) => void;
};
const annotationsLoading = t('Annotation layers are still loading.');
@@ -168,7 +167,6 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
formData,
width,
height,
exportPivotExcel = () => ({}),
},
ref,
) => {
@@ -346,7 +344,6 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
formData={formData}
exploreUrl={exploreUrl}
crossFiltersEnabled={isCrossFiltersEnabled}
exportPivotExcel={exportPivotExcel}
/>
)}
</>
@@ -33,7 +33,6 @@ 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(),
@@ -255,20 +254,6 @@ 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,7 +128,6 @@ 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;
@@ -256,10 +255,6 @@ const SliceHeaderControls = (
});
break;
}
case MenuKeys.ExportPivotXlsx: {
props.exportPivotExcel?.('.pvtTable', props.slice.slice_name);
break;
}
case MenuKeys.CrossFilterScoping: {
openScopingModal();
break;
@@ -473,15 +468,6 @@ 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,7 +37,6 @@ 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';
@@ -129,9 +128,6 @@ 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,
);
@@ -166,12 +162,6 @@ 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);
@@ -223,15 +213,11 @@ const Chart = props => {
const getHeaderHeight = useCallback(() => {
if (headerRef.current) {
const computedMarginBottom = getComputedStyle(
const computedStyle = getComputedStyle(
headerRef.current,
).getPropertyValue('margin-bottom');
const marginBottom = parseInt(computedMarginBottom, 10) || 0;
const computedHeight = getComputedStyle(
headerRef.current,
).getPropertyValue('height');
const height = parseInt(computedHeight, 10) || DEFAULT_HEADER_HEIGHT;
return height + marginBottom;
const marginBottom = parseInt(computedStyle, 10) || 0;
return headerRef.current.offsetHeight + marginBottom;
}
return DEFAULT_HEADER_HEIGHT;
}, [headerRef]);
@@ -258,9 +244,9 @@ const Chart = props => {
const logExploreChart = useCallback(() => {
boundActionCreators.logEvent(LOG_ACTIONS_EXPLORE_DASHBOARD_CHART, {
slice_id: slice.slice_id,
is_cached: isCached,
is_cached: props.isCached,
});
}, [boundActionCreators.logEvent, slice.slice_id, isCached]);
}, [boundActionCreators.logEvent, slice.slice_id, props.isCached]);
const chartConfiguration = useSelector(
state => state.dashboardInfo.metadata?.chart_configuration,
@@ -374,22 +360,22 @@ const Chart = props => {
: LOG_ACTIONS_EXPORT_XLSX_DASHBOARD_CHART;
boundActionCreators.logEvent(logAction, {
slice_id: slice.slice_id,
is_cached: isCached,
is_cached: props.isCached,
});
exportChart({
formData: isFullCSV ? { ...formData, row_limit: maxRows } : formData,
resultType: isPivot ? 'post_processed' : 'full',
resultFormat: format,
force: true,
ownState: dataMask[props.id]?.ownState,
ownState: props.ownState,
});
},
[
slice.slice_id,
isCached,
props.isCached,
formData,
props.maxRows,
dataMask[props.id]?.ownState,
props.ownState,
boundActionCreators.logEvent,
],
);
@@ -417,7 +403,7 @@ const Chart = props => {
const forceRefresh = useCallback(() => {
boundActionCreators.logEvent(LOG_ACTIONS_FORCE_REFRESH_CHART, {
slice_id: slice.slice_id,
is_cached: isCached,
is_cached: props.isCached,
});
return boundActionCreators.refreshChart(chart.id, true, props.dashboardId);
}, [
@@ -425,7 +411,7 @@ const Chart = props => {
chart.id,
props.dashboardId,
slice.slice_id,
isCached,
props.isCached,
boundActionCreators.logEvent,
]);
@@ -433,7 +419,11 @@ 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) || [];
@@ -481,7 +471,6 @@ const Chart = props => {
formData={formData}
width={width}
height={getHeaderHeight()}
exportPivotExcel={exportPivotExcel}
/>
{/*
@@ -27,7 +27,6 @@ export default function DownloadAsImage({
text,
logEvent,
dashboardTitle,
...props
}: {
text: string;
dashboardTitle: string;
@@ -51,7 +50,6 @@ export default function DownloadAsImage({
onClick={e => {
onDownloadImage(e.domEvent);
}}
{...props}
>
{text}
</Menu.Item>
@@ -27,7 +27,6 @@ export default function DownloadAsPdf({
text,
logEvent,
dashboardTitle,
...props
}: {
text: string;
dashboardTitle: string;
@@ -51,7 +50,6 @@ 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.colorTextSecondary};
color: ${theme.colors.grayscale.base};
margin-left: 0;
&:hover {
color: ${theme.colorPrimaryText};
@@ -54,7 +54,7 @@ const containerStyle = (theme: SupersetTheme) => css`
&[disabled],
&[disabled]:hover {
color: ${theme.colorTextDisabled};
color: ${theme.colors.grayscale.light1};
}
}
`;
@@ -62,6 +62,7 @@ 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;
@@ -73,10 +74,14 @@ const verticalStyle = (theme: SupersetTheme, width: number) => css`
padding-top: ${theme.sizeUnit * 6}px;
background: linear-gradient(
${rgba(theme.colorBgLayout, 0)},
${theme.colorBgElevated} 20%
${rgba(theme.colors.grayscale.light5, 0)},
${theme.colors.grayscale.light5} 60%
);
& > button {
pointer-events: auto;
}
& > .filter-apply-button {
margin-bottom: ${theme.sizeUnit * 3}px;
}
@@ -89,6 +94,13 @@ 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 }>`
-1
View File
@@ -289,5 +289,4 @@ export enum MenuKeys {
ToggleFullscreen = 'toggle_fullscreen',
ManageEmbedded = 'manage_embedded',
ManageEmailReports = 'manage_email_reports',
ExportPivotXlsx = 'export_pivot_xlsx',
}
@@ -28,7 +28,6 @@ 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';
@@ -95,7 +94,7 @@ const SectionHeaderTextContainer = styled.div`
width: 100%;
`;
const SectionHeader = styled(Typography.Text)`
const SectionHeader = styled.span`
${({ theme }) => css`
font-size: ${theme.fontSize}px;
font-weight: ${theme.fontWeightStrong};
@@ -46,7 +46,6 @@ 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 = {
@@ -126,7 +125,7 @@ function PropertiesModal({
);
if (isFeatureEnabled(FeatureFlag.TaggingSystem)) {
const customTags = chart.tags?.filter(
(tag: TagType) => tag.type === TagTypeEnum.Custom,
(tag: TagType) => tag.type === 1,
);
setTags(customTags);
}
@@ -95,7 +95,6 @@ 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;
@@ -455,14 +454,16 @@ class DatasourceControl extends PureComponent {
{isMissingDatasource && !isMissingParams && (
<div className="error-alert">
{extra?.error ? (
<ErrorMessageWithStackTrace
title={extra.error.statusText || extra.error.message}
subtitle={
extra.error.statusText ? extra.error.message : undefined
}
error={extra.error}
source="explore"
/>
<div className="error-alert">
<ErrorMessageWithStackTrace
title={extra.error.statusText || extra.error.message}
subtitle={
extra.error.statusText ? extra.error.message : undefined
}
error={extra.error}
source="explore"
/>
</div>
) : (
<ErrorAlert
type="warning"
@@ -43,7 +43,6 @@ 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';
@@ -68,7 +67,6 @@ 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];
@@ -250,16 +248,6 @@ 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',
@@ -377,13 +365,6 @@ 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}>
@@ -191,32 +191,4 @@ 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, useState, useEffect } from 'react';
import { ChangeEvent, EventHandler } from 'react';
import cx from 'classnames';
import {
t,
@@ -88,21 +88,12 @@ 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',
@@ -102,9 +102,9 @@ const getCommonElements = () => ({
cancelButton: screen.getByRole('button', { name: 'Cancel' }),
uploadButton: screen.getByRole('button', { name: 'Upload' }),
selectButton: screen.getByRole('button', { name: 'Select' }),
panel1: screen.getByText(/General information/i, { selector: 'strong' }),
panel2: screen.getByText(/file settings/i, { selector: 'strong' }),
panel3: screen.getByText(/columns/i, { selector: 'strong' }),
panel1: screen.getByRole('heading', { name: /General information/i }),
panel2: screen.getByRole('heading', { name: /file settings/i }),
panel3: screen.getByRole('heading', { name: /columns/i }),
selectDatabase: screen.getByRole('combobox', { name: /select a database/i }),
inputTableName: screen.getByRole('textbox', { name: /table name/i }),
inputSchema: screen.getByRole('combobox', { name: /schema/i }),
@@ -130,7 +130,7 @@ describe('UploadDataModal - General Information Elements', () => {
const common = getCommonElements();
const title = screen.getByRole('heading', { name: /csv upload/i });
const panel4 = screen.getByText(/rows/i);
const panel4 = screen.getByRole('heading', { name: /rows/i });
const selectDelimiter = screen.getByRole('combobox', {
name: /choose a delimiter/i,
});
@@ -156,7 +156,7 @@ describe('UploadDataModal - General Information Elements', () => {
const common = getCommonElements();
const title = screen.getByRole('heading', { name: /excel upload/i });
const panel4 = screen.getByText(/rows/i);
const panel4 = screen.getByRole('heading', { name: /rows/i });
const selectSheetName = screen.getByRole('combobox', {
name: /choose sheet name/i,
});
@@ -177,7 +177,9 @@ describe('UploadDataModal - General Information Elements', () => {
]);
// Check elements that should NOT be visible
expect(screen.queryByText(/csv upload/i)).not.toBeInTheDocument();
expect(
screen.queryByRole('heading', { name: /csv upload/i }),
).not.toBeInTheDocument();
expect(
screen.queryByRole('combobox', { name: /choose a delimiter/i }),
).not.toBeInTheDocument();
@@ -204,8 +206,8 @@ describe('UploadDataModal - General Information Elements', () => {
// Check elements that should NOT be visible
expectElementsNotVisible([
screen.queryByText(/csv upload/i),
screen.queryByText(/rows/i),
screen.queryByRole('heading', { name: /csv upload/i }),
screen.queryByRole('heading', { name: /rows/i }),
screen.queryByRole('combobox', { name: /choose a delimiter/i }),
screen.queryByRole('combobox', { name: /choose sheet name/i }),
]);
@@ -214,7 +216,7 @@ describe('UploadDataModal - General Information Elements', () => {
describe('UploadDataModal - File Settings Elements', () => {
const openFileSettings = async () => {
const panelHeader = screen.getByText(/file settings/i);
const panelHeader = screen.getByRole('heading', { name: /file settings/i });
await userEvent.click(panelHeader);
};
@@ -292,7 +294,7 @@ describe('UploadDataModal - File Settings Elements', () => {
describe('UploadDataModal - Columns Elements', () => {
const openColumns = async () => {
const panelHeader = screen.getByText(/columns/i, { selector: 'strong' });
const panelHeader = screen.getByRole('heading', { name: /columns/i });
await userEvent.click(panelHeader);
};
@@ -363,7 +365,7 @@ describe('UploadDataModal - Rows Elements', () => {
test('CSV/Excel rows render correctly', async () => {
render(<UploadDataModal {...csvProps} />, { useRedux: true });
const panelHeader = screen.getByText(/rows/i);
const panelHeader = screen.getByRole('heading', { name: /rows/i });
await userEvent.click(panelHeader);
const elements = [
@@ -378,7 +380,7 @@ describe('UploadDataModal - Rows Elements', () => {
test('Columnar does not render rows', () => {
render(<UploadDataModal {...columnarProps} />, { useRedux: true });
const panelHeader = screen.queryByText(/rows/i);
const panelHeader = screen.queryByRole('heading', { name: /rows/i });
expect(panelHeader).not.toBeInTheDocument();
});
});
@@ -606,11 +608,11 @@ describe('UploadDataModal Collapse Tabs', () => {
useRedux: true,
});
const generalInfoTab = screen.getByRole('tab', {
name: /expanded General information/i,
name: /expanded General information Upload a file to a database./i,
});
expect(generalInfoTab).toHaveAttribute('aria-expanded', 'true');
const fileSettingsTab = screen.getByRole('tab', {
name: /collapsed File settings/i,
name: /collapsed File settings Adjust how spaces, blank lines, null values are handled and other file wide settings./i,
});
userEvent.click(fileSettingsTab);
expect(fileSettingsTab).toHaveAttribute('aria-expanded', 'true');
@@ -624,11 +626,11 @@ describe('UploadDataModal Collapse Tabs', () => {
useRedux: true,
});
const generalInfoTab = screen.getByRole('tab', {
name: /expanded General information/i,
name: /expanded General information Upload a file to a database./i,
});
expect(generalInfoTab).toHaveAttribute('aria-expanded', 'true');
const fileSettingsTab = screen.getByRole('tab', {
name: /collapsed File settings/i,
name: /collapsed File settings Adjust how spaces, blank lines, null values are handled and other file wide settings./i,
});
userEvent.click(fileSettingsTab);
expect(fileSettingsTab).toHaveAttribute('aria-expanded', 'true');
@@ -642,11 +644,11 @@ describe('UploadDataModal Collapse Tabs', () => {
useRedux: true,
});
const generalInfoTab = screen.getByRole('tab', {
name: /expanded General information/i,
name: /expanded General information Upload a file to a database./i,
});
expect(generalInfoTab).toHaveAttribute('aria-expanded', 'true');
const fileSettingsTab = screen.getByRole('tab', {
name: /collapsed File settings/i,
name: /collapsed File settings Adjust how spaces, blank lines, null values are handled and other file wide settings./i,
});
userEvent.click(fileSettingsTab);
expect(fileSettingsTab).toHaveAttribute('aria-expanded', 'true');
@@ -26,7 +26,6 @@ import {
} from 'react';
import {
css,
getClientErrorObject,
SupersetClient,
SupersetTheme,
@@ -46,7 +45,6 @@ import {
Upload,
type UploadChangeParam,
type UploadFile,
Typography,
} from '@superset-ui/core/components';
import { Switch, SwitchProps } from '@superset-ui/core/components/Switch';
import { Icons } from '@superset-ui/core/components/Icons';
@@ -578,17 +576,7 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
const UploadTitle: FC = () => {
const title = uploadTitles[type] || t('Upload');
return (
<Typography.Title
level={5}
css={css`
margin-top: 0;
margin-bottom: 0;
`}
>
{title}
</Typography.Title>
);
return <h4>{title}</h4>;
};
return (
@@ -604,7 +592,7 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
onHandledPrimaryAction={form.submit}
onHide={onClose}
width="500px"
primaryButtonName={t('Upload')}
primaryButtonName="Upload"
centered
show={show}
title={<UploadTitle />}
@@ -627,9 +615,10 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
{
key: 'general',
label: (
<Typography.Text strong>
{t('General information')}
</Typography.Text>
<div>
<h4>{t('General information')}</h4>
<p className="helper">{t('Upload a file to a database.')}</p>
</div>
),
children: (
<>
@@ -783,7 +772,14 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
{
key: 'file-settings',
label: (
<Typography.Text strong>{t('File settings')}</Typography.Text>
<div>
<h4>{t('File settings')}</h4>
<p className="helper">
{t(
'Adjust how spaces, blank lines, null values are handled and other file wide settings.',
)}
</p>
</div>
),
children: (
<>
@@ -905,7 +901,16 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
},
{
key: 'columns',
label: <Typography.Text strong>{t('Columns')}</Typography.Text>,
label: (
<div>
<h4>{t('Columns')}</h4>
<p className="helper">
{t(
'Adjust column settings such as specifying the columns to read, how duplicates are handled, column data types, and more.',
)}
</p>
</div>
),
children: (
<>
<Row>
@@ -1005,7 +1010,14 @@ const UploadDataModal: FunctionComponent<UploadDataModalProps> = ({
{
key: 'rows',
label: (
<Typography.Text strong>{t('Rows')}</Typography.Text>
<div>
<h4>{t('Rows')}</h4>
<p className="helper">
{t(
'Set header rows and the number of rows to read or skip.',
)}
</p>
</div>
),
children: (
<Row>
@@ -46,7 +46,7 @@ export const antDModalNoPaddingStyles = css`
export const formStyles = (theme: SupersetTheme) => css`
.switch-label {
color: ${theme.colorTextSecondary};
color: ${theme.colors.grayscale.base};
margin-left: ${theme.sizeUnit * 4}px;
}
`;
+1 -6
View File
@@ -19,7 +19,6 @@
import { JsonObject, SupersetClient } from '@superset-ui/core';
import rison from 'rison';
import { TagType } from 'src/components';
import { TagTypeEnum } from 'src/components/Tag/TagType';
export const OBJECT_TYPES_VALUES = Object.freeze([
'dashboard',
@@ -94,11 +93,7 @@ export function fetchTags(
endpoint: `/api/v1/${objectType}/${objectId}`,
})
.then(({ json }) =>
callback(
json.result.tags.filter(
(tag: TagType) => tag.type === TagTypeEnum.Custom,
),
),
callback(json.result.tags.filter((tag: TagType) => tag.type === 1)),
)
.catch(response => error(response));
}
@@ -71,7 +71,6 @@ import PropertiesModal from 'src/explore/components/PropertiesModal';
import Chart from 'src/types/Chart';
import { Icons } from '@superset-ui/core/components/Icons';
import { nativeFilterGate } from 'src/dashboard/components/nativeFilters/utils';
import { TagTypeEnum } from 'src/components/Tag/TagType';
import { loadTags } from 'src/components/Tag/utils';
import ChartCard from 'src/features/charts/ChartCard';
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
@@ -418,8 +417,7 @@ function ChartList(props: ChartListProps) {
<TagsList
tags={tags.filter((tag: TagType) =>
tag.type
? tag.type === TagTypeEnum.Custom ||
tag.type === 'TagTypes.custom'
? tag.type === 1 || tag.type === 'TagTypes.custom'
: true,
)}
maxTags={3}
@@ -67,7 +67,6 @@ import {
Dashboard as CRUDDashboard,
QueryObjectColumns,
} from 'src/views/CRUD/types';
import { TagTypeEnum } from 'src/components/Tag/TagType';
import { loadTags } from 'src/components/Tag/utils';
import DashboardCard from 'src/features/dashboards/DashboardCard';
import { DashboardStatus } from 'src/features/dashboards/types';
@@ -377,8 +376,7 @@ function DashboardList(props: DashboardListProps) {
<TagsList
tags={tags.filter(
(tag: TagType) =>
tag.type === 'TagTypes.custom' ||
tag.type === TagTypeEnum.Custom,
tag.type === 'TagTypes.custom' || tag.type === 1,
)}
maxTags={3}
/>
@@ -58,7 +58,6 @@ import handleResourceExport from 'src/utils/export';
import SubMenu, { ButtonProps, SubMenuProps } from 'src/features/home/SubMenu';
import { commonMenuData } from 'src/features/home/commonMenuData';
import { QueryObjectColumns, SavedQueryObject } from 'src/views/CRUD/types';
import { TagTypeEnum } from 'src/components/Tag/TagType';
import { loadTags } from 'src/components/Tag/utils';
import { Icons } from '@superset-ui/core/components/Icons';
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
@@ -394,11 +393,7 @@ function SavedQueryList({
},
}: any) => (
// Only show custom type tags
<TagsList
tags={tags.filter(
(tag: TagType) => tag.type === TagTypeEnum.Custom,
)}
/>
<TagsList tags={tags.filter((tag: TagType) => tag.type === 1)} />
),
Header: t('Tags'),
accessor: 'tags',
+36 -25
View File
@@ -101,14 +101,13 @@ export class ThemeController {
const {
storage = new LocalStorageAdapter(),
modeStorageKey = STORAGE_KEYS.THEME_MODE,
themeObject = supersetThemeObject,
themeObject: fallbackThemeObject = supersetThemeObject,
defaultTheme = (supersetThemeObject.theme as AnyThemeConfig) ?? {},
onChange = null,
} = options;
this.storage = storage;
this.modeStorageKey = modeStorageKey;
this.themeObject = themeObject;
// Initialize bootstrap data and themes
const {
@@ -140,14 +139,16 @@ export class ThemeController {
// Initialize theme and mode
this.currentMode = this.determineInitialMode();
const initialTheme =
this.getThemeForMode(this.currentMode) || this.defaultTheme;
const { theme, themeObject } =
this.createInitialThemeObject(fallbackThemeObject);
this.themeObject = themeObject;
// Setup change callback
if (onChange) this.onChangeCallbacks.add(onChange);
// Apply initial theme and persist mode
this.applyTheme(initialTheme);
this.applyTheme(theme);
this.persistMode();
}
@@ -157,12 +158,7 @@ export class ThemeController {
* Cleans up listeners and references. Should be called when the controller is no longer needed.
*/
public destroy(): void {
if (this.mediaQuery)
this.mediaQuery.removeEventListener(
'change',
this.handleSystemThemeChange,
);
this.mediaQuery.removeEventListener('change', this.handleSystemThemeChange);
this.onChangeCallbacks.clear();
}
@@ -333,12 +329,8 @@ export class ThemeController {
* Initializes media query listeners if OS preference is allowed
*/
private initializeMediaQueryListener(): void {
try {
this.mediaQuery = window.matchMedia(MEDIA_QUERY_DARK_SCHEME);
this.mediaQuery.addEventListener('change', this.handleSystemThemeChange);
} catch (error) {
console.warn('Failed to initialize media query listener:', error);
}
this.mediaQuery = window.matchMedia(MEDIA_QUERY_DARK_SCHEME);
this.mediaQuery.addEventListener('change', this.handleSystemThemeChange);
}
/**
@@ -355,9 +347,9 @@ export class ThemeController {
settings: themeSettings,
} = theme;
const hasValidDefault: boolean = this.isNonEmptyObject(defaultTheme);
const hasValidDark: boolean = this.isNonEmptyObject(darkTheme);
const hasValidSettings: boolean = this.isNonEmptyObject(themeSettings);
const hasValidDefault: boolean = this.hasKeys(defaultTheme);
const hasValidDark: boolean = this.hasKeys(darkTheme);
const hasValidSettings: boolean = this.hasKeys(themeSettings);
return {
bootstrapDefaultTheme: hasValidDefault ? defaultTheme : null,
@@ -368,11 +360,9 @@ export class ThemeController {
}
/**
* Checks if an object is non-empty (has at least one property).
* Checks if an object has keys (not empty).
*/
private isNonEmptyObject(
obj: Record<string, any> | undefined | null,
): boolean {
private hasKeys(obj: Record<string, any> | undefined | null): boolean {
return Boolean(
obj && typeof obj === 'object' && Object.keys(obj).length > 0,
);
@@ -427,7 +417,28 @@ export class ThemeController {
? this.darkTheme || this.defaultTheme
: this.defaultTheme;
return selectedTheme;
return normalizeThemeConfig(selectedTheme);
}
/**
* Creates the initial theme object.
* This sets the theme based on the current mode and ensures it has the correct algorithm.
* @param defaultThemeObject - The fallback theme object to use if no theme is set
* @returns An object containing the theme and the themeObject
*/
private createInitialThemeObject(defaultThemeObject: Theme): {
theme: AnyThemeConfig;
themeObject: Theme;
} {
let theme: AnyThemeConfig | null = this.getThemeForMode(this.currentMode);
theme = theme || (defaultThemeObject.theme as AnyThemeConfig);
const normalizedTheme = this.normalizeTheme(theme);
return {
theme: normalizedTheme,
themeObject: Theme.fromConfig(normalizedTheme),
};
}
/**
@@ -230,13 +230,13 @@ describe('ThemeController', () => {
expect(controller.getTheme()).toBe(mockThemeObject);
});
it('should use BootstrapData themes when available', () => {
it('should use BootsrapData themes when available', () => {
controller = new ThemeController({
themeObject: mockThemeObject,
});
expect(mockSetConfig).toHaveBeenCalledTimes(1);
expect(mockSetConfig).toHaveBeenCalledWith(
expect(mockThemeFromConfig).toHaveBeenCalledTimes(1);
expect(mockThemeFromConfig).toHaveBeenCalledWith(
expect.objectContaining({
token: expect.objectContaining({
colorBgBase: '#ededed',
@@ -246,7 +246,7 @@ describe('ThemeController', () => {
);
});
it('should fallback to Superset default theme when BootstrapData themes are empty', () => {
it('should fallback to Superset default theme when BootsrapData themes are empty', () => {
mockGetBootstrapData.mockReturnValue(
createMockBootstrapData({
default: {},
@@ -267,8 +267,8 @@ describe('ThemeController', () => {
defaultTheme: fallbackTheme,
});
expect(mockSetConfig).toHaveBeenCalledTimes(1);
expect(mockSetConfig).toHaveBeenCalledWith(
expect(mockThemeFromConfig).toHaveBeenCalledTimes(1);
expect(mockThemeFromConfig).toHaveBeenCalledWith(
expect.objectContaining({
...fallbackTheme,
algorithm: antdThemeImport.defaultAlgorithm,
-7
View File
@@ -319,13 +319,6 @@ const config = {
'./node_modules/@storybook/react-dom-shim/dist/react-16',
),
),
// Workaround for react-color trying to import non-existent icon
'@icons/material/UnfoldMoreHorizontalIcon': path.resolve(
path.join(
APP_DIR,
'./node_modules/@icons/material/CubeUnfoldedIcon.js',
),
),
},
extensions: ['.ts', '.tsx', '.js', '.jsx', '.yml'],
fallback: {
+15 -15
View File
@@ -13,7 +13,7 @@
"express": "~5.1.0",
"http-errors": "~2.0.0",
"jsonwebtoken": "^9.0.2",
"morgan": "~1.10.1",
"morgan": "~1.10.0",
"pug": "~3.0.3"
}
},
@@ -863,15 +863,15 @@
}
},
"node_modules/morgan": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
"integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
"integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
"dependencies": {
"basic-auth": "~2.0.1",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-finished": "~2.3.0",
"on-headers": "~1.1.0"
"on-headers": "~1.0.2"
},
"engines": {
"node": ">= 0.8.0"
@@ -936,9 +936,9 @@
}
},
"node_modules/on-headers": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
"engines": {
"node": ">= 0.8"
}
@@ -2045,15 +2045,15 @@
}
},
"morgan": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
"integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
"integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
"requires": {
"basic-auth": "~2.0.1",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-finished": "~2.3.0",
"on-headers": "~1.1.0"
"on-headers": "~1.0.2"
},
"dependencies": {
"debug": {
@@ -2100,9 +2100,9 @@
}
},
"on-headers": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
},
"once": {
"version": "1.4.0",
@@ -11,7 +11,7 @@
"express": "~5.1.0",
"http-errors": "~2.0.0",
"jsonwebtoken": "^9.0.2",
"morgan": "~1.10.1",
"morgan": "~1.10.0",
"pug": "~3.0.3"
}
}
@@ -87,40 +87,40 @@ def cidr_translate_filter_func( # noqa: C901
if operator in (FilterOperator.IN, FilterOperator.NOT_IN):
dict_items = [val for val in values if isinstance(val, dict)]
single_values = [val for val in values if not isinstance(val, dict)]
if operator == FilterOperator.IN:
if operator == FilterOperator.IN.value:
cond = col.in_(single_values)
for dictionary in dict_items:
cond = cond | (col <= dictionary["end"]) & (col >= dictionary["start"])
elif operator == FilterOperator.NOT_IN:
elif operator == FilterOperator.NOT_IN.value:
cond = ~(col.in_(single_values))
for dictionary in dict_items:
cond = cond & (col > dictionary["end"]) & (col < dictionary["start"])
return_expression = cond
if len(values) == 1:
value = values[0]
if operator == FilterOperator.EQUALS:
if operator == FilterOperator.EQUALS.value:
return_expression = (
col == value
if not isinstance(value, dict)
else (col <= value["end"]) & (col >= value["start"])
)
if operator == FilterOperator.GREATER_THAN_OR_EQUALS:
if operator == FilterOperator.GREATER_THAN_OR_EQUALS.value:
return_expression = (
col >= value if not isinstance(value, dict) else col >= value["end"]
)
if operator == FilterOperator.GREATER_THAN:
if operator == FilterOperator.GREATER_THAN.value:
return_expression = (
col > value if not isinstance(value, dict) else col > value["end"]
)
if operator == FilterOperator.LESS_THAN:
if operator == FilterOperator.LESS_THAN.value:
return_expression = (
col < value if not isinstance(value, dict) else col < value["start"]
)
if operator == FilterOperator.LESS_THAN_OR_EQUALS:
if operator == FilterOperator.LESS_THAN_OR_EQUALS.value:
return_expression = (
col <= value if not isinstance(value, dict) else col <= value["start"]
)
if operator == FilterOperator.NOT_EQUALS:
if operator == FilterOperator.NOT_EQUALS.value:
return_expression = (
col != value
if not isinstance(value, dict)
@@ -114,25 +114,25 @@ def port_translate_filter_func( # noqa: C901
return_expression: Any
if operator in (FilterOperator.IN, FilterOperator.NOT_IN):
vals_list = itertools.chain.from_iterable(values)
if operator == FilterOperator.IN:
if operator == FilterOperator.IN.value:
cond = col.in_(vals_list)
elif operator == FilterOperator.NOT_IN:
elif operator == FilterOperator.NOT_IN.value:
cond = ~(col.in_(vals_list))
return_expression = cond
if len(values) == 1:
value = values[0]
value.sort()
if operator == FilterOperator.EQUALS:
if operator == FilterOperator.EQUALS.value:
return_expression = col.in_(value)
if operator == FilterOperator.GREATER_THAN_OR_EQUALS:
if operator == FilterOperator.GREATER_THAN_OR_EQUALS.value:
return_expression = col >= value[0]
if operator == FilterOperator.GREATER_THAN:
if operator == FilterOperator.GREATER_THAN.value:
return_expression = col > value[0]
if operator == FilterOperator.LESS_THAN:
if operator == FilterOperator.LESS_THAN.value:
return_expression = col < value[-1]
if operator == FilterOperator.LESS_THAN_OR_EQUALS:
if operator == FilterOperator.LESS_THAN_OR_EQUALS.value:
return_expression = col <= value[-1]
if operator == FilterOperator.NOT_EQUALS:
if operator == FilterOperator.NOT_EQUALS.value:
return_expression = ~col.in_(value)
return return_expression
+3 -1
View File
@@ -541,7 +541,9 @@ class QueryContextProcessor:
# Lets find the first temporal filter in the filters array and change
# its val to be the result of get_since_until with the offset
for flt in query_object_clone.filter:
if flt.get("op") == FilterOperator.TEMPORAL_RANGE and isinstance(
if flt.get(
"op"
) == FilterOperator.TEMPORAL_RANGE.value and isinstance(
flt.get("val"), str
):
time_range = cast(str, flt.get("val"))
+1 -1
View File
@@ -66,7 +66,7 @@ def get_since_until_from_query_object(
time_range = None
for flt in query_object.filter:
if flt.get("op") == FilterOperator.TEMPORAL_RANGE and isinstance(
if flt.get("op") == FilterOperator.TEMPORAL_RANGE.value and isinstance(
flt.get("val"), str
):
time_range = cast(str, flt.get("val"))
+4 -35
View File
@@ -422,28 +422,6 @@ class D3Format(TypedDict, total=False):
D3_FORMAT: D3Format = {}
# Override the default mapbox tiles
# Default values are equivalent to
# 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'],
# ]
# for adding your own map tiles, you can use the following format:
# - tile:// + your_personal_url or openstreetmap_url
# example:
# DECKGL_BASE_MAP = [
# ['tile://https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', 'OpenStreetMap']
# ]
# Enable CORS and set map url in origins option.
# Add also map url in connect-src of TALISMAN_CONFIG variable
DECKGL_BASE_MAP: list[list[str, str]] = None
# Override the default d3 locale for time format
# Default values are equivalent to
@@ -598,8 +576,8 @@ DEFAULT_FEATURE_FLAGS: dict[str, bool] = {
# This is intended to use for theme creation, visual review and theming-debugging
# purposes.
"THEME_ALLOW_THEME_EDITOR_BETA": False,
# Allow users to optionally specify date formats in email subjects, which
# will be parsed if enabled
# Allow users to optionally specify date formats in email subjects, which will
# be parsed if enabled
"DATE_FORMAT_IN_EMAIL_SUBJECT": False,
# Allow metrics and columns to be grouped into (potentially nested) folders in the
# chart builder
@@ -899,13 +877,8 @@ STORE_CACHE_KEYS_IN_METADATA_DB = False
# CORS Options
# NOTE: enabling this requires installing the cors-related python dependencies
# `pip install .[cors]` or `pip install apache_superset[cors]`, depending
ENABLE_CORS = True
CORS_OPTIONS: dict[Any, Any] = {
"origins": [
"https://tile.openstreetmap.org",
"https://tile.osm.ch",
]
}
ENABLE_CORS = False
CORS_OPTIONS: dict[Any, Any] = {}
# Sanitizes the HTML content used in markdowns to allow its rendering in a safe manner.
# Disabling this option is not recommended for security reasons. If you wish to allow
@@ -1734,8 +1707,6 @@ TALISMAN_CONFIG = {
"'self'",
"https://api.mapbox.com",
"https://events.mapbox.com",
"https://tile.openstreetmap.org",
"https://tile.osm.ch",
],
"object-src": "'none'",
"style-src": [
@@ -1768,8 +1739,6 @@ TALISMAN_DEV_CONFIG = {
"'self'",
"https://api.mapbox.com",
"https://events.mapbox.com",
"https://tile.openstreetmap.org",
"https://tile.osm.ch",
],
"object-src": "'none'",
"style-src": [
+1 -77
View File
@@ -54,7 +54,7 @@ from sqlalchemy.engine.reflection import Inspector
from sqlalchemy.engine.url import URL
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql import literal_column, quoted_name, text
from sqlalchemy.sql.expression import BinaryExpression, ColumnClause, Select, TextClause
from sqlalchemy.sql.expression import ColumnClause, Select, TextClause
from sqlalchemy.types import TypeEngine
from superset import db
@@ -377,10 +377,6 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
disallow_uri_query_params: dict[str, set[str]] = {}
# A Dict of query parameters that will always be used on every connection
# by driver name
# Whether to use equality operators (= true/false) instead of IS operators
# for boolean filters. Some databases like Snowflake don't support IS true/false
use_equality_for_boolean_filters = False
enforce_uri_query_params: dict[str, dict[str, Any]] = {}
force_column_alias_quotes = False
@@ -1206,78 +1202,6 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
"""
return None
@classmethod
def handle_boolean_filter(
cls, sqla_col: Any, op: str, value: bool
) -> BinaryExpression:
"""
Handle boolean filter operations with engine-specific logic.
By default, uses SQLAlchemy's IS operator (column IS true/false).
Engines that don't support IS for boolean values can override
use_equality_for_boolean_filters to use equality operators instead.
:param sqla_col: SQLAlchemy column element
:param op: Filter operator (IS_TRUE or IS_FALSE)
:param value: Boolean value (True or False)
:return: SQLAlchemy expression for the boolean filter
"""
if cls.use_equality_for_boolean_filters:
return sqla_col == value
else:
return sqla_col.is_(value)
@classmethod
def handle_null_filter(
cls,
sqla_col: Any,
op: utils.FilterOperator,
) -> BinaryExpression:
"""
Handle null/not null filter operations.
:param sqla_col: SQLAlchemy column element
:param op: Filter operator (IS_NULL or IS_NOT_NULL)
:return: SQLAlchemy expression for the null filter
"""
from superset.utils import core as utils
if op == utils.FilterOperator.IS_NULL:
return sqla_col.is_(None)
elif op == utils.FilterOperator.IS_NOT_NULL:
return sqla_col.isnot(None)
else:
raise ValueError(f"Invalid null filter operator: {op}")
@classmethod
def handle_comparison_filter(
cls, sqla_col: Any, op: utils.FilterOperator, value: Any
) -> BinaryExpression:
"""
Handle comparison filter operations (=, !=, >, <, >=, <=).
:param sqla_col: SQLAlchemy column element
:param op: Filter operator
:param value: Filter value
:return: SQLAlchemy expression for the comparison filter
"""
from superset.utils import core as utils
if op == utils.FilterOperator.EQUALS:
return sqla_col == value
elif op == utils.FilterOperator.NOT_EQUALS:
return sqla_col != value
elif op == utils.FilterOperator.GREATER_THAN:
return sqla_col > value
elif op == utils.FilterOperator.LESS_THAN:
return sqla_col < value
elif op == utils.FilterOperator.GREATER_THAN_OR_EQUALS:
return sqla_col >= value
elif op == utils.FilterOperator.LESS_THAN_OR_EQUALS:
return sqla_col <= value
else:
raise ValueError(f"Invalid comparison filter operator: {op}")
@classmethod
def handle_cursor(cls, cursor: Any, query: Query) -> None:
"""Handle a live cursor between the execute and fetchall calls
-3
View File
@@ -83,9 +83,6 @@ class SnowflakeEngineSpec(PostgresBaseEngineSpec):
force_column_alias_quotes = True
max_column_name_length = 256
# Snowflake doesn't support IS true/false syntax, use = true/false instead
use_equality_for_boolean_filters = True
parameters_schema = SnowflakeParametersSchema()
default_driver = "snowflake"
sqlalchemy_uri_placeholder = "snowflake://"
+7 -7
View File
@@ -194,7 +194,7 @@ def load_deck_dash() -> None: # pylint: disable=too-many-statements
"datasource": "5__table",
"granularity_sqla": None,
"groupby": [],
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/light-v9",
"multiplier": 10,
"point_radius_fixed": {"type": "metric", "value": "count"},
"point_unit": "square_m",
@@ -229,7 +229,7 @@ def load_deck_dash() -> None: # pylint: disable=too-many-statements
"point_unit": "square_m",
"row_limit": 5000,
"spatial": {"type": "latlong", "lonCol": "LON", "latCol": "LAT"},
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/dark-v9",
"granularity_sqla": None,
"size": "count",
"viz_type": "deck_screengrid",
@@ -263,7 +263,7 @@ def load_deck_dash() -> None: # pylint: disable=too-many-statements
slice_data = {
"spatial": {"type": "latlong", "lonCol": "LON", "latCol": "LAT"},
"row_limit": 5000,
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/streets-v9",
"granularity_sqla": None,
"size": "count",
"viz_type": "deck_hex",
@@ -300,7 +300,7 @@ def load_deck_dash() -> None: # pylint: disable=too-many-statements
"autozoom": False,
"spatial": {"type": "latlong", "lonCol": "LON", "latCol": "LAT"},
"row_limit": 5000,
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/satellite-streets-v9",
"granularity_sqla": None,
"size": "count",
"viz_type": "deck_grid",
@@ -367,7 +367,7 @@ def load_deck_dash() -> None: # pylint: disable=too-many-statements
},
"line_type": "json",
"linear_color_scheme": "oranges",
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/light-v9",
"viewport": {
"longitude": -122.43388541747726,
"latitude": 37.752020331384834,
@@ -442,7 +442,7 @@ def load_deck_dash() -> None: # pylint: disable=too-many-statements
"lonCol": "LONGITUDE_DEST",
},
"row_limit": 5000,
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/light-v9",
"viewport": {
"altitude": 1.5,
"bearing": 8.546256357301871,
@@ -486,7 +486,7 @@ def load_deck_dash() -> None: # pylint: disable=too-many-statements
"line_column": "path_json",
"line_type": "json",
"row_limit": 5000,
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/light-v9",
"viewport": {
"longitude": -122.18885402582598,
"latitude": 37.73671752604488,
+3 -3
View File
@@ -110,15 +110,15 @@ def load_long_lat_data(only_metadata: bool = False, force: bool = False) -> None
"viz_type": "mapbox",
"all_columns_x": "LON",
"all_columns_y": "LAT",
"mapbox_style": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"mapbox_style": "mapbox://styles/mapbox/light-v9",
"all_columns": ["occupancy"],
"row_limit": 500000,
}
logger.debug("Creating a slice")
slc = Slice(
slice_name="OSM Long/Lat",
viz_type="osm",
slice_name="Mapbox Long/Lat",
viz_type="mapbox",
datasource_type=DatasourceType.TABLE,
datasource_id=tbl.id,
params=get_slice_json(slice_data),
+1 -1
View File
@@ -47,7 +47,7 @@ def load_misc_dashboard() -> None:
"meta": {
"chartId": 3969,
"height": 69,
"sliceName": "OSM Long/Lat",
"sliceName": "Mapbox Long/Lat",
"uuid": "164efe31-295b-4408-aaa6-2f4bfb58a212",
"width": 4
},
+4 -4
View File
@@ -409,8 +409,8 @@ class ExtraCache:
# IS_NULL and IS_NOT_NULL operators do not have a value
or op
in (
FilterOperator.IS_NULL,
FilterOperator.IS_NOT_NULL,
FilterOperator.IS_NULL.value,
FilterOperator.IS_NOT_NULL.value,
)
)
):
@@ -421,8 +421,8 @@ class ExtraCache:
self.applied_filters.append(column)
if op in (
FilterOperator.IN,
FilterOperator.NOT_IN,
FilterOperator.IN.value,
FilterOperator.NOT_IN.value,
) and not isinstance(val, list):
val = [val]
+31 -37
View File
@@ -1756,7 +1756,7 @@ class ExploreMixin: # pylint: disable=too-many-public-methods
flt_col = flt["col"]
val = flt.get("val")
flt_grain = flt.get("grain")
op = utils.FilterOperator(flt["op"].upper())
op = flt["op"].upper()
col_obj: Optional["TableColumn"] = None
sqla_col: Optional[Column] = None
if flt_col == utils.DTTM_ALIAS and is_timeseries and dttm_col:
@@ -1790,8 +1790,8 @@ class ExploreMixin: # pylint: disable=too-many-public-methods
col_type = col_obj.type if col_obj else None
col_spec = db_engine_spec.get_column_spec(native_type=col_type)
is_list_target = op in (
utils.FilterOperator.IN,
utils.FilterOperator.NOT_IN,
utils.FilterOperator.IN.value,
utils.FilterOperator.NOT_IN.value,
)
col_advanced_data_type = col_obj.advanced_data_type if col_obj else ""
@@ -1850,30 +1850,23 @@ class ExploreMixin: # pylint: disable=too-many-public-methods
cond = is_null_cond
else:
cond = sqla_col.in_(eq)
if op == utils.FilterOperator.NOT_IN:
if op == utils.FilterOperator.NOT_IN.value:
cond = ~cond
where_clause_and.append(cond)
elif op in {
utils.FilterOperator.IS_NULL,
utils.FilterOperator.IS_NOT_NULL,
}:
where_clause_and.append(
db_engine_spec.handle_null_filter(sqla_col, op)
)
elif op == utils.FilterOperator.IS_TRUE:
where_clause_and.append(
db_engine_spec.handle_boolean_filter(sqla_col, op, True)
)
elif op == utils.FilterOperator.IS_FALSE:
where_clause_and.append(
db_engine_spec.handle_boolean_filter(sqla_col, op, False)
)
elif op == utils.FilterOperator.IS_NULL.value:
where_clause_and.append(sqla_col.is_(None))
elif op == utils.FilterOperator.IS_NOT_NULL.value:
where_clause_and.append(sqla_col.isnot(None))
elif op == utils.FilterOperator.IS_TRUE.value:
where_clause_and.append(sqla_col.is_(True))
elif op == utils.FilterOperator.IS_FALSE.value:
where_clause_and.append(sqla_col.is_(False))
else:
if (
op
not in {
utils.FilterOperator.EQUALS,
utils.FilterOperator.NOT_EQUALS,
utils.FilterOperator.EQUALS.value,
utils.FilterOperator.NOT_EQUALS.value,
}
and eq is None
):
@@ -1883,35 +1876,36 @@ class ExploreMixin: # pylint: disable=too-many-public-methods
"with comparison operators"
)
)
if op in {
utils.FilterOperator.EQUALS,
utils.FilterOperator.NOT_EQUALS,
utils.FilterOperator.GREATER_THAN,
utils.FilterOperator.LESS_THAN,
utils.FilterOperator.GREATER_THAN_OR_EQUALS,
utils.FilterOperator.LESS_THAN_OR_EQUALS,
}:
where_clause_and.append(
db_engine_spec.handle_comparison_filter(sqla_col, op, eq)
)
if op == utils.FilterOperator.EQUALS.value:
where_clause_and.append(sqla_col == eq)
elif op == utils.FilterOperator.NOT_EQUALS.value:
where_clause_and.append(sqla_col != eq)
elif op == utils.FilterOperator.GREATER_THAN.value:
where_clause_and.append(sqla_col > eq)
elif op == utils.FilterOperator.LESS_THAN.value:
where_clause_and.append(sqla_col < eq)
elif op == utils.FilterOperator.GREATER_THAN_OR_EQUALS.value:
where_clause_and.append(sqla_col >= eq)
elif op == utils.FilterOperator.LESS_THAN_OR_EQUALS.value:
where_clause_and.append(sqla_col <= eq)
elif op in {
utils.FilterOperator.ILIKE,
utils.FilterOperator.LIKE,
utils.FilterOperator.ILIKE.value,
utils.FilterOperator.LIKE.value,
}:
if target_generic_type != GenericDataType.STRING:
sqla_col = sa.cast(sqla_col, sa.String)
if op == utils.FilterOperator.LIKE:
if op == utils.FilterOperator.LIKE.value:
where_clause_and.append(sqla_col.like(eq))
else:
where_clause_and.append(sqla_col.ilike(eq))
elif op in {utils.FilterOperator.NOT_LIKE}:
elif op in {utils.FilterOperator.NOT_LIKE.value}:
if target_generic_type != GenericDataType.STRING:
sqla_col = sa.cast(sqla_col, sa.String)
where_clause_and.append(sqla_col.not_like(eq))
elif (
op == utils.FilterOperator.TEMPORAL_RANGE
op == utils.FilterOperator.TEMPORAL_RANGE.value
and isinstance(eq, str)
and col_obj is not None
):
-2
View File
@@ -55,7 +55,6 @@ from superset.views.filters import (
BaseFilterRelatedRoles,
BaseFilterRelatedUsers,
FilterRelatedOwners,
FilterRelatedTables,
)
logger = logging.getLogger(__name__)
@@ -136,7 +135,6 @@ class RLSRestApi(BaseSupersetModelRestApi):
allowed_rel_fields = {"tables", "roles", "created_by", "changed_by"}
related_field_filters = {
"tables": RelatedFieldFilter("table_name", FilterRelatedTables),
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
}
base_related_field_filters = {
-1
View File
@@ -410,7 +410,6 @@ def cached_common_bootstrap_data( # pylint: disable=unused-argument
"d3_format": conf.get("D3_FORMAT"),
"d3_time_format": conf.get("D3_TIME_FORMAT"),
"currencies": conf.get("CURRENCIES"),
"deckgl_tiles": conf.get("DECKGL_BASE_MAP"),
"feature_flags": get_feature_flags(),
"extra_sequential_color_schemes": conf["EXTRA_SEQUENTIAL_COLOR_SCHEMES"],
"extra_categorical_color_schemes": conf["EXTRA_CATEGORICAL_COLOR_SCHEMES"],
-19
View File
@@ -102,22 +102,3 @@ class BaseFilterRelatedRoles(BaseFilter): # pylint: disable=too-few-public-meth
return extra_filters(query)
return query
class FilterRelatedTables(BaseFilter): # pylint: disable=too-few-public-methods
"""
A filter to allow searching for related tables.
Use in the api by adding something like:
related_field_filters = {
"tables": RelatedFieldFilter("table_name", FilterRelatedTables),
}
"""
name = lazy_gettext("Table")
arg_name = "tables"
def apply(self, query: Query, value: Optional[Any]) -> Query:
from superset.connectors.sqla.models import SqlaTable
like_value = "%" + cast(str, value) + "%"
return query.filter(SqlaTable.table_name.ilike(like_value))
@@ -555,30 +555,6 @@ class TestRowLevelSecurityWithRelatedAPI(SupersetTestCase):
assert len(result) == len(db_tables)
assert db_table_names == received_tables
def test_rls_tables_related_api_with_filter_matching_birth(self):
self.login(ADMIN_USERNAME)
# Test with filter that should match 'birth_names'
params = prison.dumps({"filter": "birth", "page": 0, "page_size": 100})
rv = self.client.get(f"/api/v1/rowlevelsecurity/related/tables?q={params}")
assert rv.status_code == 200
data = json.loads(rv.data.decode("utf-8"))
result = data["result"]
received_tables = {table["text"] for table in result}
# Should only return tables with 'birth' in the name
assert all("birth" in table_name.lower() for table_name in received_tables)
assert len(result) >= 1 # At least birth_names should be returned
def test_rls_tables_related_api_with_filter_no_matches(self):
self.login(ADMIN_USERNAME)
# Test with filter that should match nothing
params = prison.dumps({"filter": "nonexistent", "page": 0, "page_size": 100})
rv = self.client.get(f"/api/v1/rowlevelsecurity/related/tables?q={params}")
assert rv.status_code == 200
data = json.loads(rv.data.decode("utf-8"))
result = data["result"]
assert len(result) == 0
assert data["count"] == 0
def test_rls_roles_related_api(self):
self.login(ADMIN_USERNAME)
params = prison.dumps({"page": 0, "page_size": 100})

Some files were not shown because too many files have changed in this diff Show More