mirror of https://github.com/apache/superset.git
Merge branch 'master' into hotfix/lnglat-and-delimited
This commit is contained in:
commit
578113f3a6
|
@ -73,14 +73,6 @@ github:
|
|||
- test-postgres (3.9)
|
||||
- test-postgres (3.10)
|
||||
- test-sqlite (3.9)
|
||||
- docker-build (dev, linux/amd64)
|
||||
- docker-build (lean, linux/amd64)
|
||||
- docker-build (py310, linux/arm64)
|
||||
- docker-build (py310, linux/amd64)
|
||||
- docker-build (websocket, linux/arm64)
|
||||
- docker-build (websocket, linux/amd64)
|
||||
- docker-build (dockerize, linux/arm64)
|
||||
- docker-build (dockerize, linux/amd64)
|
||||
|
||||
required_pull_request_reviews:
|
||||
dismiss_stale_reviews: false
|
||||
|
|
|
@ -4,7 +4,8 @@ on:
|
|||
paths:
|
||||
- "superset/migrations/**"
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
pull_request:
|
||||
paths:
|
||||
- "superset/migrations/**"
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
# .github/workflows/chromatic.yml
|
||||
# see https://www.chromatic.com/docs/github-actions
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Workflow name
|
||||
name: 'Chromatic Storybook Master'
|
||||
|
||||
# Event for the workflow
|
||||
# Only run if changes were made in superset-frontend folder of repo on merge to Master
|
||||
on:
|
||||
# This will trigger when a branch merges to master when the PR has changes in the frontend folder updating the chromatic baseline
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- "superset-frontend/**"
|
||||
|
||||
# List of jobs
|
||||
jobs:
|
||||
config:
|
||||
runs-on: "ubuntu-latest"
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
- name: "Check for secrets"
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ (secrets.CHROMATIC_PROJECT_TOKEN != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
chromatic-deployment:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
# Operating System
|
||||
runs-on: ubuntu-latest
|
||||
# Job steps
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # 👈 Required to retrieve git history
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
working-directory: superset-frontend
|
||||
# 👇 Build and publish Storybook to Chromatic
|
||||
- name: Build and publish Storybook to Chromatic
|
||||
id: chromatic-master
|
||||
uses: chromaui/action@v10
|
||||
# Required options for the Chromatic GitHub Action
|
||||
with:
|
||||
# 👇 Location of package.json from root of mono-repo
|
||||
workingDir: superset-frontend
|
||||
# 👇 Chromatic projectToken, refer to the manage page to obtain it.
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
exitZeroOnChanges: true # 👈 Option to prevent the workflow from failing
|
||||
autoAcceptChanges: true # 👈 Option to accept all changes when merging to master
|
|
@ -2,16 +2,16 @@ name: "CodeQL"
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
branches: ["master", "[0-9].[0-9]"]
|
||||
paths:
|
||||
- 'superset/**'
|
||||
- "superset/**"
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
branches: ["master"]
|
||||
paths:
|
||||
- 'superset/**'
|
||||
- "superset/**"
|
||||
schedule:
|
||||
- cron: '0 4 * * *'
|
||||
- cron: "0 4 * * *"
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
|
@ -30,7 +30,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'python', 'javascript' ]
|
||||
language: ["python", "javascript"]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
|
|
|
@ -3,29 +3,35 @@ name: Docker
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
setup_matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix_config: ${{ steps.set_matrix.outputs.matrix_config }}
|
||||
steps:
|
||||
- id: set_matrix
|
||||
run: |
|
||||
MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["ci"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize"]'; fi)
|
||||
echo "matrix_config=${MATRIX_CONFIG}" >> $GITHUB_OUTPUT
|
||||
echo $GITHUB_OUTPUT
|
||||
|
||||
docker-build:
|
||||
name: docker-build
|
||||
needs: setup_matrix
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
build_preset: ["dev", "lean", "py310", "websocket", "dockerize"]
|
||||
platform: ["linux/amd64", "linux/arm64"]
|
||||
exclude:
|
||||
# disabling because slow! no python wheels for arm/py39 and
|
||||
# QEMU is slow!
|
||||
- build_preset: "dev"
|
||||
platform: "linux/arm64"
|
||||
- build_preset: "lean"
|
||||
platform: "linux/arm64"
|
||||
build_preset: ${{fromJson(needs.setup_matrix.outputs.matrix_config)}}
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
|
@ -46,4 +52,17 @@ jobs:
|
|||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
run: |
|
||||
pip install click
|
||||
./scripts/build_docker.py ${{ matrix.build_preset }} ${{ github.event_name }} --platform ${{ matrix.platform }}
|
||||
if [ "${{ github.event_name }}" = "push" ]; then
|
||||
./scripts/build_docker.py \
|
||||
${{ matrix.build_preset }} \
|
||||
${{ github.event_name }} \
|
||||
--build_context_ref "$RELEASE" $FORCE_LATEST \
|
||||
--platform "linux/arm64" \
|
||||
--platform "linux/amd64"
|
||||
elif [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
./scripts/build_docker.py \
|
||||
${{ matrix.build_preset }} \
|
||||
${{ github.event_name }} \
|
||||
--build_context_ref "$RELEASE" $FORCE_LATEST \
|
||||
--platform "linux/amd64"
|
||||
fi
|
||||
|
|
|
@ -3,7 +3,8 @@ name: Embedded SDK Release
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
|
||||
jobs:
|
||||
config:
|
||||
|
@ -31,7 +32,7 @@ jobs:
|
|||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "16"
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- run: npm ci
|
||||
- run: npm run ci:release
|
||||
env:
|
||||
|
|
|
@ -4,6 +4,7 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
|
||||
jobs:
|
||||
config:
|
||||
|
@ -33,8 +34,8 @@ jobs:
|
|||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
- name: Generate fossa report
|
||||
env:
|
||||
FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
# - Ensure that the job names in this workflow match exactly the names of the corresponding jobs in the main workflows.
|
||||
# - This workflow should be kept as-is, without path-specific conditions.
|
||||
|
||||
name: No Operation Checks
|
||||
name: no-op Checks
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
|
|
|
@ -3,7 +3,8 @@ name: pre-commit checks
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@ name: Prefer TypeScript
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
paths:
|
||||
- "superset-frontend/src/**"
|
||||
pull_request:
|
||||
|
|
|
@ -3,7 +3,8 @@ name: release-workflow
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
|
||||
jobs:
|
||||
config:
|
||||
|
|
|
@ -3,7 +3,8 @@ name: Superset CLI tests
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
|
@ -55,8 +56,8 @@ jobs:
|
|||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/testing.txt'
|
||||
cache: "pip"
|
||||
cache-dependency-path: "requirements/testing.txt"
|
||||
- name: Install dependencies
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
|
|
|
@ -6,6 +6,7 @@ on:
|
|||
- "docs/**"
|
||||
branches:
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
|
||||
jobs:
|
||||
config:
|
||||
|
@ -38,7 +39,7 @@ jobs:
|
|||
- name: Set up Node.js 16
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
node-version: "16"
|
||||
- name: yarn install
|
||||
run: |
|
||||
yarn install --check-cache
|
||||
|
|
|
@ -3,7 +3,8 @@ name: E2E
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
paths:
|
||||
- "superset-frontend/**"
|
||||
pull_request:
|
||||
|
|
|
@ -4,6 +4,7 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
paths:
|
||||
- "helm/**"
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ name: Python-Integration
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
|
@ -54,8 +55,8 @@ jobs:
|
|||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/testing.txt'
|
||||
cache: "pip"
|
||||
cache-dependency-path: "requirements/testing.txt"
|
||||
- name: Install dependencies
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
|
@ -120,8 +121,8 @@ jobs:
|
|||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/testing.txt'
|
||||
cache: "pip"
|
||||
cache-dependency-path: "requirements/testing.txt"
|
||||
- name: Install dependencies
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
|
@ -180,8 +181,8 @@ jobs:
|
|||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/testing.txt'
|
||||
cache: "pip"
|
||||
cache-dependency-path: "requirements/testing.txt"
|
||||
- name: Install dependencies
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
|
|
|
@ -4,7 +4,8 @@ name: Python Misc
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
paths:
|
||||
- "superset/**"
|
||||
pull_request:
|
||||
|
|
|
@ -4,7 +4,8 @@ name: Python Presto/Hive
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
paths:
|
||||
- "superset/**"
|
||||
pull_request:
|
||||
|
@ -70,8 +71,8 @@ jobs:
|
|||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/testing.txt'
|
||||
cache: "pip"
|
||||
cache-dependency-path: "requirements/testing.txt"
|
||||
- name: Install dependencies
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
|
@ -147,8 +148,8 @@ jobs:
|
|||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/testing.txt'
|
||||
cache: "pip"
|
||||
cache-dependency-path: "requirements/testing.txt"
|
||||
- name: Install dependencies
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
|
|
|
@ -4,17 +4,20 @@ name: Python-Unit
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
paths:
|
||||
- "superset/**"
|
||||
- "requirements/**"
|
||||
- "tests/unit_tests/**"
|
||||
- "scripts/**"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
paths:
|
||||
- "superset/**"
|
||||
- "requirements/**"
|
||||
- "tests/unit_tests/**"
|
||||
- "scripts/**"
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
|
@ -47,9 +50,9 @@ jobs:
|
|||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/testing.txt'
|
||||
# TODO: separated requirements.txt file just for unit tests
|
||||
cache: "pip"
|
||||
cache-dependency-path: "requirements/testing.txt"
|
||||
# TODO: separated requirements.txt file just for unit tests
|
||||
- name: Install dependencies
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
|
|
|
@ -3,7 +3,8 @@ name: Translations
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
|
@ -24,7 +25,7 @@ jobs:
|
|||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
node-version: "16"
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
|
|
|
@ -2,7 +2,8 @@ name: WebSocket server
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- "master"
|
||||
- "[0-9].[0-9]"
|
||||
paths:
|
||||
- "superset-websocket/**"
|
||||
pull_request:
|
||||
|
|
|
@ -4,6 +4,7 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- master
|
||||
- "[0-9].[0-9]"
|
||||
|
||||
jobs:
|
||||
config:
|
||||
|
@ -31,7 +32,7 @@ jobs:
|
|||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
node-version: "16"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
@ -39,7 +40,7 @@ jobs:
|
|||
|
||||
- name: Run Script
|
||||
env:
|
||||
SPREADSHEET_ID: '1oABNnzxJYzwUrHjr_c9wfYEq9dFL1ScVof9LlaAdxvo'
|
||||
SPREADSHEET_ID: "1oABNnzxJYzwUrHjr_c9wfYEq9dFL1ScVof9LlaAdxvo"
|
||||
SERVICE_ACCOUNT_KEY: ${{ secrets.GSHEET_KEY }}
|
||||
run: npm run lint-stats
|
||||
continue-on-error: true
|
||||
|
|
10
README.md
10
README.md
|
@ -201,5 +201,15 @@ Understanding the Superset Points of View
|
|||
|
||||
- [Superset API](https://superset.apache.org/docs/rest-api)
|
||||
|
||||
## Repo Activity
|
||||
<a href="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats?repo_id=39464018" target="_blank" style="display: block" align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=39464018&image_size=auto&color_scheme=dark" width="655" height="auto">
|
||||
<img alt="Performance Stats of apache/superset - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=39464018&image_size=auto&color_scheme=light" width="655" height="auto">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
|
||||
|
||||
<!-- telemetry/analytics pixel: -->
|
||||
<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=bc1c90cd-bc04-4e11-8c7b-289fb2839492" />
|
||||
|
|
|
@ -39,7 +39,7 @@ PYTHON=$(get_python_command)
|
|||
PIP=$(get_pip_command)
|
||||
|
||||
# Get the release directory's path. If you unzip an Apache release and just run the npm script to validate the release, this will be a file name like `apache-superset-x.x.xrcx-source.tar.gz`
|
||||
RELEASE_DIR_NAME="../../$(basename "$(dirname "$(pwd)")").tar.gz"
|
||||
RELEASE_ZIP_PATH="../../$(basename "$(dirname "$(pwd)")")-source.tar.gz"
|
||||
|
||||
# Install dependencies from requirements.txt if the file exists
|
||||
if [ -f "path/to/requirements.txt" ]; then
|
||||
|
@ -47,8 +47,5 @@ if [ -f "path/to/requirements.txt" ]; then
|
|||
$PYTHON -m $PIP install -r path/to/requirements.txt
|
||||
fi
|
||||
|
||||
# echo $PYTHON
|
||||
# echo $RELEASE_DIR_NAME
|
||||
|
||||
# Run the Python script with the parent directory name as an argument
|
||||
$PYTHON ../RELEASING/verify_release.py "$RELEASE_DIR_NAME"
|
||||
$PYTHON ../RELEASING/verify_release.py "$RELEASE_ZIP_PATH"
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
x-superset-image: &superset-image apachesuperset.docker.scarf.sh/apache/superset:${TAG:-latest-dev}
|
||||
x-superset-image: &superset-image apachesuperset.docker.scarf.sh/apache/superset:${TAG:-master-dev}
|
||||
x-superset-user: &superset-user root
|
||||
x-superset-depends-on: &superset-depends-on
|
||||
- db
|
||||
|
|
|
@ -9,7 +9,7 @@ version: 1
|
|||
|
||||
#### OS Dependencies
|
||||
|
||||
Make sure your machine meets the [OS dependencies](/docs/installation/installing-superset-from-scratch#os-dependencies) before following these steps.
|
||||
Make sure your machine meets the [OS dependencies](/docs/installation/installing-superset-from-pypi#os-dependencies) before following these steps.
|
||||
You also need to install MySQL or [MariaDB](https://mariadb.com/downloads).
|
||||
|
||||
Ensure that you are using Python version 3.9 or 3.10, then proceed with:
|
||||
|
|
|
@ -200,33 +200,6 @@ top of the box.
|
|||
To exit, select any other part of the dashboard. Finally, don’t forget to keep your changes using
|
||||
**Save changes**.
|
||||
|
||||
### Filter Box
|
||||
|
||||
In this section, you will learn how to add a filter to your dashboard. Specifically, we will create
|
||||
a filter that allows us to look at those flights that depart from a particular country.
|
||||
|
||||
A filter box visualization can be created as any other visualization by selecting **+ ‣ Chart**,
|
||||
and then _tutorial_flights_ as the datasource and Filter Box as the visualization type.
|
||||
|
||||
First of all, in the **Time** section, remove the filter from the Time range selection by selecting
|
||||
No filter.
|
||||
|
||||
Next, in **Filters Configurations** first add a new filter by selecting the plus sign and then edit
|
||||
the newly created filter by selecting the pencil icon.
|
||||
|
||||
For our use case, it makes most sense to present a list of countries in alphabetical order. First,
|
||||
enter the column as Origin Country and keep all other options the same and then select **Run
|
||||
Query**. This gives us a preview of our filter.
|
||||
|
||||
Next, remove the date filter by unchecking the Date Filter checkbox.
|
||||
|
||||
<img src={useBaseUrl("/img/tutorial/filter_on_origin_country.png" )} />
|
||||
|
||||
Finally, select **Save**, name the chart as Tutorial Filter, add the chart to our existing Tutorial
|
||||
Dashboard and then Save & go to dashboard. Once on the Dashboard, try using the filter to show only
|
||||
those flights that departed from the United Kingdom – you will see the filter is applied to all of
|
||||
the other visualizations on the dashboard.
|
||||
|
||||
### Publishing Your Dashboard
|
||||
|
||||
If you have followed all of the steps outlined in the previous section, you should have a dashboard
|
||||
|
|
|
@ -64,7 +64,7 @@ DATA_CACHE_CONFIG = {
|
|||
|
||||
The cache timeout for charts may be overridden by the settings for an individual chart, dataset, or
|
||||
database. Each of these configurations will be checked in order before falling back to the default
|
||||
value defined in `DATA_CACHE_CONFIG.
|
||||
value defined in `DATA_CACHE_CONFIG`.
|
||||
|
||||
Note, that by setting the cache timeout to `-1`, caching for charting data can be disabled, either
|
||||
per chart, dataset or database, or by default if set in `DATA_CACHE_CONFIG`.
|
||||
|
|
|
@ -1,47 +1,47 @@
|
|||
# Docker Images and Tags
|
||||
# Docker builds, images and tags
|
||||
|
||||
The Apache Superset community extensively uses Docker for development, release,
|
||||
and productionizing Superset. This page details our Docker builds and tag naming
|
||||
schemes to help users navigate our offerings.
|
||||
|
||||
Images are built and pushed to the [Superset Docker Hub repository](
|
||||
https://hub.docker.com/r/apache/superset). Different sets of images are created for:
|
||||
https://hub.docker.com/r/apache/superset) using GitHub Actions.
|
||||
Different sets of images are built and/or published at different times:
|
||||
|
||||
- **Published releases** (`release`): with tags like `3.0.0` and the `latest` tag.
|
||||
Those are multi-platform (arm+amd). More on that later.
|
||||
- **Pull request iterations** (`pull_request`):, each identified by tags starting with a SHA like
|
||||
`8a2f7d378ab13c156fa183d9284b607ed69f5ecc`, and `pr-3454`, referencing the pull
|
||||
request ID.
|
||||
- **Published releases** (`release`): published using
|
||||
tags like `3.0.0` and the `latest` tag.
|
||||
- **Pull request iterations** (`pull_request`): for each pull request, while
|
||||
we actively build the docker to validate the build, we do
|
||||
not publish those images for security reasons, we simply `docker build --load`
|
||||
- **Merges to the main branch** (`push`): resulting in new SHAs, with tags
|
||||
prefixed with `master` for the latest `master` version.
|
||||
|
||||
Each CI build run has multiple builds for different purposes, identified by suffixes:
|
||||
- **Build preset:** We offer various images for different needs:
|
||||
- `lean`: The default Docker image, including both frontend and backend. Tags
|
||||
without a build_preset are lean builds, e.g., `latest`.
|
||||
- `dev`: For development, with a headless browser and root access.
|
||||
- `py310`, e.g., Py310: Similar to lean but with a different Python version (in this example, 3.10).
|
||||
- `ci`: For certain CI workloads.
|
||||
- `websocket`: For Superset clusters supporting advanced features.
|
||||
- `dockerize`: Used by Helm.
|
||||
- **Platform:** We build for `linux/arm64` and `linux/amd64`. The `-arm` suffix
|
||||
indicates ARM builds (e.g., `latest-arm`), while tags without a suffix are for
|
||||
AMD (e.g., `latest`).
|
||||
# Build presets
|
||||
|
||||
## Key Image Tags and Examples
|
||||
We have a set of build "presets" that each represent a combination of
|
||||
parameters for the build, mostly pointing to either different target layer
|
||||
for the build, and/or base image.
|
||||
|
||||
- `latest`: The latest official release build, implicitly the lean build on
|
||||
`linux/amd64`.
|
||||
Here are the build presets that are exposed through the `build_docker.py` script:
|
||||
- `lean`: The default Docker image, including both frontend and backend. Tags
|
||||
without a build_preset are lean builds, e.g., `latest`.
|
||||
- `dev`: For development, with a headless browser, dev-related utilities and root access.
|
||||
- `py310`, e.g., Py310: Similar to lean but with a different Python version (in this example, 3.10).
|
||||
- `ci`: For certain CI workloads.
|
||||
- `websocket`: For Superset clusters supporting advanced features.
|
||||
- `dockerize`: Used by Helm.
|
||||
|
||||
## Key tags examples
|
||||
|
||||
- `latest`: The latest official release build
|
||||
- `latest-dev`: the `-dev` image of the latest official release build, with a
|
||||
headless browser and root access.
|
||||
- `master`: The latest build from the `master` branch, implicitly lean on
|
||||
`linux/amd64`.
|
||||
- `master`: The latest build from the `master` branch, implicitly the lean build
|
||||
preset
|
||||
- `master-dev`: Similar to `master` but includes a headless browser and root access.
|
||||
- `pr-5252`: The latest commit in PR 5252.
|
||||
- `30948dc401b40982cb7c0dbf6ebbe443b2748c1b-dev-arm`: A `linux/arm64` build for
|
||||
this specific SHA, which could be from a pull request, master merge, or release.
|
||||
- `30948dc-dev-arm`: Same as above, but SHA truncated to 7 characters for a
|
||||
shorter handle on the same image
|
||||
- `30948dc401b40982cb7c0dbf6ebbe443b2748c1b-dev`: A build for
|
||||
this specific SHA, which could be from a `master` merge, or release.
|
||||
- `websocket-latest`: The WebSocket image for use in a Superset cluster.
|
||||
|
||||
For insights or modifications to the build matrix and tagging conventions,
|
||||
|
@ -64,9 +64,9 @@ build times, larger images, lower layer cache hit rate, ...).
|
|||
For production use cases, we recommend that you derive our `lean` image(s) and
|
||||
add database support for the database you need.
|
||||
|
||||
## On supporting arm64 AND amd64
|
||||
## On supporting different platforms (namely arm64 AND amd64)
|
||||
|
||||
Only the release builds are multi-platform, supporting `linux/arm64`
|
||||
Currently all automated builds are multi-platform, supporting both `linux/arm64`
|
||||
and `linux/amd64`. This enables higher level constructs like `helm` and
|
||||
docker-compose to point to these images and effectively be multi-platform
|
||||
as well.
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
---
|
||||
title: Installing From Scratch
|
||||
title: Installing from PyPI
|
||||
hide_title: true
|
||||
sidebar_position: 2
|
||||
version: 1
|
||||
---
|
||||
|
||||
## Installing Superset from Scratch
|
||||
## Installing Superset from PyPI
|
||||
|
||||
This page describes how to install Superset using the `apache-superset` package [published on PyPI](https://pypi.org/project/apache-superset/).
|
||||
|
||||
### OS Dependencies
|
||||
|
|
@ -174,7 +174,7 @@ In this section, we'll walkthrough the pre-defined Jinja macros in Superset.
|
|||
|
||||
**Current Username**
|
||||
|
||||
The `{{ current_username() }}` macro returns the username of the currently logged in user.
|
||||
The `{{ current_username() }}` macro returns the `username` of the currently logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the `username` value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
|
@ -189,19 +189,34 @@ cache key by adding the following parameter to your Jinja code:
|
|||
|
||||
**Current User ID**
|
||||
|
||||
The `{{ current_user_id() }}` macro returns the user_id of the currently logged in user.
|
||||
The `{{ current_user_id() }}` macro returns the account ID of the currently logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the `user_id` value will be used
|
||||
If you have caching enabled in your Superset configuration, then by default the account `id` value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
You can disable the inclusion of the `user_id` value in the calculation of the
|
||||
You can disable the inclusion of the account `id` value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code:
|
||||
|
||||
```
|
||||
{{ current_user_id(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
**Current User Email**
|
||||
|
||||
The `{{ current_user_email() }}` macro returns the email address of the currently logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the email address value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
You can disable the inclusion of the email value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code:
|
||||
|
||||
```
|
||||
{{ current_user_email(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
**Custom URL Parameters**
|
||||
|
||||
The `{{ url_param('custom_variable') }}` macro lets you define arbitrary URL
|
||||
|
|
|
@ -13,15 +13,11 @@ geospatial charts.
|
|||
|
||||
Here are a **few different ways you can get started with Superset**:
|
||||
|
||||
- Install Superset [from scratch](/docs/installation/installing-superset-from-scratch/)
|
||||
- Deploy Superset locally with one command
|
||||
[using Docker Compose](/docs/installation/installing-superset-using-docker-compose)
|
||||
- Try a [Quickstart deployment](/docs/quickstart), which runs a single Docker container
|
||||
- Install Superset [from PyPI](/docs/installation/installing-superset-from-pypi/)
|
||||
- Deploy Superset [using Docker Compose](/docs/installation/installing-superset-using-docker-compose)
|
||||
- Deploy Superset [with Kubernetes](/docs/installation/running-on-kubernetes)
|
||||
- Run a [Docker image](https://hub.docker.com/r/apache/superset) from Dockerhub
|
||||
- Download Superset [from Pypi here](https://pypi.org/project/apache-superset/)
|
||||
- Install the latest version of Superset
|
||||
[from GitHub](https://github.com/apache/superset/tree/latest)
|
||||
- Download the [source from Apache Foundation's website](https://dist.apache.org/repos/dist/release/superset/)
|
||||
- Download the [source code from Apache Foundation's website](https://dist.apache.org/repos/dist/release/superset/)
|
||||
|
||||
#### Video Overview
|
||||
|
||||
|
|
|
@ -61,15 +61,39 @@ superset export_datasource_schema
|
|||
|
||||
As a reminder, you can use the `-b` flag to include back references.
|
||||
|
||||
### Importing Datasources from YAML
|
||||
### Importing Datasources
|
||||
|
||||
In order to import datasources from a YAML file(s), run:
|
||||
In order to import datasources from a ZIP file, run:
|
||||
|
||||
```
|
||||
superset import_datasources -p <path / filename>
|
||||
```
|
||||
|
||||
The optional username flag **-u** sets the user used for the datasource import. The default is 'admin'. Example:
|
||||
|
||||
```
|
||||
superset import_datasources -p <path / filename> -u 'admin'
|
||||
```
|
||||
|
||||
### Legacy Importing Datasources
|
||||
|
||||
#### From older versions of Superset to current version
|
||||
|
||||
When using Superset version 4.x.x to import from an older version (2.x.x or 3.x.x) importing is supported as the command `legacy_import_datasources` and expects a JSON or directory of JSONs. The options are `-r` for recursive and `-u` for specifying a user. Example of legacy import without options:
|
||||
|
||||
```
|
||||
superset legacy_import_datasources -p <path or filename>
|
||||
```
|
||||
|
||||
#### From older versions of Superset to older versions
|
||||
|
||||
When using an older Superset version (2.x.x & 3.x.x) of Superset, the command is `import_datasources`. ZIP and YAML files are supported and to switch between them the feature flag `VERSIONED_EXPORT` is used. When `VERSIONED_EXPORT` is `True`, `import_datasources` expects a ZIP file, otherwise YAML. Example:
|
||||
|
||||
```
|
||||
superset import_datasources -p <path or filename>
|
||||
```
|
||||
|
||||
If you supply a path all files ending with **yaml** or **yml** will be parsed. You can apply
|
||||
When `VERSIONED_EXPORT` is `False`, if you supply a path all files ending with **yaml** or **yml** will be parsed. You can apply
|
||||
additional flags (e.g. to search the supplied path recursively):
|
||||
|
||||
```
|
||||
|
|
|
@ -4,6 +4,16 @@ hide_title: true
|
|||
sidebar_position: 2
|
||||
---
|
||||
|
||||
#### Version 3.0.4, 3.1.1
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|:---------------|:-----------------------------------------------------------------------------|----------------------------:|
|
||||
| CVE-2024-27315 | Improper error handling on alerts | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-24773 | Improper validation of SQL statements allows for unauthorized access to data | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-24772 | Improper Neutralisation of custom SQL on embedded context | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-24779 | Improper data authorization when creating a new dataset | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
| CVE-2024-26016 | Improper authorization validation on dashboards and charts import | < 3.0.4, >= 3.1.0, < 3.1.1 |
|
||||
|
||||
#### Version 3.0.3
|
||||
|
||||
| CVE | Title | Affected |
|
||||
|
|
|
@ -139,7 +139,7 @@ const config = {
|
|||
({
|
||||
docs: {
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
editUrl: 'https://github.com/apache/superset/tree/master/docs',
|
||||
editUrl: 'https://github.com/apache/superset/edit/master/docs',
|
||||
},
|
||||
blog: {
|
||||
showReadingTime: true,
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@algolia/client-search": "^4.22.1",
|
||||
"@ant-design/icons": "^4.7.0",
|
||||
"@ant-design/icons": "^5.3.1",
|
||||
"@docsearch/react": "^3.5.2",
|
||||
"@docusaurus/core": "^2.4.1",
|
||||
"@docusaurus/plugin-client-redirects": "^2.4.3",
|
||||
|
|
|
@ -259,3 +259,13 @@ a > span > svg {
|
|||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Edit Button */
|
||||
|
||||
.edit-page-link {
|
||||
position: sticky;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
border-radius: 10px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import DocItem from '@theme-original/DocItem';
|
||||
|
||||
const EditPageLink = styled('a')`
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
padding: 1rem;
|
||||
padding-left: 4rem;
|
||||
background-color: #444;
|
||||
border-radius: 10px;
|
||||
z-index: 9999;
|
||||
background-image: url('/img/github-dark.png');
|
||||
background-size: 2rem;
|
||||
background-position: 1rem center;
|
||||
background-repeat: no-repeat;
|
||||
transition: background-color 0.3s; /* Smooth transition for hover effect */
|
||||
bpx-shadow: 0 0 0 0 rgba(0,0,0,0); /* Smooth transition for hover effect */
|
||||
scale: .9;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: #333;
|
||||
box-shadow: 5px 5px 10px 0 rgba(0,0,0,0.3);
|
||||
scale: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function DocItemWrapper(props) {
|
||||
return (
|
||||
<>
|
||||
<EditPageLink href={props.content.metadata.editUrl} target="_blank" rel="noopener noreferrer">
|
||||
Edit this page on GitHub
|
||||
</EditPageLink>
|
||||
<DocItem {...props} />
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -21,3 +21,5 @@ RewriteRule ^(.*)$ https://superset.apache.org/$1 [R,L]
|
|||
|
||||
RewriteCond %{HTTP_HOST} ^superset.incubator.apache.org$ [NC]
|
||||
RewriteRule ^(.*)$ https://superset.apache.org/$1 [R=301,L]
|
||||
|
||||
Header set Content-Security-Policy "default-src data: blob: 'self' *.apache.org *.bugherd.com *.scarf.sh *.googleapis.com *.googletagmanager.com *.google-analytics.com 'unsafe-inline' 'unsafe-eval'; frame-src *; frame-ancestors 'self' *.preset.io *.google.com https://sidebar.bugherd.com https://unpkg.com; form-action 'self'; worker-src blob:; img-src 'self' blob: data: https:; font-src 'self' https://fonts.gstatic.com; object-src 'none'"
|
||||
|
|
128
docs/yarn.lock
128
docs/yarn.lock
|
@ -153,10 +153,17 @@
|
|||
dependencies:
|
||||
"@ctrl/tinycolor" "^3.4.0"
|
||||
|
||||
"@ant-design/icons-svg@^4.2.1":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a"
|
||||
integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==
|
||||
"@ant-design/colors@^7.0.0":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.0.2.tgz#c5c753a467ce8d86ba7ca4736d2c01f599bb5492"
|
||||
integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg==
|
||||
dependencies:
|
||||
"@ctrl/tinycolor" "^3.6.1"
|
||||
|
||||
"@ant-design/icons-svg@^4.2.1", "@ant-design/icons-svg@^4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.4.0.tgz#435b544291fdabe992b3fd17829ff88c04c628b4"
|
||||
integrity sha512-71rcNssTaRL1ytvPLebKuc/8Bjqxs5V1YkTbqlSCvNa0Se+HmYJwWHhRTpsSHBh+sWFtc7xpGCTRW2Ta04XyHw==
|
||||
|
||||
"@ant-design/icons@^4.7.0":
|
||||
version "4.7.0"
|
||||
|
@ -169,6 +176,17 @@
|
|||
classnames "^2.2.6"
|
||||
rc-util "^5.9.4"
|
||||
|
||||
"@ant-design/icons@^5.3.1":
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-5.3.1.tgz#908eda82cbd455b83b30d620947ab8fbf2f4c5da"
|
||||
integrity sha512-85zROTJCCApQn0Ee6L9561+Vd7yVKtSWNm2TpmOsYMrumchbzaRK83x1WWHv2VG+Y1ZAaKkDwcnnSPS/eSwNHA==
|
||||
dependencies:
|
||||
"@ant-design/colors" "^7.0.0"
|
||||
"@ant-design/icons-svg" "^4.4.0"
|
||||
"@babel/runtime" "^7.11.2"
|
||||
classnames "^2.2.6"
|
||||
rc-util "^5.31.1"
|
||||
|
||||
"@ant-design/react-slick@~0.28.1":
|
||||
version "0.28.4"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-0.28.4.tgz#8b296b87ad7c7ae877f2a527b81b7eebd9dd29a9"
|
||||
|
@ -1505,26 +1523,12 @@
|
|||
core-js-pure "^3.25.1"
|
||||
regenerator-runtime "^0.13.11"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||
version "7.16.3"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz"
|
||||
integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||
version "7.23.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7"
|
||||
integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
|
||||
integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.18.6":
|
||||
version "7.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
|
||||
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.11"
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/template@^7.12.7", "@babel/template@^7.16.0":
|
||||
version "7.16.0"
|
||||
|
@ -1634,6 +1638,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz#c3c5ae543c897caa9c2a68630bed355be5f9990f"
|
||||
integrity sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==
|
||||
|
||||
"@ctrl/tinycolor@^3.6.1":
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31"
|
||||
integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
|
||||
|
||||
"@docsearch/css@3.5.2":
|
||||
version "3.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.5.2.tgz#610f47b48814ca94041df969d9fcc47b91fc5aac"
|
||||
|
@ -4887,16 +4896,17 @@ es-module-lexer@^1.2.1:
|
|||
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5"
|
||||
integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==
|
||||
|
||||
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
|
||||
version "0.10.53"
|
||||
resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz"
|
||||
integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
|
||||
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@^0.10.62, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
|
||||
version "0.10.63"
|
||||
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
|
||||
integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
|
||||
dependencies:
|
||||
es6-iterator "~2.0.3"
|
||||
es6-symbol "~3.1.3"
|
||||
next-tick "~1.0.0"
|
||||
es6-iterator "^2.0.3"
|
||||
es6-symbol "^3.1.3"
|
||||
esniff "^2.0.1"
|
||||
next-tick "^1.1.0"
|
||||
|
||||
es6-iterator@^2.0.3, es6-iterator@~2.0.3:
|
||||
es6-iterator@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz"
|
||||
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
|
||||
|
@ -4905,7 +4915,7 @@ es6-iterator@^2.0.3, es6-iterator@~2.0.3:
|
|||
es5-ext "^0.10.35"
|
||||
es6-symbol "^3.1.1"
|
||||
|
||||
es6-symbol@^3.1.1, es6-symbol@~3.1.3:
|
||||
es6-symbol@^3.1.1, es6-symbol@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz"
|
||||
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
|
||||
|
@ -4956,6 +4966,16 @@ eslint-scope@5.1.1:
|
|||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
esniff@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
|
||||
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
|
||||
dependencies:
|
||||
d "^1.0.1"
|
||||
es5-ext "^0.10.62"
|
||||
event-emitter "^0.3.5"
|
||||
type "^2.7.2"
|
||||
|
||||
esprima@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
|
||||
|
@ -7367,11 +7387,6 @@ next-tick@1, next-tick@^1.1.0:
|
|||
resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz"
|
||||
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
|
||||
|
||||
next-tick@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz"
|
||||
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
|
||||
|
||||
no-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz"
|
||||
|
@ -8634,23 +8649,13 @@ rc-upload@~4.3.0:
|
|||
classnames "^2.2.5"
|
||||
rc-util "^5.2.0"
|
||||
|
||||
rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.0.7, rc-util@^5.12.0, rc-util@^5.14.0, rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.2.0, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.4.0, rc-util@^5.5.0, rc-util@^5.5.1, rc-util@^5.6.1, rc-util@^5.7.0, rc-util@^5.8.0, rc-util@^5.9.4, rc-util@^5.9.8:
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.17.0.tgz#6b0788038075c3d5c215541539573a4a03827070"
|
||||
integrity sha512-HWuTIKzBeZQQ7IBqdokE0wMp/xx39/KfUJ0gcquBigoldDCrf3YBcWFHrrQlJG7sI82Wg8mwp1uAKV3zMGfAgg==
|
||||
rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.0.7, rc-util@^5.12.0, rc-util@^5.14.0, rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.3, rc-util@^5.2.0, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.31.1, rc-util@^5.4.0, rc-util@^5.5.0, rc-util@^5.5.1, rc-util@^5.6.1, rc-util@^5.7.0, rc-util@^5.8.0, rc-util@^5.9.4, rc-util@^5.9.8:
|
||||
version "5.38.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.38.1.tgz#4915503b89855f5c5cd9afd4c72a7a17568777bb"
|
||||
integrity sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
react-is "^16.12.0"
|
||||
shallowequal "^1.1.0"
|
||||
|
||||
rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.3:
|
||||
version "5.19.3"
|
||||
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.19.3.tgz#5f6aa854820f6d5824451d80771035b013eaf6d8"
|
||||
integrity sha512-S28epi9E2s7Nir05q8Ffl3hzDLwkavTGi0PGH1cTqCmkpG1AeBEuZgQDpksYeU6IgHcds5hWIPE5PUcdFiZl8w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
react-is "^16.12.0"
|
||||
shallowequal "^1.1.0"
|
||||
"@babel/runtime" "^7.18.3"
|
||||
react-is "^18.2.0"
|
||||
|
||||
rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.1:
|
||||
version "3.4.2"
|
||||
|
@ -8785,7 +8790,7 @@ react-inspector@^5.1.1:
|
|||
is-dom "^1.0.0"
|
||||
prop-types "^15.0.0"
|
||||
|
||||
react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
|
||||
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
@ -8795,6 +8800,11 @@ react-is@^17.0.2:
|
|||
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
react-is@^18.2.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-json-view@^1.21.3:
|
||||
version "1.21.3"
|
||||
resolved "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz"
|
||||
|
@ -8983,6 +8993,11 @@ regenerator-runtime@^0.13.4:
|
|||
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz"
|
||||
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
|
||||
|
||||
regenerator-runtime@^0.14.0:
|
||||
version "0.14.1"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
|
||||
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
|
||||
|
||||
regenerator-transform@^0.15.2:
|
||||
version "0.15.2"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4"
|
||||
|
@ -10076,6 +10091,11 @@ type@^2.5.0:
|
|||
resolved "https://registry.npmjs.org/type/-/type-2.5.0.tgz"
|
||||
integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==
|
||||
|
||||
type@^2.7.2:
|
||||
version "2.7.2"
|
||||
resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
|
||||
integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
|
||||
|
||||
typedarray-to-buffer@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz"
|
||||
|
|
|
@ -17,3 +17,6 @@
|
|||
# under the License.
|
||||
#
|
||||
-e file:.
|
||||
urllib3>=1.26.18
|
||||
werkzeug>=3.0.1
|
||||
numexpr>=2.9.0
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# SHA1:a9dde048f1ee1f00586264d726d0e89f16e56183
|
||||
# SHA1:85649679306ea016e401f37adfbad832028d2e5f
|
||||
#
|
||||
# This file is autogenerated by pip-compile-multi
|
||||
# To update, run:
|
||||
|
@ -78,7 +78,7 @@ cron-descriptor==1.2.24
|
|||
# via apache-superset
|
||||
croniter==1.0.15
|
||||
# via apache-superset
|
||||
cryptography==42.0.2
|
||||
cryptography==42.0.4
|
||||
# via
|
||||
# apache-superset
|
||||
# paramiko
|
||||
|
@ -90,6 +90,8 @@ dnspython==2.1.0
|
|||
# via email-validator
|
||||
email-validator==1.1.3
|
||||
# via flask-appbuilder
|
||||
exceptiongroup==1.2.0
|
||||
# via cattrs
|
||||
flask==2.2.5
|
||||
# via
|
||||
# apache-superset
|
||||
|
@ -104,7 +106,7 @@ flask==2.2.5
|
|||
# flask-session
|
||||
# flask-sqlalchemy
|
||||
# flask-wtf
|
||||
flask-appbuilder==4.4.0
|
||||
flask-appbuilder==4.4.1
|
||||
# via apache-superset
|
||||
flask-babel==1.0.0
|
||||
# via flask-appbuilder
|
||||
|
@ -143,7 +145,9 @@ geopy==2.2.0
|
|||
google-auth==2.27.0
|
||||
# via shillelagh
|
||||
greenlet==3.0.3
|
||||
# via shillelagh
|
||||
# via
|
||||
# shillelagh
|
||||
# sqlalchemy
|
||||
gunicorn==21.2.0
|
||||
# via apache-superset
|
||||
hashids==1.3.1
|
||||
|
@ -208,8 +212,10 @@ nh3==0.2.11
|
|||
# via apache-superset
|
||||
numba==0.57.1
|
||||
# via pandas
|
||||
numexpr==2.8.4
|
||||
# via pandas
|
||||
numexpr==2.9.0
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# pandas
|
||||
numpy==1.23.5
|
||||
# via
|
||||
# apache-superset
|
||||
|
@ -232,7 +238,9 @@ packaging==23.1
|
|||
pandas[performance]==2.0.3
|
||||
# via apache-superset
|
||||
paramiko==3.4.0
|
||||
# via sshtunnel
|
||||
# via
|
||||
# apache-superset
|
||||
# sshtunnel
|
||||
parsedatetime==2.6
|
||||
# via apache-superset
|
||||
pgsanity==0.2.9
|
||||
|
@ -293,7 +301,7 @@ pyyaml==6.0.1
|
|||
# via
|
||||
# apache-superset
|
||||
# apispec
|
||||
redis==4.5.4
|
||||
redis==4.6.0
|
||||
# via apache-superset
|
||||
requests==2.31.0
|
||||
# via
|
||||
|
@ -347,6 +355,7 @@ tabulate==0.8.9
|
|||
typing-extensions==4.4.0
|
||||
# via
|
||||
# apache-superset
|
||||
# cattrs
|
||||
# flask-limiter
|
||||
# limits
|
||||
# shillelagh
|
||||
|
@ -358,6 +367,7 @@ url-normalize==1.4.3
|
|||
# via requests-cache
|
||||
urllib3==1.26.18
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# requests
|
||||
# requests-cache
|
||||
# selenium
|
||||
|
@ -370,6 +380,7 @@ wcwidth==0.2.5
|
|||
# via prompt-toolkit
|
||||
werkzeug==3.0.1
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# flask
|
||||
# flask-appbuilder
|
||||
# flask-jwt-extended
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
# via
|
||||
# -r requirements/base.in
|
||||
# -r requirements/development.in
|
||||
appnope==0.1.3
|
||||
# via ipython
|
||||
astroid==2.15.8
|
||||
# via pylint
|
||||
asttokens==2.2.1
|
||||
|
@ -115,6 +113,8 @@ thrift==0.16.0
|
|||
# thrift-sasl
|
||||
thrift-sasl==0.4.3
|
||||
# via pyhive
|
||||
tomli==2.0.1
|
||||
# via pylint
|
||||
tomlkit==0.11.8
|
||||
# via pylint
|
||||
traitlets==5.9.0
|
||||
|
|
|
@ -15,6 +15,5 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
-r base.in
|
||||
-e .[postgres]
|
||||
gevent
|
||||
-e .[postgres,gevent]
|
||||
greenlet>=2.0.2
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# SHA1:439e3ee196ce81f342c935117ba5e0eeee8c385b
|
||||
# SHA1:f00a57c70a52607d638c19f64f426f887382927e
|
||||
#
|
||||
# This file is autogenerated by pip-compile-multi
|
||||
# To update, run:
|
||||
|
@ -11,7 +11,7 @@
|
|||
# -r requirements/base.in
|
||||
# -r requirements/docker.in
|
||||
gevent==23.9.1
|
||||
# via -r requirements/docker.in
|
||||
# via apache-superset
|
||||
psycopg2-binary==2.9.6
|
||||
# via apache-superset
|
||||
zope-event==4.5.0
|
||||
|
|
|
@ -52,6 +52,12 @@ pyproject-hooks==1.0.0
|
|||
# via build
|
||||
pyyaml==6.0.1
|
||||
# via pre-commit
|
||||
tomli==2.0.1
|
||||
# via
|
||||
# build
|
||||
# pip-tools
|
||||
# pyproject-api
|
||||
# tox
|
||||
toposort==1.10
|
||||
# via pip-compile-multi
|
||||
tox==4.6.4
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
docker
|
||||
flask-testing
|
||||
freezegun
|
||||
grpcio>=1.55.3
|
||||
openapi-spec-validator
|
||||
parameterized
|
||||
pyfakefs
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# SHA1:95300275481abb1413eb98a5c79fb7cf96814cdd
|
||||
# SHA1:a37a1037f359c1101162ef43288178fbf00c487d
|
||||
#
|
||||
# This file is autogenerated by pip-compile-multi
|
||||
# To update, run:
|
||||
|
@ -62,6 +62,7 @@ googleapis-common-protos==1.59.0
|
|||
# grpcio-status
|
||||
grpcio==1.60.1
|
||||
# via
|
||||
# -r requirements/testing.in
|
||||
# google-api-core
|
||||
# google-cloud-bigquery
|
||||
# grpcio-status
|
||||
|
@ -109,6 +110,8 @@ pyee==11.0.1
|
|||
# via playwright
|
||||
pyfakefs==5.2.2
|
||||
# via -r requirements/testing.in
|
||||
pyhive[presto]==0.7.0
|
||||
# via apache-superset
|
||||
pytest==7.3.1
|
||||
# via
|
||||
# -r requirements/testing.in
|
||||
|
@ -132,7 +135,7 @@ tqdm==4.65.0
|
|||
# via
|
||||
# cmdstanpy
|
||||
# prophet
|
||||
trino==0.324.0
|
||||
trino==0.328.0
|
||||
# via apache-superset
|
||||
tzlocal==4.3
|
||||
# via trino
|
||||
|
|
|
@ -34,7 +34,7 @@ REGEXES=()
|
|||
for CHECK in "$@"
|
||||
do
|
||||
if [[ ${CHECK} == "python" ]]; then
|
||||
REGEX="(^\.github\/workflows\/.*python|^tests\/|^superset\/|^setup\.py|^requirements\/.+\.txt|^\.pylintrc)"
|
||||
REGEX="(^\.github\/workflows\/.*python|^tests\/|^superset\/|^scripts\/|^setup\.py|^requirements\/.+\.txt|^\.pylintrc)"
|
||||
echo "Searching for changes in python files"
|
||||
elif [[ ${CHECK} == "frontend" ]]; then
|
||||
REGEX="(^\.github\/workflows\/.*(bashlib|frontend|e2e)|^superset-frontend\/)"
|
||||
|
|
|
@ -98,13 +98,13 @@ done
|
|||
|
||||
if [ -z "${GITHUB_TAG_NAME}" ]; then
|
||||
echo "Missing tag parameter, usage: ./scripts/tag_latest_release.sh <GITHUB_TAG_NAME>"
|
||||
echo "::set-output name=SKIP_TAG::true"
|
||||
echo "SKIP_TAG=true" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$(git_show_ref)" ]; then
|
||||
echo "The tag ${GITHUB_TAG_NAME} does not exist. Please use a different tag."
|
||||
echo "::set-output name=SKIP_TAG::true"
|
||||
echo "SKIP_TAG=true" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
@ -112,7 +112,7 @@ fi
|
|||
if ! [[ ${GITHUB_TAG_NAME} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
||||
then
|
||||
echo "This tag ${GITHUB_TAG_NAME} is not a valid release version. Not tagging."
|
||||
echo "::set-output name=SKIP_TAG::true"
|
||||
echo "SKIP_TAG=true" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -177,14 +177,14 @@ done
|
|||
# Determine the result based on the comparison
|
||||
if [[ -z "$compare_result" ]]; then
|
||||
echo "Versions are equal"
|
||||
echo "::set-output name=SKIP_TAG::true"
|
||||
echo "SKIP_TAG=true" >> $GITHUB_OUTPUT
|
||||
elif [[ "$compare_result" == "greater" ]]; then
|
||||
echo "This release tag ${GITHUB_TAG_NAME} is newer than the latest."
|
||||
echo "::set-output name=SKIP_TAG::false"
|
||||
echo "SKIP_TAG=false" >> $GITHUB_OUTPUT
|
||||
# Add other actions you want to perform for a newer version
|
||||
elif [[ "$compare_result" == "lesser" ]]; then
|
||||
echo "This release tag ${GITHUB_TAG_NAME} is older than the latest."
|
||||
echo "This release tag ${GITHUB_TAG_NAME} is not the latest. Not tagging."
|
||||
# if you've gotten this far, then we don't want to run any tags in the next step
|
||||
echo "::set-output name=SKIP_TAG::true"
|
||||
echo "SKIP_TAG=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
|
10
setup.py
10
setup.py
|
@ -80,11 +80,10 @@ setup(
|
|||
"colorama",
|
||||
"croniter>=0.3.28",
|
||||
"cron-descriptor",
|
||||
# snowflake-connector-python as of 3.7.0 doesn't support >=42.* therefore lowering the min to 41.0.2
|
||||
"cryptography>=41.0.2, <43.0.0",
|
||||
"cryptography>=42.0.4, <43.0.0",
|
||||
"deprecation>=2.1.0, <2.2.0",
|
||||
"flask>=2.2.5, <3.0.0",
|
||||
"flask-appbuilder>=4.4.0, <5.0.0",
|
||||
"flask-appbuilder>=4.4.1, <5.0.0",
|
||||
"flask-caching>=2.1.0, <3",
|
||||
"flask-compress>=1.13, <2.0",
|
||||
"flask-talisman>=1.0.0, <2.0",
|
||||
|
@ -108,6 +107,7 @@ setup(
|
|||
"packaging",
|
||||
"pandas[performance]>=2.0.3, <2.1",
|
||||
"parsedatetime",
|
||||
"paramiko>=3.4.0",
|
||||
"pgsanity",
|
||||
"polyline>=2.0.0, <3.0",
|
||||
"pyparsing>=3.0.6, <4",
|
||||
|
@ -117,7 +117,7 @@ setup(
|
|||
"pyarrow>=14.0.1, <15",
|
||||
"pyyaml>=6.0.0, <7.0.0",
|
||||
"PyJWT>=2.4.0, <3.0",
|
||||
"redis>=4.5.4, <5.0",
|
||||
"redis>=4.6.0, <5.0",
|
||||
"selenium>=3.141.0, <4.10.0",
|
||||
"shillelagh[gsheetsapi]>=1.2.10, <2.0",
|
||||
"shortid",
|
||||
|
@ -189,7 +189,7 @@ setup(
|
|||
"playwright": ["playwright>=1.37.0, <2"],
|
||||
"postgres": ["psycopg2-binary==2.9.6"],
|
||||
"presto": ["pyhive[presto]>=0.6.5"],
|
||||
"trino": ["trino>=0.324.0"],
|
||||
"trino": ["trino>=0.328.0"],
|
||||
"prophet": ["prophet>=1.1.5, <2"],
|
||||
"redshift": ["sqlalchemy-redshift>=0.8.1, <0.9"],
|
||||
"rockset": ["rockset-sqlalchemy>=0.0.1, <1"],
|
||||
|
|
|
@ -40,10 +40,15 @@ embedDashboard({
|
|||
supersetDomain: "https://superset.example.com",
|
||||
mountPoint: document.getElementById("my-superset-container"), // any html element that can contain an iframe
|
||||
fetchGuestToken: () => fetchGuestTokenFromBackend(),
|
||||
dashboardUiConfig: { // dashboard UI config: hideTitle, hideTab, hideChartControls, filters.visible, filters.expanded (optional)
|
||||
dashboardUiConfig: { // dashboard UI config: hideTitle, hideTab, hideChartControls, filters.visible, filters.expanded (optional), urlParams (optional)
|
||||
hideTitle: true,
|
||||
filters: {
|
||||
expanded: true,
|
||||
},
|
||||
urlParams: {
|
||||
foo: 'value1',
|
||||
bar: 'value2',
|
||||
// ...
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@superset-ui/embedded-sdk",
|
||||
"version": "0.1.0-alpha.10",
|
||||
"version": "0.1.0-alpha.11",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@superset-ui/embedded-sdk",
|
||||
"version": "0.1.0-alpha.10",
|
||||
"version": "0.1.0-alpha.11",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@superset-ui/switchboard": "^0.18.26-0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@superset-ui/embedded-sdk",
|
||||
"version": "0.1.0-alpha.10",
|
||||
"version": "0.1.0-alpha.11",
|
||||
"description": "SDK for embedding resources from Superset into your own application",
|
||||
"access": "public",
|
||||
"keywords": [
|
||||
|
|
|
@ -42,6 +42,9 @@ export type UiConfigType = {
|
|||
visible?: boolean
|
||||
expanded?: boolean
|
||||
}
|
||||
urlParams?: {
|
||||
[key: string]: any
|
||||
}
|
||||
}
|
||||
|
||||
export type EmbedDashboardParams = {
|
||||
|
@ -112,14 +115,15 @@ export async function embedDashboard({
|
|||
async function mountIframe(): Promise<Switchboard> {
|
||||
return new Promise(resolve => {
|
||||
const iframe = document.createElement('iframe');
|
||||
const dashboardConfig = dashboardUiConfig ? `?uiConfig=${calculateConfig()}` : ""
|
||||
const dashboardConfigUrlParams = dashboardUiConfig ? {uiConfig: `${calculateConfig()}`} : undefined;
|
||||
const filterConfig = dashboardUiConfig?.filters || {}
|
||||
const filterConfigKeys = Object.keys(filterConfig)
|
||||
const filterConfigUrlParams = filterConfigKeys.length > 0
|
||||
? "&"
|
||||
+ filterConfigKeys
|
||||
.map(key => DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY[key] + '=' + filterConfig[key]).join('&')
|
||||
: ""
|
||||
const filterConfigUrlParams = Object.fromEntries(filterConfigKeys.map(
|
||||
key => [DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY[key], filterConfig[key]]))
|
||||
|
||||
// Allow url query parameters from dashboardUiConfig.urlParams to override the ones from filterConfig
|
||||
const urlParams = {...dashboardConfigUrlParams, ...filterConfigUrlParams, ...dashboardUiConfig?.urlParams}
|
||||
const urlParamsString = Object.keys(urlParams).length ? '?' + new URLSearchParams(urlParams).toString() : ''
|
||||
|
||||
// set up the iframe's sandbox configuration
|
||||
iframe.sandbox.add("allow-same-origin"); // needed for postMessage to work
|
||||
|
@ -153,7 +157,7 @@ export async function embedDashboard({
|
|||
resolve(new Switchboard({ port: ourPort, name: 'superset-embedded-sdk', debug }));
|
||||
});
|
||||
|
||||
iframe.src = `${supersetDomain}/embedded/${id}${dashboardConfig}${filterConfigUrlParams}`;
|
||||
iframe.src = `${supersetDomain}/embedded/${id}${urlParamsString}`;
|
||||
//@ts-ignore
|
||||
mountPoint.replaceChildren(iframe);
|
||||
log('placed the iframe')
|
||||
|
|
|
@ -173,6 +173,13 @@ describe('Charts list', () => {
|
|||
orderAlphabetical();
|
||||
cy.getBySel('styled-card').first().contains('% Rural');
|
||||
});
|
||||
|
||||
it('should preserve other filters when sorting', () => {
|
||||
cy.getBySel('styled-card').should('have.length', 25);
|
||||
setFilter('Type', 'Big Number');
|
||||
setFilter('Sort', 'Least recently modified');
|
||||
cy.getBySel('styled-card').should('have.length', 3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('common actions', () => {
|
||||
|
|
|
@ -759,7 +759,7 @@ describe('Dashboard edit', () => {
|
|||
cy.getBySel('dashboard-markdown-editor').click().type('Test resize');
|
||||
|
||||
resize(
|
||||
'[data-test="dashboard-markdown-editor"] .resizable-container span div:last-child',
|
||||
'[data-test="dashboard-markdown-editor"] .resizable-container div.resizable-container-handle--bottom + div',
|
||||
).to(500, 600);
|
||||
|
||||
cy.getBySel('dashboard-markdown-editor').contains('Test resize');
|
||||
|
|
|
@ -117,6 +117,13 @@ describe('Dashboards list', () => {
|
|||
orderAlphabetical();
|
||||
cy.getBySel('styled-card').first().contains('Supported Charts Dashboard');
|
||||
});
|
||||
|
||||
it('should preserve other filters when sorting', () => {
|
||||
cy.getBySel('styled-card').should('have.length', 5);
|
||||
setFilter('Status', 'Published');
|
||||
setFilter('Sort', 'Least recently modified');
|
||||
cy.getBySel('styled-card').should('have.length', 3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('common actions', () => {
|
||||
|
|
|
@ -210,7 +210,7 @@ describe('Time range filter', () => {
|
|||
.click()
|
||||
.then(() => {
|
||||
cy.get('.ant-radio-group').children().its('length').should('eq', 5);
|
||||
cy.get('.ant-radio-checked + span').contains('last year');
|
||||
cy.get('.ant-radio-checked + span').contains('Last year');
|
||||
cy.get('[data-test=cancel-button]').click();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8068,9 +8068,9 @@
|
|||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||
},
|
||||
"node_modules/ip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
|
||||
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ=="
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
|
@ -10984,9 +10984,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/socks/node_modules/ip": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
|
||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
|
||||
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ=="
|
||||
},
|
||||
"node_modules/sonic-boom": {
|
||||
"version": "1.4.1",
|
||||
|
@ -18391,9 +18391,9 @@
|
|||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
|
||||
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ=="
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
|
@ -20518,9 +20518,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"ip": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
|
||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
|
||||
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -43,7 +43,6 @@
|
|||
"build-instrumented": "cross-env NODE_ENV=production BABEL_ENV=instrumented webpack --mode=production --color",
|
||||
"build-storybook": "storybook build",
|
||||
"check-translation": "prettier --check ../superset/translations/**/LC_MESSAGES/*.json",
|
||||
"chromatic": "npx chromatic --skip 'dependabot/**' --only-changed",
|
||||
"clean-translation": "prettier --write ../superset/translations/**/LC_MESSAGES/*.json",
|
||||
"core:cover": "cross-env NODE_ENV=test jest --coverage --coverageThreshold='{\"global\":{\"statements\":100,\"branches\":100,\"functions\":100,\"lines\":100}}' --collectCoverageFrom='[\"packages/**/src/**/*.{js,ts}\", \"!packages/superset-ui-demo/**/*\"]' packages",
|
||||
"cover": "cross-env NODE_ENV=test jest --coverage",
|
||||
|
@ -57,7 +56,6 @@
|
|||
"plugins:build": "node ./scripts/build.js",
|
||||
"plugins:build-assets": "node ./scripts/copyAssets.js",
|
||||
"plugins:build-storybook": "cd packages/superset-ui-demo && npm run build-storybook",
|
||||
"plugins:chromatic": "cd packages/superset-ui-demo && npm run chromatic",
|
||||
"plugins:create-conventional-version": "npm run prune && lerna version --conventional-commits --create-release github --no-private --yes",
|
||||
"plugins:create-minor-version": "npm run prune && lerna version minor --no-private --yes",
|
||||
"plugins:create-patch-version": "npm run prune && lerna version patch --no-private --yes",
|
||||
|
@ -163,7 +161,7 @@
|
|||
"polished": "^3.7.2",
|
||||
"prop-types": "^15.7.2",
|
||||
"query-string": "^6.13.7",
|
||||
"re-resizable": "^6.6.1",
|
||||
"re-resizable": "^6.9.11",
|
||||
"react": "^16.13.1",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-checkbox-tree": "^1.8.0",
|
||||
|
@ -178,7 +176,7 @@
|
|||
"react-js-cron": "^2.1.2",
|
||||
"react-json-tree": "^0.17.0",
|
||||
"react-jsonschema-form": "^1.8.1",
|
||||
"react-lines-ellipsis": "^0.15.0",
|
||||
"react-lines-ellipsis": "^0.15.4",
|
||||
"react-loadable": "^5.5.0",
|
||||
"react-redux": "^7.2.9",
|
||||
"react-resize-detector": "^7.1.2",
|
||||
|
@ -283,7 +281,6 @@
|
|||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-jsx-remove-data-test-id": "^2.1.3",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"chromatic": "^6.7.4",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"cross-env": "^5.2.1",
|
||||
"css-loader": "^6.8.1",
|
||||
|
|
|
@ -37,3 +37,4 @@ export * from './math-expression';
|
|||
export * from './ui-overrides';
|
||||
export * from './hooks';
|
||||
export * from './currency-format';
|
||||
export * from './time-comparison';
|
||||
|
|
|
@ -115,11 +115,11 @@ export default function makeApi<
|
|||
jsonPayload: undefined as JsonObject | undefined,
|
||||
};
|
||||
if (requestType === 'search') {
|
||||
requestConfig.searchParams = payload as URLSearchParams;
|
||||
requestConfig.searchParams = payload as unknown as URLSearchParams;
|
||||
} else if (requestType === 'rison') {
|
||||
requestConfig.endpoint = `${endpoint}?q=${rison.encode(payload)}`;
|
||||
} else if (requestType === 'form') {
|
||||
requestConfig.postPayload = payload as FormData;
|
||||
requestConfig.postPayload = payload as unknown as FormData;
|
||||
} else {
|
||||
requestConfig.jsonPayload = payload as JsonObject;
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ export type QueryObjectExtras = Partial<{
|
|||
time_grain_sqla?: TimeGranularity;
|
||||
/** WHERE condition */
|
||||
where?: string;
|
||||
/** Instant Time Comparison */
|
||||
instant_time_comparison_range?: string;
|
||||
}>;
|
||||
|
||||
export type ResidualQueryObjectData = {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
## @superset-ui/core/time-comparison
|
||||
|
||||
This is a collection of methods used to support Time Comparison in charts.
|
||||
|
||||
#### Example usage
|
||||
|
||||
```js
|
||||
import { getComparisonTimeRangeInfo } from '@superset-ui/core';
|
||||
const { since, until } = getComparisonTimeRangeInfo(
|
||||
adhocFilters,
|
||||
extraFormData,
|
||||
);
|
||||
console.log(adhocFilters, extraFormData);
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
import { ComparisonTimeRangeType } from '@superset-ui/core';
|
||||
ComparisonTimeRangeType.Custom; // 'c'
|
||||
ComparisonTimeRangeType.InheritRange; // 'r'
|
||||
```
|
||||
|
||||
#### API
|
||||
|
||||
`fn(args)`
|
||||
|
||||
- Do something
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { QueryFormData } from '../query';
|
||||
import { AdhocFilter } from '../types';
|
||||
|
||||
/**
|
||||
* This method is used to get the query filters to be applied to the comparison query after
|
||||
* overriding the time range in case an extra form data is provided.
|
||||
* For example when rendering a chart that uses time comparison in a dashboard with time filters.
|
||||
* @param formData - the form data
|
||||
* @param extraFormData - the extra form data
|
||||
* @returns the query filters to be applied to the comparison query
|
||||
*/
|
||||
export const getComparisonFilters = (
|
||||
formData: QueryFormData,
|
||||
extraFormData: any,
|
||||
): AdhocFilter[] => {
|
||||
const timeFilterIndex: number =
|
||||
formData.adhoc_filters?.findIndex(
|
||||
filter => 'operator' in filter && filter.operator === 'TEMPORAL_RANGE',
|
||||
) ?? -1;
|
||||
|
||||
const timeFilter: AdhocFilter | null =
|
||||
timeFilterIndex !== -1 && formData.adhoc_filters
|
||||
? formData.adhoc_filters[timeFilterIndex]
|
||||
: null;
|
||||
|
||||
if (
|
||||
timeFilter &&
|
||||
'comparator' in timeFilter &&
|
||||
typeof timeFilter.comparator === 'string'
|
||||
) {
|
||||
if (extraFormData?.time_range) {
|
||||
timeFilter.comparator = extraFormData.time_range;
|
||||
}
|
||||
}
|
||||
|
||||
const comparisonQueryFilter = timeFilter ? [timeFilter] : [];
|
||||
|
||||
const otherFilters = formData.adhoc_filters?.filter(
|
||||
(_value: any, index: number) => timeFilterIndex !== index,
|
||||
);
|
||||
const comparisonQueryFilters = otherFilters
|
||||
? [...comparisonQueryFilter, ...otherFilters]
|
||||
: comparisonQueryFilter;
|
||||
|
||||
return comparisonQueryFilters;
|
||||
};
|
||||
|
||||
export default getComparisonFilters;
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { QueryFormData } from '../query';
|
||||
import { getComparisonFilters } from './getComparisonFilters';
|
||||
import { ComparisonTimeRangeType } from './types';
|
||||
|
||||
/**
|
||||
* This is the main function to get the comparison info. It will return the formData
|
||||
* that a viz can use to query the comparison data and the time shift text needed for
|
||||
* the comparison time range based on the control value.
|
||||
* @param formData
|
||||
* @param timeComparison
|
||||
* @param extraFormData
|
||||
* @returns the processed formData
|
||||
*/
|
||||
|
||||
export const getComparisonInfo = (
|
||||
formData: QueryFormData,
|
||||
timeComparison: string,
|
||||
extraFormData: any,
|
||||
): QueryFormData => {
|
||||
let comparisonFormData;
|
||||
|
||||
if (timeComparison !== ComparisonTimeRangeType.Custom) {
|
||||
comparisonFormData = {
|
||||
...formData,
|
||||
adhoc_filters: getComparisonFilters(formData, extraFormData),
|
||||
extra_form_data: {
|
||||
...extraFormData,
|
||||
time_range: undefined,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// This is when user selects Custom as time comparison
|
||||
comparisonFormData = {
|
||||
...formData,
|
||||
adhoc_filters: formData.adhoc_custom,
|
||||
extra_form_data: {
|
||||
...extraFormData,
|
||||
time_range: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return comparisonFormData;
|
||||
};
|
||||
|
||||
export default getComparisonInfo;
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './types';
|
||||
|
||||
export { default as getComparisonInfo } from './getComparisonInfo';
|
||||
export { default as getComparisonFilters } from './getComparisonFilters';
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -16,12 +16,15 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export { default as PopKPIPlugin } from './plugin';
|
||||
|
||||
/**
|
||||
* Note: this file exports the default export from PopKPI.tsx.
|
||||
* If you want to export multiple visualization modules, you will need to
|
||||
* either add additional plugin folders (similar in structure to ./plugin)
|
||||
* OR export multiple instances of `ChartPlugin` extensions in ./plugin/index.ts
|
||||
* which in turn load exports from CustomViz.tsx
|
||||
* Supported comparison time ranges
|
||||
*/
|
||||
|
||||
export enum ComparisonTimeRangeType {
|
||||
Custom = 'c',
|
||||
InheritedRange = 'r',
|
||||
Month = 'm',
|
||||
Week = 'w',
|
||||
Year = 'y',
|
||||
}
|
|
@ -24,3 +24,4 @@ export { default as validateNumber } from './validateNumber';
|
|||
export { default as validateNonEmpty } from './validateNonEmpty';
|
||||
export { default as validateMaxValue } from './validateMaxValue';
|
||||
export { default as validateMapboxStylesUrl } from './validateMapboxStylesUrl';
|
||||
export { default as validateTimeComparisonRangeValues } from './validateTimeComparisonRangeValues';
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ComparisonTimeRangeType } from '../time-comparison';
|
||||
import { t } from '../translation';
|
||||
import { ensureIsArray } from '../utils';
|
||||
|
||||
export const validateTimeComparisonRangeValues = (
|
||||
timeRangeValue?: any,
|
||||
controlValue?: any,
|
||||
) => {
|
||||
const isCustomTimeRange = timeRangeValue === ComparisonTimeRangeType.Custom;
|
||||
const isCustomControlEmpty = controlValue?.every(
|
||||
(val: any) => ensureIsArray(val).length === 0,
|
||||
);
|
||||
return isCustomTimeRange && isCustomControlEmpty
|
||||
? [t('Filters for comparison must have a value')]
|
||||
: [];
|
||||
};
|
||||
|
||||
export default validateTimeComparisonRangeValues;
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { getComparisonFilters } from '@superset-ui/core';
|
||||
|
||||
const form_data = {
|
||||
datasource: '22__table',
|
||||
viz_type: 'pop_kpi',
|
||||
slice_id: 97,
|
||||
url_params: {
|
||||
form_data_key:
|
||||
'TaBakyDiAx2VsQ47gLmlsJKeN4foqnoxUKdbQrM05qnKMRjO9PDe42iZN1oxmxZ8',
|
||||
save_action: 'overwrite',
|
||||
slice_id: '97',
|
||||
},
|
||||
metrics: ['count'],
|
||||
adhoc_filters: [
|
||||
{
|
||||
clause: 'WHERE',
|
||||
comparator: '2004-02-16 : 2024-02-16',
|
||||
datasourceWarning: false,
|
||||
expressionType: 'SIMPLE',
|
||||
filterOptionName: 'filter_8274fo9pogn_ihi8x28o7a',
|
||||
isExtra: false,
|
||||
isNew: false,
|
||||
operator: 'TEMPORAL_RANGE',
|
||||
sqlExpression: null,
|
||||
subject: 'order_date',
|
||||
} as any,
|
||||
],
|
||||
time_comparison: 'y',
|
||||
adhoc_custom: [
|
||||
{
|
||||
clause: 'WHERE',
|
||||
comparator: 'No filter',
|
||||
expressionType: 'SIMPLE',
|
||||
operator: 'TEMPORAL_RANGE',
|
||||
subject: 'order_date',
|
||||
},
|
||||
],
|
||||
row_limit: 10000,
|
||||
y_axis_format: 'SMART_NUMBER',
|
||||
header_font_size: 60,
|
||||
subheader_font_size: 26,
|
||||
comparison_color_enabled: true,
|
||||
extra_form_data: {},
|
||||
force: false,
|
||||
result_format: 'json',
|
||||
result_type: 'full',
|
||||
};
|
||||
|
||||
const mockExtraFormData = {
|
||||
time_range: 'new and cool range from extra form data',
|
||||
};
|
||||
|
||||
describe('getComparisonFilters', () => {
|
||||
it('Keeps the original adhoc_filters since no extra data was passed', () => {
|
||||
const result = getComparisonFilters(form_data, {});
|
||||
|
||||
expect(result).toEqual(form_data.adhoc_filters);
|
||||
});
|
||||
|
||||
it('Updates the time_range if the filter if extra form data is passed', () => {
|
||||
const result = getComparisonFilters(form_data, mockExtraFormData);
|
||||
|
||||
const expectedFilters = [
|
||||
{
|
||||
clause: 'WHERE',
|
||||
comparator: 'new and cool range from extra form data',
|
||||
datasourceWarning: false,
|
||||
expressionType: 'SIMPLE',
|
||||
filterOptionName: 'filter_8274fo9pogn_ihi8x28o7a',
|
||||
isExtra: false,
|
||||
isNew: false,
|
||||
operator: 'TEMPORAL_RANGE',
|
||||
sqlExpression: null,
|
||||
subject: 'order_date',
|
||||
} as any,
|
||||
];
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(expectedFilters[0]);
|
||||
});
|
||||
|
||||
it('handles no time range filters', () => {
|
||||
const result = getComparisonFilters(
|
||||
{
|
||||
...form_data,
|
||||
adhoc_filters: [
|
||||
{
|
||||
expressionType: 'SIMPLE',
|
||||
subject: 'address_line1',
|
||||
operator: 'IN',
|
||||
comparator: ['7734 Strong St.'],
|
||||
clause: 'WHERE',
|
||||
isExtra: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
const expectedFilters = [
|
||||
{
|
||||
expressionType: 'SIMPLE',
|
||||
subject: 'address_line1',
|
||||
operator: 'IN',
|
||||
comparator: ['7734 Strong St.'],
|
||||
clause: 'WHERE',
|
||||
isExtra: false,
|
||||
},
|
||||
];
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(expectedFilters[0]);
|
||||
});
|
||||
|
||||
it('If adhoc_filter is undefrined the code wont break', () => {
|
||||
const result = getComparisonFilters(
|
||||
{
|
||||
...form_data,
|
||||
adhoc_filters: undefined,
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { getComparisonInfo, ComparisonTimeRangeType } from '@superset-ui/core';
|
||||
|
||||
const form_data = {
|
||||
datasource: '22__table',
|
||||
viz_type: 'pop_kpi',
|
||||
slice_id: 97,
|
||||
url_params: {
|
||||
form_data_key:
|
||||
'TaBakyDiAx2VsQ47gLmlsJKeN4foqnoxUKdbQrM05qnKMRjO9PDe42iZN1oxmxZ8',
|
||||
save_action: 'overwrite',
|
||||
slice_id: '97',
|
||||
},
|
||||
metrics: ['count'],
|
||||
adhoc_filters: [
|
||||
{
|
||||
clause: 'WHERE',
|
||||
comparator: '2004-02-16 : 2024-02-16',
|
||||
datasourceWarning: false,
|
||||
expressionType: 'SIMPLE',
|
||||
filterOptionName: 'filter_8274fo9pogn_ihi8x28o7a',
|
||||
isExtra: false,
|
||||
isNew: false,
|
||||
operator: 'TEMPORAL_RANGE',
|
||||
sqlExpression: null,
|
||||
subject: 'order_date',
|
||||
} as any,
|
||||
],
|
||||
time_comparison: 'y',
|
||||
adhoc_custom: [
|
||||
{
|
||||
clause: 'WHERE',
|
||||
comparator: 'No filter',
|
||||
expressionType: 'SIMPLE',
|
||||
operator: 'TEMPORAL_RANGE',
|
||||
subject: 'order_date',
|
||||
},
|
||||
],
|
||||
row_limit: 10000,
|
||||
y_axis_format: 'SMART_NUMBER',
|
||||
header_font_size: 60,
|
||||
subheader_font_size: 26,
|
||||
comparison_color_enabled: true,
|
||||
extra_form_data: {},
|
||||
force: false,
|
||||
result_format: 'json',
|
||||
result_type: 'full',
|
||||
};
|
||||
|
||||
const mockExtraFormData = {
|
||||
time_range: 'new and cool range from extra form data',
|
||||
};
|
||||
|
||||
describe('getComparisonInfo', () => {
|
||||
it('Keeps the original adhoc_filters since no extra data was passed', () => {
|
||||
const resultFormData = getComparisonInfo(
|
||||
form_data,
|
||||
ComparisonTimeRangeType.Year,
|
||||
{},
|
||||
);
|
||||
expect(resultFormData).toEqual(form_data);
|
||||
});
|
||||
|
||||
it('Updates the time_range of the adhoc_filters when extra form data is passed', () => {
|
||||
const resultFormData = getComparisonInfo(
|
||||
form_data,
|
||||
ComparisonTimeRangeType.Month,
|
||||
mockExtraFormData,
|
||||
);
|
||||
|
||||
const expectedFilters = [
|
||||
{
|
||||
clause: 'WHERE',
|
||||
comparator: 'new and cool range from extra form data',
|
||||
datasourceWarning: false,
|
||||
expressionType: 'SIMPLE',
|
||||
filterOptionName: 'filter_8274fo9pogn_ihi8x28o7a',
|
||||
isExtra: false,
|
||||
isNew: false,
|
||||
operator: 'TEMPORAL_RANGE',
|
||||
sqlExpression: null,
|
||||
subject: 'order_date',
|
||||
} as any,
|
||||
];
|
||||
|
||||
expect(resultFormData.adhoc_filters?.length).toEqual(1);
|
||||
expect(resultFormData.adhoc_filters).toEqual(expectedFilters);
|
||||
});
|
||||
|
||||
it('handles no time range filters', () => {
|
||||
const resultFormData = getComparisonInfo(
|
||||
{
|
||||
...form_data,
|
||||
adhoc_filters: [
|
||||
{
|
||||
expressionType: 'SIMPLE',
|
||||
subject: 'address_line1',
|
||||
operator: 'IN',
|
||||
comparator: ['7734 Strong St.'],
|
||||
clause: 'WHERE',
|
||||
isExtra: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
ComparisonTimeRangeType.Week,
|
||||
{},
|
||||
);
|
||||
|
||||
const expectedFilters = [
|
||||
{
|
||||
expressionType: 'SIMPLE',
|
||||
subject: 'address_line1',
|
||||
operator: 'IN',
|
||||
comparator: ['7734 Strong St.'],
|
||||
clause: 'WHERE',
|
||||
isExtra: false,
|
||||
},
|
||||
];
|
||||
expect(resultFormData.adhoc_filters?.length).toEqual(1);
|
||||
expect(resultFormData.adhoc_filters?.[0]).toEqual(expectedFilters[0]);
|
||||
});
|
||||
|
||||
it('If adhoc_filter is undefrined the code wont break', () => {
|
||||
const resultFormData = getComparisonInfo(
|
||||
{
|
||||
...form_data,
|
||||
adhoc_filters: undefined,
|
||||
},
|
||||
ComparisonTimeRangeType.InheritedRange,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(resultFormData.adhoc_filters?.length).toEqual(0);
|
||||
expect(resultFormData.adhoc_filters).toEqual([]);
|
||||
});
|
||||
|
||||
it('Handles the custom time filters and return the correct time shift text', () => {
|
||||
const resultFormData = getComparisonInfo(
|
||||
form_data,
|
||||
ComparisonTimeRangeType.Custom,
|
||||
{},
|
||||
);
|
||||
|
||||
const expectedFilters = [
|
||||
{
|
||||
clause: 'WHERE',
|
||||
comparator: 'No filter',
|
||||
expressionType: 'SIMPLE',
|
||||
operator: 'TEMPORAL_RANGE',
|
||||
subject: 'order_date',
|
||||
},
|
||||
];
|
||||
expect(resultFormData.adhoc_filters?.length).toEqual(1);
|
||||
expect(resultFormData.adhoc_filters).toEqual(expectedFilters);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ComparisonTimeRangeType,
|
||||
getComparisonFilters,
|
||||
getComparisonInfo,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
describe('index', () => {
|
||||
it('exports modules', () => {
|
||||
[ComparisonTimeRangeType, getComparisonFilters, getComparisonInfo].forEach(
|
||||
x => expect(x).toBeDefined(),
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ComparisonTimeRangeType,
|
||||
validateTimeComparisonRangeValues,
|
||||
} from '@superset-ui/core';
|
||||
import './setup';
|
||||
|
||||
describe('validateTimeComparisonRangeValues()', () => {
|
||||
it('returns the warning message if invalid', () => {
|
||||
expect(
|
||||
validateTimeComparisonRangeValues(ComparisonTimeRangeType.Custom, []),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
validateTimeComparisonRangeValues(
|
||||
ComparisonTimeRangeType.Custom,
|
||||
undefined,
|
||||
),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
validateTimeComparisonRangeValues(ComparisonTimeRangeType.Custom, null),
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('returns empty array if the input is valid', () => {
|
||||
expect(
|
||||
validateTimeComparisonRangeValues(ComparisonTimeRangeType.Year, []),
|
||||
).toEqual([]);
|
||||
expect(
|
||||
validateTimeComparisonRangeValues(
|
||||
ComparisonTimeRangeType.Year,
|
||||
undefined,
|
||||
),
|
||||
).toEqual([]);
|
||||
expect(
|
||||
validateTimeComparisonRangeValues(ComparisonTimeRangeType.Year, null),
|
||||
).toEqual([]);
|
||||
expect(
|
||||
validateTimeComparisonRangeValues(ComparisonTimeRangeType.Custom, [1]),
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
|
@ -62,7 +62,6 @@
|
|||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@storybook/react-webpack5": "^7.6.13",
|
||||
"babel-loader": "^8.1.0",
|
||||
"chromatic": "^5.4.0",
|
||||
"fork-ts-checker-webpack-plugin": "^5.0.7",
|
||||
"ts-loader": "^7.0.4",
|
||||
"typescript": "^4.5.4"
|
||||
|
|
|
@ -90,9 +90,6 @@ export default function createQueryStory({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
story.parameters = {
|
||||
chromatic: { disable: true },
|
||||
};
|
||||
story.args = {
|
||||
host: 'localhost:8088',
|
||||
mode: keys[0],
|
||||
|
|
|
@ -40,7 +40,7 @@ export default {
|
|||
],
|
||||
};
|
||||
|
||||
export const configureCORS = ({
|
||||
export const ConfigureCORS = ({
|
||||
host,
|
||||
selectEndpoint,
|
||||
customEndpoint,
|
||||
|
@ -84,18 +84,14 @@ export const configureCORS = ({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
configureCORS.parameters = {
|
||||
chromatic: { disable: true },
|
||||
};
|
||||
configureCORS.args = {
|
||||
ConfigureCORS.args = {
|
||||
host: 'localhost:8088',
|
||||
selectEndpoint: '/api/v1/chart/data',
|
||||
customEndpoint: '',
|
||||
methodOption: 'POST', // TODO disable when custonEndpoint and selectEndpoint are empty
|
||||
postPayloadContents: JSON.stringify({ form_data: bigNumberFormData }),
|
||||
};
|
||||
configureCORS.argTypes = {
|
||||
ConfigureCORS.argTypes = {
|
||||
host: {
|
||||
control: 'text',
|
||||
description: 'Set Superset App host for CORS request',
|
||||
|
@ -122,4 +118,4 @@ configureCORS.argTypes = {
|
|||
description: 'Set POST payload contents',
|
||||
},
|
||||
};
|
||||
configureCORS.storyName = 'Verify CORS';
|
||||
ConfigureCORS.storyName = 'Verify CORS';
|
||||
|
|
|
@ -177,15 +177,12 @@ function Heatmap(element, props) {
|
|||
}
|
||||
}
|
||||
|
||||
function ordScale(k, rangeBands, sortMethod) {
|
||||
function ordScale(k, rangeBands, sortMethod, formatter) {
|
||||
let domain = {};
|
||||
const actualKeys = {}; // hack to preserve type of keys when number
|
||||
records.forEach(d => {
|
||||
domain[d[k]] = (domain[d[k]] || 0) + d.v;
|
||||
actualKeys[d[k]] = d[k];
|
||||
});
|
||||
// Not using object.keys() as it converts to strings
|
||||
const keys = Object.keys(actualKeys).map(s => actualKeys[s]);
|
||||
const keys = Object.keys(domain).map(k => formatter(k));
|
||||
if (sortMethod === 'alpha_asc') {
|
||||
domain = keys.sort(cmp);
|
||||
} else if (sortMethod === 'alpha_desc') {
|
||||
|
@ -252,10 +249,10 @@ function Heatmap(element, props) {
|
|||
|
||||
const fp = getNumberFormatter(NumberFormats.PERCENT_2_POINT);
|
||||
|
||||
const xScale = ordScale('x', null, sortXAxis);
|
||||
const yScale = ordScale('y', null, sortYAxis);
|
||||
const xRbScale = ordScale('x', [0, hmWidth], sortXAxis);
|
||||
const yRbScale = ordScale('y', [hmHeight, 0], sortYAxis);
|
||||
const xScale = ordScale('x', null, sortXAxis, xAxisFormatter);
|
||||
const yScale = ordScale('y', null, sortYAxis, yAxisFormatter);
|
||||
const xRbScale = ordScale('x', [0, hmWidth], sortXAxis, xAxisFormatter);
|
||||
const yRbScale = ordScale('y', [hmHeight, 0], sortYAxis, yAxisFormatter);
|
||||
const X = 0;
|
||||
const Y = 1;
|
||||
const heatmapDim = [xRbScale.domain().length, yRbScale.domain().length];
|
||||
|
|
|
@ -57,11 +57,15 @@ export default function transformProps(chartProps) {
|
|||
const xAxisFormatter =
|
||||
coltypes[0] === GenericDataType.Temporal
|
||||
? getTimeFormatter(timeFormat)
|
||||
: String;
|
||||
: coltypes[0] === GenericDataType.Numeric
|
||||
? Number
|
||||
: String;
|
||||
const yAxisFormatter =
|
||||
coltypes[1] === GenericDataType.Temporal
|
||||
? getTimeFormatter(timeFormat)
|
||||
: String;
|
||||
: coltypes[1] === GenericDataType.Numeric
|
||||
? Number
|
||||
: String;
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React, { createRef, useMemo } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { css, styled, t, useTheme } from '@superset-ui/core';
|
||||
import { Tooltip } from '@superset-ui/chart-controls';
|
||||
import {
|
||||
|
@ -24,24 +24,33 @@ import {
|
|||
PopKPIComparisonValueStyleProps,
|
||||
PopKPIProps,
|
||||
} from './types';
|
||||
import { useOverflowDetection } from './useOverflowDetection';
|
||||
|
||||
const NumbersContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const ComparisonValue = styled.div<PopKPIComparisonValueStyleProps>`
|
||||
${({ theme, subheaderFontSize }) => `
|
||||
font-weight: ${theme.typography.weights.light};
|
||||
width: 33%;
|
||||
display: table-cell;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: ${subheaderFontSize || 20}px;
|
||||
text-align: center;
|
||||
flex: 1 1 0px;
|
||||
`}
|
||||
`;
|
||||
|
||||
const SymbolWrapper = styled.div<PopKPIComparisonSymbolStyleProps>`
|
||||
const SymbolWrapper = styled.span<PopKPIComparisonSymbolStyleProps>`
|
||||
${({ theme, backgroundColor, textColor }) => `
|
||||
background-color: ${backgroundColor};
|
||||
color: ${textColor};
|
||||
padding: ${theme.gridUnit}px ${theme.gridUnit * 2}px;
|
||||
border-radius: ${theme.gridUnit * 2}px;
|
||||
display: inline-block;
|
||||
margin-right: ${theme.gridUnit}px;
|
||||
`}
|
||||
`;
|
||||
|
@ -61,25 +70,23 @@ export default function PopKPI(props: PopKPIProps) {
|
|||
comparatorText,
|
||||
} = props;
|
||||
|
||||
const rootElem = createRef<HTMLDivElement>();
|
||||
const theme = useTheme();
|
||||
|
||||
const flexGap = theme.gridUnit * 5;
|
||||
const wrapperDivStyles = css`
|
||||
font-family: ${theme.typography.families.sansSerif};
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: ${theme.gridUnit * 4}px;
|
||||
border-radius: ${theme.gridUnit * 2}px;
|
||||
align-items: center;
|
||||
height: ${height}px;
|
||||
width: ${width}px;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const bigValueContainerStyles = css`
|
||||
font-size: ${headerFontSize || 60}px;
|
||||
font-weight: ${theme.typography.weights.normal};
|
||||
text-align: center;
|
||||
margin-bottom: ${theme.gridUnit * 4}px;
|
||||
`;
|
||||
|
||||
const getArrowIndicatorColor = () => {
|
||||
|
@ -135,29 +142,59 @@ export default function PopKPI(props: PopKPIProps) {
|
|||
tooltipText: t('Percentage difference between the time periods'),
|
||||
},
|
||||
],
|
||||
[prevNumber, valueDifference, percentDifferenceFormattedString],
|
||||
[
|
||||
comparatorText,
|
||||
prevNumber,
|
||||
valueDifference,
|
||||
percentDifferenceFormattedString,
|
||||
],
|
||||
);
|
||||
|
||||
const { isOverflowing, symbolContainerRef, wrapperRef } =
|
||||
useOverflowDetection(flexGap);
|
||||
|
||||
return (
|
||||
<div ref={rootElem} css={wrapperDivStyles}>
|
||||
<div css={bigValueContainerStyles}>
|
||||
{bigNumber}
|
||||
{percentDifferenceNumber !== 0 && (
|
||||
<span css={arrowIndicatorStyle}>
|
||||
{percentDifferenceNumber > 0 ? '↑' : '↓'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
css={css`
|
||||
width: 100%;
|
||||
display: table;
|
||||
`}
|
||||
<div css={wrapperDivStyles} ref={wrapperRef}>
|
||||
<NumbersContainer
|
||||
css={
|
||||
isOverflowing &&
|
||||
css`
|
||||
width: fit-content;
|
||||
margin: auto;
|
||||
align-items: flex-start;
|
||||
`
|
||||
}
|
||||
>
|
||||
<div css={bigValueContainerStyles}>
|
||||
{bigNumber}
|
||||
{percentDifferenceNumber !== 0 && (
|
||||
<span css={arrowIndicatorStyle}>
|
||||
{percentDifferenceNumber > 0 ? '↑' : '↓'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
css={css`
|
||||
display: table-row;
|
||||
`}
|
||||
css={[
|
||||
css`
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
gap: ${flexGap}px;
|
||||
min-width: 0;
|
||||
flex-shrink: 1;
|
||||
`,
|
||||
isOverflowing
|
||||
? css`
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
width: fit-content;
|
||||
`
|
||||
: css`
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
`,
|
||||
]}
|
||||
ref={symbolContainerRef}
|
||||
>
|
||||
{SYMBOLS_WITH_VALUES.map((symbol_with_value, index) => (
|
||||
<ComparisonValue
|
||||
|
@ -182,7 +219,7 @@ export default function PopKPI(props: PopKPIProps) {
|
|||
</ComparisonValue>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</NumbersContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import {
|
||||
buildQueryContext,
|
||||
getComparisonInfo,
|
||||
ComparisonTimeRangeType,
|
||||
QueryFormData,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
export default function buildQuery(formData: QueryFormData) {
|
||||
const {
|
||||
cols: groupby,
|
||||
time_comparison: timeComparison,
|
||||
extra_form_data: extraFormData,
|
||||
} = formData;
|
||||
|
||||
const queryContextA = buildQueryContext(formData, baseQueryObject => [
|
||||
{
|
||||
...baseQueryObject,
|
||||
groupby,
|
||||
},
|
||||
]);
|
||||
|
||||
const comparisonFormData = getComparisonInfo(
|
||||
formData,
|
||||
timeComparison,
|
||||
extraFormData,
|
||||
);
|
||||
|
||||
const queryContextB = buildQueryContext(
|
||||
comparisonFormData,
|
||||
baseQueryObject => [
|
||||
{
|
||||
...baseQueryObject,
|
||||
groupby,
|
||||
extras: {
|
||||
...baseQueryObject.extras,
|
||||
instant_time_comparison_range:
|
||||
timeComparison !== ComparisonTimeRangeType.Custom
|
||||
? timeComparison
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
...queryContextA,
|
||||
queries: [...queryContextA.queries, ...queryContextB.queries],
|
||||
};
|
||||
}
|
|
@ -16,26 +16,22 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { ensureIsArray, t, validateNonEmpty } from '@superset-ui/core';
|
||||
import {
|
||||
AdhocFilter,
|
||||
ComparisonTimeRangeType,
|
||||
SimpleAdhocFilter,
|
||||
t,
|
||||
validateTimeComparisonRangeValues,
|
||||
} from '@superset-ui/core';
|
||||
import {
|
||||
ColumnMeta,
|
||||
ControlPanelConfig,
|
||||
ControlPanelState,
|
||||
ControlState,
|
||||
getStandardizedControls,
|
||||
sharedControls,
|
||||
} from '@superset-ui/chart-controls';
|
||||
|
||||
const validateTimeComparisonRangeValues = (
|
||||
timeRangeValue?: any,
|
||||
controlValue?: any,
|
||||
) => {
|
||||
const isCustomTimeRange = timeRangeValue === 'c';
|
||||
const isCustomControlEmpty = controlValue?.every(
|
||||
(val: any) => ensureIsArray(val).length === 0,
|
||||
);
|
||||
return isCustomTimeRange && isCustomControlEmpty
|
||||
? [t('Filters for comparison must have a value')]
|
||||
: [];
|
||||
};
|
||||
import { headerFontSize, subheaderFontSize } from '../sharedControls';
|
||||
|
||||
const config: ControlPanelConfig = {
|
||||
controlPanelSections: [
|
||||
|
@ -43,17 +39,7 @@ const config: ControlPanelConfig = {
|
|||
label: t('Query'),
|
||||
expanded: true,
|
||||
controlSetRows: [
|
||||
[
|
||||
{
|
||||
name: 'metrics',
|
||||
config: {
|
||||
...sharedControls.metrics,
|
||||
// it's possible to add validators to controls if
|
||||
// certain selections/types need to be enforced
|
||||
validators: [validateNonEmpty],
|
||||
},
|
||||
},
|
||||
],
|
||||
['metric'],
|
||||
['adhoc_filters'],
|
||||
[
|
||||
{
|
||||
|
@ -88,20 +74,34 @@ const config: ControlPanelConfig = {
|
|||
description:
|
||||
'This only applies when selecting the Range for Comparison Type: Custom',
|
||||
visibility: ({ controls }) =>
|
||||
controls?.time_comparison?.value === 'c',
|
||||
controls?.time_comparison?.value ===
|
||||
ComparisonTimeRangeType.Custom,
|
||||
mapStateToProps: (
|
||||
state: ControlPanelState,
|
||||
controlState: ControlState,
|
||||
) => ({
|
||||
...(sharedControls.adhoc_filters.mapStateToProps?.(
|
||||
state,
|
||||
controlState,
|
||||
) || {}),
|
||||
externalValidationErrors: validateTimeComparisonRangeValues(
|
||||
state.controls?.time_comparison?.value,
|
||||
controlState.value,
|
||||
),
|
||||
}),
|
||||
) => {
|
||||
const originalMapStateToPropsRes =
|
||||
sharedControls.adhoc_filters.mapStateToProps?.(
|
||||
state,
|
||||
controlState,
|
||||
) || {};
|
||||
const columns = originalMapStateToPropsRes.columns.filter(
|
||||
(col: ColumnMeta) =>
|
||||
col.is_dttm &&
|
||||
(state.controls.adhoc_filters.value as AdhocFilter[]).some(
|
||||
(val: SimpleAdhocFilter) =>
|
||||
val.subject === col.column_name,
|
||||
),
|
||||
);
|
||||
return {
|
||||
...originalMapStateToPropsRes,
|
||||
columns,
|
||||
externalValidationErrors: validateTimeComparisonRangeValues(
|
||||
state.controls?.time_comparison?.value,
|
||||
controlState.value,
|
||||
),
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -121,69 +121,17 @@ const config: ControlPanelConfig = {
|
|||
['currency_format'],
|
||||
[
|
||||
{
|
||||
name: 'header_font_size',
|
||||
config: {
|
||||
type: 'SelectControl',
|
||||
label: t('Big Number Font Size'),
|
||||
renderTrigger: true,
|
||||
clearable: false,
|
||||
default: 60,
|
||||
options: [
|
||||
{
|
||||
label: t('Tiny'),
|
||||
value: 16,
|
||||
},
|
||||
{
|
||||
label: t('Small'),
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
label: t('Normal'),
|
||||
value: 30,
|
||||
},
|
||||
{
|
||||
label: t('Large'),
|
||||
value: 48,
|
||||
},
|
||||
{
|
||||
label: t('Huge'),
|
||||
value: 60,
|
||||
},
|
||||
],
|
||||
},
|
||||
...headerFontSize,
|
||||
config: { ...headerFontSize.config, default: 0.2 },
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'subheader_font_size',
|
||||
...subheaderFontSize,
|
||||
config: {
|
||||
type: 'SelectControl',
|
||||
label: t('Subheader Font Size'),
|
||||
renderTrigger: true,
|
||||
clearable: false,
|
||||
default: 40,
|
||||
options: [
|
||||
{
|
||||
label: t('Tiny'),
|
||||
value: 16,
|
||||
},
|
||||
{
|
||||
label: t('Small'),
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
label: t('Normal'),
|
||||
value: 26,
|
||||
},
|
||||
{
|
||||
label: t('Large'),
|
||||
value: 32,
|
||||
},
|
||||
{
|
||||
label: t('Huge'),
|
||||
value: 40,
|
||||
},
|
||||
],
|
||||
...subheaderFontSize.config,
|
||||
default: 0.125,
|
||||
label: t('Comparison font size'),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -206,7 +154,14 @@ const config: ControlPanelConfig = {
|
|||
y_axis_format: {
|
||||
label: t('Number format'),
|
||||
},
|
||||
adhoc_filters: {
|
||||
rerender: ['adhoc_custom'],
|
||||
},
|
||||
},
|
||||
formDataOverrides: formData => ({
|
||||
...formData,
|
||||
metric: getStandardizedControls().shiftMetric(),
|
||||
}),
|
||||
};
|
||||
|
||||
export default config;
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
@ -20,19 +20,9 @@ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
|
|||
import buildQuery from './buildQuery';
|
||||
import controlPanel from './controlPanel';
|
||||
import transformProps from './transformProps';
|
||||
import thumbnail from '../images/thumbnail.png';
|
||||
import thumbnail from './images/thumbnail.png';
|
||||
|
||||
export default class PopKPIPlugin extends ChartPlugin {
|
||||
/**
|
||||
* The constructor is used to pass relevant metadata and callbacks that get
|
||||
* registered in respective registries that are used throughout the library
|
||||
* and application. A more thorough description of each property is given in
|
||||
* the respective imported file.
|
||||
*
|
||||
* It is worth noting that `buildQuery` and is optional, and only needed for
|
||||
* advanced visualizations that require either post processing operations
|
||||
* (pivoting, rolling aggregations, sorting etc) or submitting multiple queries.
|
||||
*/
|
||||
constructor() {
|
||||
const metadata = new ChartMetadata({
|
||||
category: t('KPI'),
|
||||
|
@ -45,6 +35,7 @@ export default class PopKPIPlugin extends ChartPlugin {
|
|||
t('Percentages'),
|
||||
t('Report'),
|
||||
t('Description'),
|
||||
t('Advanced-Analytics'),
|
||||
],
|
||||
thumbnail,
|
||||
});
|
||||
|
@ -52,7 +43,7 @@ export default class PopKPIPlugin extends ChartPlugin {
|
|||
super({
|
||||
buildQuery,
|
||||
controlPanel,
|
||||
loadChart: () => import('../PopKPI'),
|
||||
loadChart: () => import('./PopKPI'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
|
@ -23,8 +23,9 @@ import {
|
|||
getValueFormatter,
|
||||
NumberFormats,
|
||||
getNumberFormatter,
|
||||
formatTimeRange,
|
||||
} from '@superset-ui/core';
|
||||
import { computeQueryBComparator, formatCustomComparator } from '../utils';
|
||||
import { getComparisonFontSize, getHeaderFontSize } from './utils';
|
||||
|
||||
export const parseMetricValue = (metricValue: number | string | null) => {
|
||||
if (typeof metricValue === 'string') {
|
||||
|
@ -78,23 +79,27 @@ export default function transformProps(chartProps: ChartProps) {
|
|||
boldText,
|
||||
headerFontSize,
|
||||
headerText,
|
||||
metrics,
|
||||
metric,
|
||||
yAxisFormat,
|
||||
currencyFormat,
|
||||
subheaderFontSize,
|
||||
comparisonColorEnabled,
|
||||
} = formData;
|
||||
const { data: dataA = [] } = queriesData[0];
|
||||
const { data: dataB = [] } = queriesData[1];
|
||||
const {
|
||||
data: dataB = [],
|
||||
from_dttm: comparisonFromDatetime,
|
||||
to_dttm: comparisonToDatetime,
|
||||
} = queriesData[1];
|
||||
const data = dataA;
|
||||
const metricName = getMetricLabel(metrics[0]);
|
||||
const metricName = getMetricLabel(metric);
|
||||
let bigNumber: number | string =
|
||||
data.length === 0 ? 0 : parseMetricValue(data[0][metricName]);
|
||||
let prevNumber: number | string =
|
||||
data.length === 0 ? 0 : parseMetricValue(dataB[0][metricName]);
|
||||
|
||||
const numberFormatter = getValueFormatter(
|
||||
metrics[0],
|
||||
metric,
|
||||
currencyFormats,
|
||||
columnFormats,
|
||||
yAxisFormat,
|
||||
|
@ -129,33 +134,23 @@ export default function transformProps(chartProps: ChartProps) {
|
|||
prevNumber = numberFormatter(prevNumber);
|
||||
valueDifference = numberFormatter(valueDifference);
|
||||
const percentDifference: string = formatPercentChange(percentDifferenceNum);
|
||||
const comparatorText =
|
||||
formData.timeComparison !== 'c'
|
||||
? ` ${computeQueryBComparator(
|
||||
formData.adhocFilters,
|
||||
formData.timeComparison,
|
||||
formData.extraFormData,
|
||||
' - ',
|
||||
)}`
|
||||
: `${formatCustomComparator(
|
||||
formData.adhocCustom,
|
||||
formData.extraFormData,
|
||||
)}`;
|
||||
const comparatorText = formatTimeRange('%Y-%m-%d', [
|
||||
comparisonFromDatetime,
|
||||
comparisonToDatetime,
|
||||
]);
|
||||
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
// and now your control data, manipulated as needed, and passed through as props!
|
||||
metrics,
|
||||
metricName,
|
||||
bigNumber,
|
||||
prevNumber,
|
||||
valueDifference,
|
||||
percentDifferenceFormattedString: percentDifference,
|
||||
boldText,
|
||||
headerFontSize,
|
||||
subheaderFontSize,
|
||||
headerFontSize: getHeaderFontSize(headerFontSize),
|
||||
subheaderFontSize: getComparisonFontSize(subheaderFontSize),
|
||||
headerText,
|
||||
compType,
|
||||
comparisonColorEnabled,
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
export const useOverflowDetection = (flexGap: number) => {
|
||||
const symbolContainerRef = useRef<HTMLDivElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const [isOverflowing, setIsOverflowing] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let obs: ResizeObserver;
|
||||
const symbolContainerElem = symbolContainerRef.current;
|
||||
const wrapperElem = wrapperRef.current;
|
||||
if (symbolContainerElem && wrapperElem) {
|
||||
const symbolContainerChildrenElems = Array.from(
|
||||
symbolContainerElem.children,
|
||||
);
|
||||
obs = new ResizeObserver(
|
||||
debounce(() => {
|
||||
const totalChildrenWidth = symbolContainerChildrenElems.reduce(
|
||||
(acc, element) =>
|
||||
// take symbol container's child's scroll width to account for the container growing with display: flex
|
||||
acc + (element.firstElementChild?.scrollWidth ?? 0),
|
||||
0,
|
||||
);
|
||||
if (
|
||||
totalChildrenWidth +
|
||||
flexGap * Math.max(symbolContainerChildrenElems.length - 1, 0) >
|
||||
wrapperElem.clientWidth
|
||||
) {
|
||||
setIsOverflowing(true);
|
||||
} else {
|
||||
setIsOverflowing(false);
|
||||
}
|
||||
}, 500),
|
||||
);
|
||||
obs.observe(document.body);
|
||||
symbolContainerChildrenElems.forEach(elem => {
|
||||
obs.observe(elem);
|
||||
});
|
||||
}
|
||||
return () => obs?.disconnect();
|
||||
}, [flexGap]);
|
||||
|
||||
return { isOverflowing, symbolContainerRef, wrapperRef };
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { getComparisonFontSize, getHeaderFontSize } from './utils';
|
||||
|
||||
test('getHeaderFontSize', () => {
|
||||
expect(getHeaderFontSize(0.2)).toEqual(16);
|
||||
expect(getHeaderFontSize(0.3)).toEqual(20);
|
||||
expect(getHeaderFontSize(0.4)).toEqual(30);
|
||||
expect(getHeaderFontSize(0.5)).toEqual(48);
|
||||
expect(getHeaderFontSize(0.6)).toEqual(60);
|
||||
expect(getHeaderFontSize(0.15)).toEqual(60);
|
||||
expect(getHeaderFontSize(2)).toEqual(60);
|
||||
});
|
||||
|
||||
test('getComparisonFontSize', () => {
|
||||
expect(getComparisonFontSize(0.125)).toEqual(16);
|
||||
expect(getComparisonFontSize(0.15)).toEqual(20);
|
||||
expect(getComparisonFontSize(0.2)).toEqual(26);
|
||||
expect(getComparisonFontSize(0.3)).toEqual(32);
|
||||
expect(getComparisonFontSize(0.4)).toEqual(40);
|
||||
expect(getComparisonFontSize(0.05)).toEqual(40);
|
||||
expect(getComparisonFontSize(0.9)).toEqual(40);
|
||||
});
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { headerFontSize, subheaderFontSize } from '../sharedControls';
|
||||
|
||||
const headerFontSizes = [16, 20, 30, 48, 60];
|
||||
const comparisonFontSizes = [16, 20, 26, 32, 40];
|
||||
|
||||
const headerProportionValues =
|
||||
headerFontSize.config.options.map(
|
||||
(option: { label: string; value: number }) => option.value,
|
||||
) ?? [];
|
||||
|
||||
const subheaderProportionValues =
|
||||
subheaderFontSize.config.options.map(
|
||||
(option: { label: string; value: number }) => option.value,
|
||||
) ?? [];
|
||||
|
||||
const getFontSizeMapping = (
|
||||
proportionValues: number[],
|
||||
actualSizes: number[],
|
||||
) =>
|
||||
proportionValues.reduce((acc, value, index) => {
|
||||
acc[value] = actualSizes[index] ?? actualSizes[actualSizes.length - 1];
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const headerFontSizesMapping = getFontSizeMapping(
|
||||
headerProportionValues,
|
||||
headerFontSizes,
|
||||
);
|
||||
|
||||
const comparisonFontSizesMapping = getFontSizeMapping(
|
||||
subheaderProportionValues,
|
||||
comparisonFontSizes,
|
||||
);
|
||||
|
||||
export const getHeaderFontSize = (proportionValue: number) =>
|
||||
headerFontSizesMapping[proportionValue] ??
|
||||
headerFontSizes[headerFontSizes.length - 1];
|
||||
|
||||
export const getComparisonFontSize = (proportionValue: number) =>
|
||||
comparisonFontSizesMapping[proportionValue] ??
|
||||
comparisonFontSizes[comparisonFontSizes.length - 1];
|
|
@ -19,3 +19,4 @@
|
|||
|
||||
export { default as BigNumberChartPlugin } from './BigNumberWithTrendline';
|
||||
export { default as BigNumberTotalChartPlugin } from './BigNumberTotal';
|
||||
export { default as BigNumberPeriodOverPeriodChartPlugin } from './BigNumberPeriodOverPeriod';
|
||||
|
|
|
@ -48,11 +48,12 @@ import { getDefaultTooltip } from '../utils/tooltip';
|
|||
import { Refs } from '../types';
|
||||
import { getColtypesMapping } from '../utils/series';
|
||||
|
||||
const setIntervalBoundsAndColors = (
|
||||
export const getIntervalBoundsAndColors = (
|
||||
intervals: string,
|
||||
intervalColorIndices: string,
|
||||
colorFn: CategoricalColorScale,
|
||||
normalizer: number,
|
||||
min: number,
|
||||
max: number,
|
||||
): Array<[number, string]> => {
|
||||
let intervalBoundsNonNormalized;
|
||||
let intervalColorIndicesArray;
|
||||
|
@ -65,7 +66,7 @@ const setIntervalBoundsAndColors = (
|
|||
}
|
||||
|
||||
const intervalBounds = intervalBoundsNonNormalized.map(
|
||||
bound => bound / normalizer,
|
||||
bound => (bound - min) / (max - min),
|
||||
);
|
||||
const intervalColors = intervalColorIndicesArray.map(
|
||||
ind => colorFn.colors[(ind - 1) % colorFn.colors.length],
|
||||
|
@ -221,12 +222,12 @@ export default function transformProps(
|
|||
const axisLabelLength = Math.max(
|
||||
...axisLabels.map(label => numberFormatter(label).length).concat([1]),
|
||||
);
|
||||
const normalizer = max;
|
||||
const intervalBoundsAndColors = setIntervalBoundsAndColors(
|
||||
const intervalBoundsAndColors = getIntervalBoundsAndColors(
|
||||
intervals,
|
||||
intervalColorIndices,
|
||||
colorFn,
|
||||
normalizer,
|
||||
min,
|
||||
max,
|
||||
);
|
||||
const splitLineDistance =
|
||||
axisLineWidth + splitLineLength + OFFSETS.ticksFromLine;
|
||||
|
|
|
@ -410,8 +410,9 @@ export default function transformProps(
|
|||
|
||||
rawSeriesB.forEach(entry => {
|
||||
const entryName = String(entry.name || '');
|
||||
const seriesName = `${inverted[entryName] || entryName} (1)`;
|
||||
const colorScaleKey = getOriginalSeries(seriesName, array);
|
||||
const seriesEntry = inverted[entryName] || entryName;
|
||||
const seriesName = `${seriesEntry} (1)`;
|
||||
const colorScaleKey = getOriginalSeries(seriesEntry, array);
|
||||
|
||||
const seriesFormatter = getFormatter(
|
||||
customFormattersSecondary,
|
||||
|
|
|
@ -575,7 +575,6 @@ export default function transformProps(
|
|||
right: TIMESERIES_CONSTANTS.toolboxRight,
|
||||
feature: {
|
||||
dataZoom: {
|
||||
yAxisIndex: false,
|
||||
title: {
|
||||
zoom: t('zoom area'),
|
||||
back: t('restore zoom'),
|
||||
|
@ -590,6 +589,7 @@ export default function transformProps(
|
|||
start: TIMESERIES_CONSTANTS.dataZoomStart,
|
||||
end: TIMESERIES_CONSTANTS.dataZoomEnd,
|
||||
bottom: TIMESERIES_CONSTANTS.zoomBottom,
|
||||
yAxisIndex: isHorizontal ? 0 : undefined,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
|
|
|
@ -570,9 +570,10 @@ export function getPadding(
|
|||
yAxisTitlePosition && yAxisTitlePosition === 'Top'
|
||||
? TIMESERIES_CONSTANTS.gridOffsetTop + (Number(yAxisTitleMargin) || 0)
|
||||
: TIMESERIES_CONSTANTS.gridOffsetTop + yAxisOffset,
|
||||
bottom: zoomable
|
||||
? TIMESERIES_CONSTANTS.gridOffsetBottomZoomable + xAxisOffset
|
||||
: TIMESERIES_CONSTANTS.gridOffsetBottom + xAxisOffset,
|
||||
bottom:
|
||||
zoomable && !isHorizontal
|
||||
? TIMESERIES_CONSTANTS.gridOffsetBottomZoomable + xAxisOffset
|
||||
: TIMESERIES_CONSTANTS.gridOffsetBottom + xAxisOffset,
|
||||
left:
|
||||
yAxisTitlePosition === 'Left'
|
||||
? TIMESERIES_CONSTANTS.gridOffsetLeft +
|
||||
|
|
|
@ -32,7 +32,11 @@ export { default as EchartsRadarChartPlugin } from './Radar';
|
|||
export { default as EchartsFunnelChartPlugin } from './Funnel';
|
||||
export { default as EchartsTreeChartPlugin } from './Tree';
|
||||
export { default as EchartsTreemapChartPlugin } from './Treemap';
|
||||
export { BigNumberChartPlugin, BigNumberTotalChartPlugin } from './BigNumber';
|
||||
export {
|
||||
BigNumberChartPlugin,
|
||||
BigNumberTotalChartPlugin,
|
||||
BigNumberPeriodOverPeriodChartPlugin,
|
||||
} from './BigNumber';
|
||||
export { default as EchartsSunburstChartPlugin } from './Sunburst';
|
||||
export { default as EchartsBubbleChartPlugin } from './Bubble';
|
||||
export { default as EchartsWaterfallChartPlugin } from './Waterfall';
|
||||
|
|
|
@ -16,8 +16,15 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { ChartProps, SqlaFormData, supersetTheme } from '@superset-ui/core';
|
||||
import transformProps from '../../src/Gauge/transformProps';
|
||||
import {
|
||||
CategoricalColorNamespace,
|
||||
ChartProps,
|
||||
SqlaFormData,
|
||||
supersetTheme,
|
||||
} from '@superset-ui/core';
|
||||
import transformProps, {
|
||||
getIntervalBoundsAndColors,
|
||||
} from '../../src/Gauge/transformProps';
|
||||
import { EchartsGaugeChartProps } from '../../src/Gauge/types';
|
||||
|
||||
describe('Echarts Gauge transformProps', () => {
|
||||
|
@ -256,8 +263,9 @@ describe('Echarts Gauge transformProps', () => {
|
|||
const formData: SqlaFormData = {
|
||||
...baseFormData,
|
||||
groupby: ['year', 'platform'],
|
||||
intervals: '50,100',
|
||||
intervals: '60,100',
|
||||
intervalColorIndices: '1,2',
|
||||
minVal: 20,
|
||||
};
|
||||
const queriesData = [
|
||||
{
|
||||
|
@ -342,3 +350,43 @@ describe('Echarts Gauge transformProps', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIntervalBoundsAndColors', () => {
|
||||
it('should generate correct interval bounds and colors', () => {
|
||||
const colorFn = CategoricalColorNamespace.getScale(
|
||||
'supersetColors' as string,
|
||||
);
|
||||
expect(getIntervalBoundsAndColors('', '', colorFn, 0, 10)).toEqual([]);
|
||||
expect(getIntervalBoundsAndColors('4, 10', '1, 2', colorFn, 0, 10)).toEqual(
|
||||
[
|
||||
[0.4, '#1f77b4'],
|
||||
[1, '#ff7f0e'],
|
||||
],
|
||||
);
|
||||
expect(
|
||||
getIntervalBoundsAndColors('4, 8, 10', '9, 8, 7', colorFn, 0, 10),
|
||||
).toEqual([
|
||||
[0.4, '#bcbd22'],
|
||||
[0.8, '#7f7f7f'],
|
||||
[1, '#e377c2'],
|
||||
]);
|
||||
expect(getIntervalBoundsAndColors('4, 10', '1, 2', colorFn, 2, 10)).toEqual(
|
||||
[
|
||||
[0.25, '#1f77b4'],
|
||||
[1, '#ff7f0e'],
|
||||
],
|
||||
);
|
||||
expect(
|
||||
getIntervalBoundsAndColors('-4, 0', '1, 2', colorFn, -10, 0),
|
||||
).toEqual([
|
||||
[0.6, '#1f77b4'],
|
||||
[1, '#ff7f0e'],
|
||||
]);
|
||||
expect(
|
||||
getIntervalBoundsAndColors('-4, -2', '1, 2', colorFn, -10, -2),
|
||||
).toEqual([
|
||||
[0.75, '#1f77b4'],
|
||||
[1, '#ff7f0e'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,87 +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.
|
||||
\*/
|
||||
|
||||
# custom-viz
|
||||
|
||||
This plugin provides a BigNumber visualization with period over period time comparisons
|
||||
|
||||
### Usage
|
||||
|
||||
To build the plugin, run the following commands:
|
||||
|
||||
```
|
||||
npm ci
|
||||
npm run build
|
||||
```
|
||||
|
||||
Alternatively, to run the plugin in development mode (=rebuilding whenever changes are made), start the dev server with the following command:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
To add the package to Superset, go to the `superset-frontend` subdirectory in your Superset source folder (assuming both the `custom-viz` plugin and `superset` repos are in the same root directory) and run
|
||||
|
||||
```
|
||||
npm i -S ../../plugin-chart-period-over-period-kpi
|
||||
```
|
||||
|
||||
If your Superset plugin exists in the `superset-frontend` directory and you wish to resolve TypeScript errors about `@superset-ui/core` not being resolved correctly, add the following to your `tsconfig.json` file:
|
||||
|
||||
```
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/superset-ui-chart-controls"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/superset-ui-core"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
You may also wish to add the following to the `include` array in `tsconfig.json` to make Superset types available to your plugin:
|
||||
|
||||
```
|
||||
"../../types/**/*"
|
||||
```
|
||||
|
||||
Finally, if you wish to ensure your plugin `tsconfig.json` is aligned with the root Superset project, you may add the following to your `tsconfig.json` file:
|
||||
|
||||
```
|
||||
"extends": "../../tsconfig.json",
|
||||
```
|
||||
|
||||
After this edit the `superset-frontend/src/visualizations/presets/MainPreset.js` and make the following changes:
|
||||
|
||||
```js
|
||||
import { PopKPIPlugin } from '@superset-ui/plugin-chart-period-over-period-kpi';
|
||||
```
|
||||
|
||||
to import the plugin and later add the following to the array that's passed to the `plugins` property:
|
||||
|
||||
```js
|
||||
new PopKPIPlugin().configure({ key: 'pop_kpi' }),
|
||||
```
|
||||
|
||||
After that the plugin should show up when you run Superset, e.g. the development server:
|
||||
|
||||
```
|
||||
npm run dev-server
|
||||
```
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue