diff --git a/.env.sample b/.env.sample
new file mode 100644
index 000000000000..5d72792db105
--- /dev/null
+++ b/.env.sample
@@ -0,0 +1,10 @@
+SQLALCHEMY_DATABASE_URI=
+TENANT=
+STAGE=
+REDIS_ENDPOINT=
+SQLALCHEMY_ENGINE_OPTIONS=
+ADMIN_EMAIL=
+ADMIN_PASSWORD=
+GUEST_EMAIL=
+GUEST_PASSWORD=
+SUPERSET_ENV=
diff --git a/.gitignore b/.gitignore
index ab5126af5d5e..162f74308423 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,3 +86,4 @@ apache-superset-*.tar.gz*
# Translation binaries
messages.mo
+.env
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000000..d8bddd16237a
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,75 @@
+FROM python:3.6-jessie
+
+RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset
+
+# Configure environment
+ENV LANG=C.UTF-8 \
+ LC_ALL=C.UTF-8
+
+RUN apt-get update -y
+
+# Install dependencies to fix `curl https support error` and `elaying package configuration warning`
+RUN apt-get install -y apt-transport-https apt-utils
+
+
+# Install superset dependencies
+# https://superset.incubator.apache.org/installation.html#os-dependencies
+RUN apt-get install -y build-essential libssl-dev \
+ libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev
+
+# Install extra useful tool for development
+RUN apt-get install -y vim less postgresql-client redis-tools
+
+# Install nodejs for custom build
+# https://superset.incubator.apache.org/installation.html#making-your-own-build
+# https://nodejs.org/en/download/package-manager/
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
+ && apt-get install -y nodejs
+
+
+ARG SUPERSET_ENV=$SUPERSET_ENV
+ARG SQLALCHEMY_DATABASE_URI=$SQLALCHEMY_DATABASE_URI
+ARG TENANT=$TENANT
+ARG STAGE=$STAGE
+ARG REDIS_ENDPOINT=$REDIS_ENDPOINT
+ARG SQLALCHEMY_ENGINE_OPTIONS=$SQLALCHEMY_ENGINE_OPTIONS
+ARG ADMIN_EMAIL=$ADMIN_EMAIL
+ARG ADMIN_PASSWORD=$ADMIN_PASSWORD
+ARG GUEST_EMAIL=$GUEST_EMAIL
+ARG GUEST_PASSWORD=$GUEST_PASSWORD
+ARG AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION
+
+ENV SUPERSET_ENV=${SUPERSET_ENV} \
+ SQLALCHEMY_DATABASE_URI=${SQLALCHEMY_DATABASE_URI} \
+ TENANT=${TENANT} \
+ STAGE=$STAGE \
+ REDIS_ENDPOINT=${REDIS_ENDPOINT} \
+ SQLALCHEMY_ENGINE_OPTIONS=${SQLALCHEMY_ENGINE_OPTIONS} \
+ ADMIN_EMAIL=${ADMIN_EMAIL} \
+ ADMIN_PASSWORD=${ADMIN_PASSWORD} \
+ GUEST_EMAIL=${GUEST_EMAIL} \
+ GUEST_PASSWORD=${GUEST_PASSWORD} \
+ AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
+
+WORKDIR /home/superset
+
+COPY . /home/superset
+
+RUN pip install --upgrade setuptools pip \
+ && pip install -r requirements.txt -r requirements-dev.txt \
+ && pip install -e . \
+ && pip install gevent \
+ && rm -rf /root/.cache/pip
+
+RUN cd superset/assets \
+ && npm ci \
+ && npm run build \
+ && rm -rf node_modules
+
+RUN chmod +x docker_init.sh && ./docker_init.sh
+
+RUN chmod +x docker_entrypoint.sh
+
+EXPOSE 8088
+
+CMD ["./docker_entrypoint.sh"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 000000000000..7b5b3fc8ae93
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,29 @@
+version: '3'
+services:
+ superset:
+ container_name: ais-service-superset
+ build:
+ context: .
+ args:
+ SQLALCHEMY_DATABASE_URI: $SQLALCHEMY_DATABASE_URI
+ TENANT: $TENANT
+ STAGE: $STAGE
+ REDIS_ENDPOINT: $REDIS_ENDPOINT
+ SQLALCHEMY_ENGINE_OPTIONS: $SQLALCHEMY_ENGINE_OPTIONS
+ ADMIN_EMAIL: $ADMIN_EMAIL
+ ADMIN_PASSWORD: $ADMIN_PASSWORD
+ GUEST_EMAIL: $GUEST_EMAIL
+ GUEST_PASSWORD: $GUEST_PASSWORD
+ SUPERSET_ENV: $SUPERSET_ENV
+ restart: always
+ environment:
+ AWS_PROFILE: peak-dev
+ AWS_REGION: eu-west-1
+ env_file:
+ - .env
+ ports:
+ - 8088:8088
+ volumes:
+ - .:/home/superset
+ - $HOME/.aws:/root/.aws
+ tty: true
diff --git a/docker_entrypoint.sh b/docker_entrypoint.sh
new file mode 100644
index 000000000000..665d70518344
--- /dev/null
+++ b/docker_entrypoint.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION
+set -ex
+
+if [ "$#" -ne 0 ]; then
+ exec "$@"
+elif [ "$SUPERSET_ENV" = "development" ]; then
+ celery worker --app=superset.sql_lab:celery_app --pool=gevent -Ofair &
+ # needed by superset runserver
+ (cd superset/assets/ && npm ci)
+ (cd superset/assets/ && npm run dev) &
+ FLASK_ENV=development FLASK_APP=superset:app flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0
+elif [ "$SUPERSET_ENV" = "production" ]; then
+ celery worker --app=superset.sql_lab:celery_app --pool=gevent -Ofair &
+ exec gunicorn --bind 0.0.0.0:8088 \
+ --workers $((2 * $(getconf _NPROCESSORS_ONLN) + 1)) \
+ --timeout 120 \
+ --limit-request-line 0 \
+ --limit-request-field_size 0 \
+ superset:app
+else
+ superset --help
+fi
diff --git a/docker_init.sh b/docker_init.sh
new file mode 100644
index 000000000000..dc79851fa98d
--- /dev/null
+++ b/docker_init.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+set -ex
+
+# Create an admin user
+export FLASK_APP=superset:app
+export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION
+
+flask fab create-admin \
+ --username admin \
+ --firstname admin \
+ --lastname admin \
+ --email $ADMIN_EMAIL \
+ --password $ADMIN_PASSWORD
+
+# Initialize the database
+superset db upgrade
+
+superset load_examples
+
+# Load PCV datasources and dashboards at build time
+superset import_datasources -p pcv_datasources.yml \
+ && superset import_dashboards -p pcv_dashboard.json
+
+# Create default roles and permissions
+superset init
+
+flask fab create-user \
+ --role Gamma \
+ --username guest \
+ --firstname guest \
+ --lastname guest \
+ --email $GUEST_EMAIL \
+ --password $GUEST_PASSWORD
diff --git a/pcv_dashboard.json b/pcv_dashboard.json
new file mode 100644
index 000000000000..705113195876
--- /dev/null
+++ b/pcv_dashboard.json
@@ -0,0 +1,2033 @@
+{
+ "dashboards": [
+ {
+ "__Dashboard__": {
+ "css": "",
+ "dashboard_title": "Dashboard",
+ "description": null,
+ "json_metadata": "{\"filter_immune_slices\": [], \"timed_refresh_immune_slices\": [], \"filter_immune_slice_fields\": {}, \"expanded_slices\": {}, \"refresh_frequency\": 0, \"default_filters\": \"{}\", \"remote_id\": 7}",
+ "position_json": "{\"CHART-GK5NOZ4vwK\":{\"children\":[],\"id\":\"CHART-GK5NOZ4vwK\",\"meta\":{\"chartId\":85,\"height\":18,\"sliceName\":\"Lapsed Customers\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"ROW-fuHPyFcoN\"],\"type\":\"CHART\"},\"CHART-I2_xx9x9BV\":{\"children\":[],\"id\":\"CHART-I2_xx9x9BV\",\"meta\":{\"chartId\":82,\"height\":18,\"sliceName\":\"Total Customers\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"ROW-fuHPyFcoN\"],\"type\":\"CHART\"},\"CHART-I9vB1IZl0mh\":{\"children\":[],\"id\":\"CHART-I9vB1IZl0mh\",\"meta\":{\"chartId\":102,\"height\":22,\"sliceName\":\"Average Basket Size\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\",\"TAB-MImdJnLy8Y\",\"ROW-DdFWy3Z97\"],\"type\":\"CHART\"},\"CHART-J8fnoAjqGO\":{\"children\":[],\"id\":\"CHART-J8fnoAjqGO\",\"meta\":{\"chartId\":89,\"height\":18,\"sliceName\":\"High Risk Customers\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"ROW-NCwPsYF_Dj\"],\"type\":\"CHART\"},\"CHART-MEWPosEnI3\":{\"children\":[],\"id\":\"CHART-MEWPosEnI3\",\"meta\":{\"chartId\":92,\"height\":42,\"sliceName\":\"Next Transaction Window\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-JWoC9_CZLC\",\"TAB-02MO99SDGZ\",\"ROW-nifcQb2AX\"],\"type\":\"CHART\"},\"CHART-PfmWmi7TAr\":{\"children\":[],\"id\":\"CHART-PfmWmi7TAr\",\"meta\":{\"chartId\":95,\"height\":38,\"sliceName\":\"Top Locations\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-xa3pS1Zc9Z\",\"TAB--zBlT2IZIC\",\"ROW-3m-1w1V9f\"],\"type\":\"CHART\"},\"CHART-QwB9vOUenj\":{\"children\":[],\"id\":\"CHART-QwB9vOUenj\",\"meta\":{\"chartId\":94,\"height\":37,\"sliceName\":\"Gender Distribution\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-xa3pS1Zc9Z\",\"TAB--zBlT2IZIC\",\"ROW-3m-1w1V9f\"],\"type\":\"CHART\"},\"CHART-Vm-quiAr2bd\":{\"children\":[],\"id\":\"CHART-Vm-quiAr2bd\",\"meta\":{\"chartId\":100,\"height\":22,\"sliceName\":\"Repeat Order Customers\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\",\"TAB-MImdJnLy8Y\",\"ROW-z5s3_miiy\"],\"type\":\"CHART\"},\"CHART-YNMwn6_rPu\":{\"children\":[],\"id\":\"CHART-YNMwn6_rPu\",\"meta\":{\"chartId\":91,\"height\":38,\"sliceName\":\"At Risk Customers\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-JWoC9_CZLC\",\"TAB-02MO99SDGZ\",\"ROW-qXQbo1lI-\"],\"type\":\"CHART\"},\"CHART-ahIpFD4c7XW\":{\"children\":[],\"id\":\"CHART-ahIpFD4c7XW\",\"meta\":{\"chartId\":103,\"height\":22,\"sliceName\":\"Average Order Value\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\",\"TAB-MImdJnLy8Y\",\"ROW-DdFWy3Z97\"],\"type\":\"CHART\"},\"CHART-dQ7_D4qEvt\":{\"children\":[],\"id\":\"CHART-dQ7_D4qEvt\",\"meta\":{\"chartId\":90,\"height\":38,\"sliceName\":\"In Market Customers\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-JWoC9_CZLC\",\"TAB-02MO99SDGZ\",\"ROW-qXQbo1lI-\"],\"type\":\"CHART\"},\"CHART-dQuJcq2XLR\":{\"children\":[],\"id\":\"CHART-dQuJcq2XLR\",\"meta\":{\"chartId\":96,\"height\":38,\"sliceName\":\"Top Brands\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-Km79KtK7V1\",\"TAB-JLHaJMHPJ7\",\"ROW-PbJ0LvEo1\"],\"type\":\"CHART\"},\"CHART-efnfIIvlQX\":{\"children\":[],\"id\":\"CHART-efnfIIvlQX\",\"meta\":{\"chartId\":86,\"height\":18,\"sliceName\":\"Predictive LTV (per customer))\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"ROW-NCwPsYF_Dj\"],\"type\":\"CHART\"},\"CHART-heiQOAa_8Q\":{\"children\":[],\"id\":\"CHART-heiQOAa_8Q\",\"meta\":{\"chartId\":88,\"height\":18,\"sliceName\":\"In Market Customers\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"ROW-NCwPsYF_Dj\"],\"type\":\"CHART\"},\"CHART-n6y3n22t6o\":{\"children\":[],\"id\":\"CHART-n6y3n22t6o\",\"meta\":{\"chartId\":97,\"height\":40,\"sliceName\":\"Top Products\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-Km79KtK7V1\",\"TAB-JLHaJMHPJ7\",\"ROW-PbJ0LvEo1\"],\"type\":\"CHART\"},\"CHART-nky2yMyPD5\":{\"children\":[],\"id\":\"CHART-nky2yMyPD5\",\"meta\":{\"chartId\":84,\"height\":18,\"sliceName\":\"Active Customers\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"ROW-fuHPyFcoN\"],\"type\":\"CHART\"},\"CHART-oosvRCf2BsI\":{\"children\":[],\"id\":\"CHART-oosvRCf2BsI\",\"meta\":{\"chartId\":101,\"height\":22,\"sliceName\":\"Average Gap Between Orders\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\",\"TAB-MImdJnLy8Y\",\"ROW-z5s3_miiy\"],\"type\":\"CHART\"},\"CHART-pI8xr-8UQjT\":{\"children\":[],\"id\":\"CHART-pI8xr-8UQjT\",\"meta\":{\"chartId\":99,\"height\":20,\"sliceName\":\"Single Order Customers\",\"width\":4},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\",\"TAB-MImdJnLy8Y\",\"ROW-z5s3_miiy\"],\"type\":\"CHART\"},\"CHART-sMmQCmkrkZ\":{\"children\":[],\"id\":\"CHART-sMmQCmkrkZ\",\"meta\":{\"chartId\":93,\"height\":42,\"sliceName\":\"Predictive Engagement\",\"width\":6},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-JWoC9_CZLC\",\"TAB-02MO99SDGZ\",\"ROW-nifcQb2AX\"],\"type\":\"CHART\"},\"DASHBOARD_VERSION_KEY\":\"v2\",\"GRID_ID\":{\"children\":[\"ROW-fuHPyFcoN\",\"ROW-NCwPsYF_Dj\",\"TABS-JWoC9_CZLC\",\"TABS-Km79KtK7V1\",\"TABS-xa3pS1Zc9Z\",\"TABS-6MVVbNFXTC\"],\"id\":\"GRID_ID\",\"parents\":[\"ROOT_ID\"],\"type\":\"GRID\"},\"HEADER_ID\":{\"id\":\"HEADER_ID\",\"meta\":{\"text\":\"Dashboard\"},\"type\":\"HEADER\"},\"ROOT_ID\":{\"children\":[\"GRID_ID\"],\"id\":\"ROOT_ID\",\"type\":\"ROOT\"},\"ROW-3m-1w1V9f\":{\"children\":[\"CHART-QwB9vOUenj\",\"CHART-PfmWmi7TAr\"],\"id\":\"ROW-3m-1w1V9f\",\"meta\":{\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-xa3pS1Zc9Z\",\"TAB--zBlT2IZIC\"],\"type\":\"ROW\"},\"ROW-DdFWy3Z97\":{\"children\":[\"CHART-I9vB1IZl0mh\",\"CHART-ahIpFD4c7XW\"],\"id\":\"ROW-DdFWy3Z97\",\"meta\":{\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\",\"TAB-MImdJnLy8Y\"],\"type\":\"ROW\"},\"ROW-NCwPsYF_Dj\":{\"children\":[\"CHART-efnfIIvlQX\",\"CHART-heiQOAa_8Q\",\"CHART-J8fnoAjqGO\"],\"id\":\"ROW-NCwPsYF_Dj\",\"meta\":{\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\"],\"type\":\"ROW\"},\"ROW-PbJ0LvEo1\":{\"children\":[\"CHART-dQuJcq2XLR\",\"CHART-n6y3n22t6o\"],\"id\":\"ROW-PbJ0LvEo1\",\"meta\":{\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-Km79KtK7V1\",\"TAB-JLHaJMHPJ7\"],\"type\":\"ROW\"},\"ROW-fuHPyFcoN\":{\"children\":[\"CHART-I2_xx9x9BV\",\"CHART-nky2yMyPD5\",\"CHART-GK5NOZ4vwK\"],\"id\":\"ROW-fuHPyFcoN\",\"meta\":{\"0\":\"ROOT_ID\",\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\"],\"type\":\"ROW\"},\"ROW-nifcQb2AX\":{\"children\":[\"CHART-MEWPosEnI3\",\"CHART-sMmQCmkrkZ\"],\"id\":\"ROW-nifcQb2AX\",\"meta\":{\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-JWoC9_CZLC\",\"TAB-02MO99SDGZ\"],\"type\":\"ROW\"},\"ROW-qXQbo1lI-\":{\"children\":[\"CHART-dQ7_D4qEvt\",\"CHART-YNMwn6_rPu\"],\"id\":\"ROW-qXQbo1lI-\",\"meta\":{\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-JWoC9_CZLC\",\"TAB-02MO99SDGZ\"],\"type\":\"ROW\"},\"ROW-z5s3_miiy\":{\"children\":[\"CHART-pI8xr-8UQjT\",\"CHART-Vm-quiAr2bd\",\"CHART-oosvRCf2BsI\"],\"id\":\"ROW-z5s3_miiy\",\"meta\":{\"background\":\"BACKGROUND_TRANSPARENT\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\",\"TAB-MImdJnLy8Y\"],\"type\":\"ROW\"},\"TAB--zBlT2IZIC\":{\"children\":[\"ROW-3m-1w1V9f\"],\"id\":\"TAB--zBlT2IZIC\",\"meta\":{\"text\":\"Demographic Distribution\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-xa3pS1Zc9Z\"],\"type\":\"TAB\"},\"TAB-02MO99SDGZ\":{\"children\":[\"ROW-qXQbo1lI-\",\"ROW-nifcQb2AX\"],\"id\":\"TAB-02MO99SDGZ\",\"meta\":{\"text\":\"Engagement breakdown by customers\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-JWoC9_CZLC\"],\"type\":\"TAB\"},\"TAB-JLHaJMHPJ7\":{\"children\":[\"ROW-PbJ0LvEo1\"],\"id\":\"TAB-JLHaJMHPJ7\",\"meta\":{\"text\":\"Preference Insight\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-Km79KtK7V1\"],\"type\":\"TAB\"},\"TAB-MImdJnLy8Y\":{\"children\":[\"ROW-z5s3_miiy\",\"ROW-DdFWy3Z97\"],\"id\":\"TAB-MImdJnLy8Y\",\"meta\":{\"text\":\"Purchase Insights\"},\"parents\":[\"ROOT_ID\",\"GRID_ID\",\"TABS-6MVVbNFXTC\"],\"type\":\"TAB\"},\"TABS-6MVVbNFXTC\":{\"children\":[\"TAB-MImdJnLy8Y\"],\"id\":\"TABS-6MVVbNFXTC\",\"meta\":{},\"parents\":[\"ROOT_ID\",\"GRID_ID\"],\"type\":\"TABS\"},\"TABS-JWoC9_CZLC\":{\"children\":[\"TAB-02MO99SDGZ\"],\"id\":\"TABS-JWoC9_CZLC\",\"meta\":{},\"parents\":[\"ROOT_ID\",\"GRID_ID\"],\"type\":\"TABS\"},\"TABS-Km79KtK7V1\":{\"children\":[\"TAB-JLHaJMHPJ7\"],\"id\":\"TABS-Km79KtK7V1\",\"meta\":{},\"parents\":[\"ROOT_ID\",\"GRID_ID\"],\"type\":\"TABS\"},\"TABS-xa3pS1Zc9Z\":{\"children\":[\"TAB--zBlT2IZIC\"],\"id\":\"TABS-xa3pS1Zc9Z\",\"meta\":{},\"parents\":[\"ROOT_ID\",\"GRID_ID\"],\"type\":\"TABS\"}}",
+ "slices": [
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Query pcv.admin admin-Untitled Query-VgE_aKo8v-grh7IFRiC",
+ "datasource_type": "table",
+ "id": 82,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"16__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"totalcustomercnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 462, \"is_dttm\": false, \"optionName\": \"_col_totalcustomercnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": true, \"hasCustomLabel\": false, \"label\": \"SUM(totalcustomercnt)\", \"optionName\": \"metric_mrx864ykdd_exy5xqlolr\", \"sqlExpression\": null}, \"show_trend_line\": false, \"slice_id\": 82, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"100 years ago : \", \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 82, \"datasource_name\": \"Total Customer\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Total Customers",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Active Customers",
+ "datasource_type": "table",
+ "id": 84,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"19__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"activecnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 468, \"is_dttm\": false, \"optionName\": \"_col_activecnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(activecnt)\", \"optionName\": \"metric_ydcpati057_cav4b7z3dfe\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 84, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 84, \"datasource_name\": \"Active Customers\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Active Customers",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Avg Predictive LTV",
+ "datasource_type": "table",
+ "id": 86,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"21__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"avgeltv\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 472, \"is_dttm\": false, \"optionName\": \"_col_avgeltv\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(avgeltv)\", \"optionName\": \"metric_arqcptjmb7j_j0yi8fjwba\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 86, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 86, \"datasource_name\": \"Avg Predictive LTV\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Predictive LTV (per customer))",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.In Market Customers",
+ "datasource_type": "table",
+ "id": 88,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"22__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"inmarkethighcnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 474, \"is_dttm\": false, \"optionName\": \"_col_inmarkethighcnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(inmarkethighcnt)\", \"optionName\": \"metric_s3mljepvza_vgq45du8zsg\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 88, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 88, \"datasource_name\": \"In Market Customers\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "In Market Customers",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.In Market Customers Breakdown",
+ "datasource_type": "table",
+ "id": 90,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"24__table\", \"granularity_sqla\": null, \"groupby\": [\"predinmarket\"], \"label_colors\": {}, \"metrics\": [{\"aggregate\": \"COUNT\", \"column\": {\"column_name\": \"predinmarket\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 477, \"is_dttm\": false, \"optionName\": \"_col_predinmarket\", \"python_date_format\": null, \"type\": \"STRING\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": true, \"hasCustomLabel\": false, \"label\": \"COUNT(predinmarket)\", \"optionName\": \"metric_2o3dxwl6jed_m7twgj1j2ek\", \"sqlExpression\": null}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": 10000, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 90, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 90, \"datasource_name\": \"In Market Customers Breakdown\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "In Market Customers",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.At Risk Customers Breakdown",
+ "datasource_type": "table",
+ "id": 91,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"25__table\", \"granularity_sqla\": null, \"groupby\": [\"predchurnrisk\"], \"label_colors\": {\"COUNT(associationvalue)\": \"#00d1c1\", \"COUNT(engagement)\": \"#007A87\", \"COUNT(predinmarket)\": \"#ff5a5f\", \"COUNT(userid)\": \"#7b0051\"}, \"metrics\": [{\"aggregate\": \"COUNT\", \"column\": {\"column_name\": \"userid\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 480, \"is_dttm\": false, \"python_date_format\": null, \"type\": \"STRING\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": true, \"hasCustomLabel\": false, \"label\": \"COUNT(userid)\", \"optionName\": \"metric_clapdl1o6gp_3ggp4twhr1x\", \"sqlExpression\": null}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": null, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 91, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 91, \"datasource_name\": \"At Risk Customers Breakdown\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "At Risk Customers",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Next Transaction Window",
+ "datasource_type": "table",
+ "id": 92,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"26__table\", \"granularity_sqla\": null, \"groupby\": [\"prednexttranswindow\"], \"label_colors\": {}, \"metrics\": [{\"aggregate\": \"COUNT\", \"column\": {\"column_name\": \"userid\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 482, \"is_dttm\": false, \"optionName\": \"_col_userid\", \"python_date_format\": null, \"type\": \"STRING\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"COUNT(userid)\", \"optionName\": \"metric_bejh7q9ndpp_jb4lsjwfv6\", \"sqlExpression\": null}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": null, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 92, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 92, \"datasource_name\": \"Next Transaction Window\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Next Transaction Window",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Predictive Engagement",
+ "datasource_type": "table",
+ "id": 93,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"27__table\", \"granularity_sqla\": null, \"groupby\": [\"predengagement\"], \"label_colors\": {}, \"metrics\": [{\"aggregate\": \"COUNT\", \"column\": {\"column_name\": \"engagement\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 484, \"is_dttm\": false, \"optionName\": \"_col_engagement\", \"python_date_format\": null, \"type\": \"STRING\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"COUNT(engagement)\", \"optionName\": \"metric_8ivr5jbpkss_xdyf5bshoe8\", \"sqlExpression\": null}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": null, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 93, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 93, \"datasource_name\": \"Predictive Engagement\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Predictive Engagement",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Gender Distribution",
+ "datasource_type": "table",
+ "id": 94,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"31__table\", \"granularity_sqla\": null, \"groupby\": [\"usergender\"], \"label_colors\": {\"COUNT(associationvalue)\": \"#00d1c1\", \"COUNT(engagement)\": \"#007A87\", \"COUNT(predinmarket)\": \"#ff5a5f\", \"COUNT(userid)\": \"#7b0051\", \"F\": \"#8ce071\", \"M\": \"#ffb400\"}, \"metrics\": [{\"aggregate\": \"COUNT\", \"column\": {\"column_name\": \"userid\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 491, \"is_dttm\": false, \"optionName\": \"_col_userid\", \"python_date_format\": null, \"type\": \"STRING\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"COUNT(userid)\", \"optionName\": \"metric_jwqkgn74b0r_sas99w2wmk\", \"sqlExpression\": null}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": null, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 94, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 94, \"datasource_name\": \"Gender Distribution\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Gender Distribution",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Top Locations",
+ "datasource_type": "table",
+ "id": 95,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"32__table\", \"granularity_sqla\": null, \"groupby\": [\"addrcountry\"], \"label_colors\": {}, \"metrics\": [{\"aggregate\": null, \"column\": null, \"expressionType\": \"SQL\", \"fromFormData\": true, \"hasCustomLabel\": false, \"label\": \"COUNT(userid)\", \"optionName\": \"metric_oz65dp841i_823yd2mgbcp\", \"sqlExpression\": \"COUNT(userid)\"}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": 10, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 95, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 95, \"datasource_name\": \"Top Locations\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Top Locations",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Top Brands",
+ "datasource_type": "table",
+ "id": 96,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"33__table\", \"granularity_sqla\": null, \"groupby\": [\"associationvalue\"], \"label_colors\": {}, \"metrics\": [{\"aggregate\": \"COUNT\", \"column\": {\"column_name\": \"associationvalue\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 497, \"is_dttm\": false, \"optionName\": \"_col_associationvalue\", \"python_date_format\": null, \"type\": \"STRING\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"COUNT(associationvalue)\", \"optionName\": \"metric_cjynmjfddcw_t29xvsfxrf\", \"sqlExpression\": null}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": 10, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 96, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 96, \"datasource_name\": \"Top Brands\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Top Brands",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Top Products",
+ "datasource_type": "table",
+ "id": 97,
+ "params": "{\"adhoc_filters\": [], \"bar_stacked\": false, \"bottom_margin\": \"auto\", \"color_scheme\": \"bnbColors\", \"columns\": [], \"contribution\": false, \"datasource\": \"34__table\", \"granularity_sqla\": null, \"groupby\": [\"associationvalue\"], \"label_colors\": {}, \"metrics\": [{\"aggregate\": \"COUNT\", \"column\": {\"column_name\": \"associationvalue\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 501, \"is_dttm\": false, \"optionName\": \"_col_associationvalue\", \"python_date_format\": null, \"type\": \"STRING\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"COUNT(associationvalue)\", \"optionName\": \"metric_dbo3fmt10iw_tvpwwohaxdm\", \"sqlExpression\": null}], \"order_bars\": false, \"reduce_x_ticks\": false, \"row_limit\": 10, \"show_bar_value\": false, \"show_controls\": false, \"show_legend\": true, \"slice_id\": 97, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"dist_bar\", \"x_axis_label\": \"\", \"x_ticks_layout\": \"auto\", \"y_axis_format\": \"SMART_NUMBER\", \"y_axis_label\": \"\", \"remote_id\": 97, \"datasource_name\": \"Top Products\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Top Products",
+ "viz_type": "dist_bar"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Single Order Customers",
+ "datasource_type": "table",
+ "id": 99,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"35__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"singleordercnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 503, \"is_dttm\": false, \"optionName\": \"_col_singleordercnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(singleordercnt)\", \"optionName\": \"metric_4tffl8tv6e_csgr4vfz5zl\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 99, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 99, \"datasource_name\": \"Single Order Customers\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Single Order Customers",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Repeat Order Customers",
+ "datasource_type": "table",
+ "id": 100,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"36__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"repeatordercnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 505, \"is_dttm\": false, \"optionName\": \"_col_repeatordercnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(repeatordercnt)\", \"optionName\": \"metric_iiab6h8ah58_offmowzpndq\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 100, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 100, \"datasource_name\": \"Repeat Order Customers\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Repeat Order Customers",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Average Gap Between Orders",
+ "datasource_type": "table",
+ "id": 101,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"37__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"avgordergapcnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 507, \"is_dttm\": false, \"optionName\": \"_col_avgordergapcnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": true, \"hasCustomLabel\": false, \"label\": \"SUM(avgordergapcnt)\", \"optionName\": \"metric_nlirbqzmzsk_bty9qlc8e3g\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 101, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 101, \"datasource_name\": \"Average Gap Between Orders\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Average Gap Between Orders",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Average Basket Size",
+ "datasource_type": "table",
+ "id": 102,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"38__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"avgbasketsize\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 509, \"is_dttm\": false, \"optionName\": \"_col_avgbasketsize\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(avgbasketsize)\", \"optionName\": \"metric_35629xpgdzc_arz5c6f9ex\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 102, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 102, \"datasource_name\": \"Average Basket Size\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Average Basket Size",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Average Order Value",
+ "datasource_type": "table",
+ "id": 103,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"39__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"avgordervalue\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 511, \"is_dttm\": false, \"optionName\": \"_col_avgordervalue\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(avgordervalue)\", \"optionName\": \"metric_m9xvozb965q_8uekn2vashd\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 103, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 103, \"datasource_name\": \"Average Order Value\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Average Order Value",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.Lapsed Customers",
+ "datasource_type": "table",
+ "id": 85,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"20__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"lapsedcnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 470, \"is_dttm\": false, \"optionName\": \"_col_lapsedcnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": true, \"hasCustomLabel\": false, \"label\": \"SUM(lapsedcnt)\", \"optionName\": \"metric_4qxpfryxex3_uk29hf6gyf\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 85, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 85, \"datasource_name\": \"Lapsed Customers\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "Lapsed Customers",
+ "viz_type": "big_number"
+ }
+ },
+ {
+ "__Slice__": {
+ "cache_timeout": null,
+ "datasource_name": "pcv.High Risk Customers",
+ "datasource_type": "table",
+ "id": 89,
+ "params": "{\"adhoc_filters\": [], \"color_picker\": {\"a\": 1, \"b\": 135, \"g\": 122, \"r\": 0}, \"compare_lag\": 7, \"datasource\": \"23__table\", \"granularity_sqla\": \"loaddate\", \"header_font_size\": 0.3, \"metric\": {\"aggregate\": \"SUM\", \"column\": {\"column_name\": \"highriskcnt\", \"description\": null, \"expression\": null, \"filterable\": true, \"groupby\": true, \"id\": 476, \"is_dttm\": false, \"optionName\": \"_col_highriskcnt\", \"python_date_format\": null, \"type\": \"INT\", \"verbose_name\": null}, \"expressionType\": \"SIMPLE\", \"fromFormData\": false, \"hasCustomLabel\": false, \"label\": \"SUM(highriskcnt)\", \"optionName\": \"metric_97tx3d4j2ab_me33kxuxqxd\", \"sqlExpression\": null}, \"show_trend_line\": true, \"slice_id\": 89, \"start_y_axis_at_zero\": true, \"subheader_font_size\": 0.125, \"time_grain_sqla\": null, \"time_range\": \"Last week\", \"url_params\": {}, \"viz_type\": \"big_number\", \"y_axis_format\": \"SMART_NUMBER\", \"remote_id\": 89, \"datasource_name\": \"High Risk Customers\", \"schema\": \"pcv\", \"database_name\": \"examples\"}",
+ "slice_name": "High Risk Customers",
+ "viz_type": "big_number"
+ }
+ }
+ ],
+ "slug": "pcv"
+ }
+ }
+ ],
+ "datasources": [
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "column_name": "associationtype",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 499,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 34,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "column_name": "userid",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 500,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 34,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "column_name": "associationvalue",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 501,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 34,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "column_name": "associationrank",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 502,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 34,
+ "type": "INT",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:15:05"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 42,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 34,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 34, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select associationtype , userid , associationvalue , associationrank from pcv.customer_preferences where associationtype = 'Product Recommendation' \r\nORDER by associationrank asc limit 10",
+ "table_name": "Top Products",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:53:40"
+ },
+ "column_name": "predchurnrisk",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:50:01"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 479,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 25,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:53:40"
+ },
+ "column_name": "userid",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:50:01"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 480,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 25,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:50:01"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:50:01"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 33,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 25,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 25, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select predchurnrisk , userid from pcv.customer_attributes",
+ "table_name": "At Risk Customers Breakdown",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:32:00"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:32:00"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 461,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 16,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:32:00"
+ },
+ "column_name": "totalcustomercnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:32:00"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 462,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 16,
+ "type": "INT",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:32:00"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:32:00"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 24,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 16,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 16, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select loaddate, totalcustomercnt from pcv.aggregatedcustomerdata",
+ "table_name": "Total Customer",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:45:19"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:45:19"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 475,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 23,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:45:19"
+ },
+ "column_name": "highriskcnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:45:19"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 476,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 23,
+ "type": "INT",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:45:19"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:45:19"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 31,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 23,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 23, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select loaddate , highriskcnt from pcv.aggregatedcustomerdata",
+ "table_name": "High Risk Customers",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:21:09"
+ },
+ "column_name": "avgordergapcnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:21:09"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 507,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 37,
+ "type": "INT",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:21:09"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:21:09"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 508,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 37,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:21:09"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:21:09"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 45,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 37,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 37, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select avgordergapcnt , loaddate from pcv.aggregatedcustomerdata",
+ "table_name": "Average Gap Between Orders",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:37:59"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:37:59"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 467,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 19,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:37:59"
+ },
+ "column_name": "activecnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:37:59"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 468,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 19,
+ "type": "INT",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:37:59"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:37:59"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 27,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 19,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 19, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select loaddate , activecnt from pcv.aggregatedcustomerdata",
+ "table_name": "Active Customers",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "column_name": "associationtype",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 495,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 33,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "column_name": "associationrank",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 496,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 33,
+ "type": "INT",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "column_name": "associationvalue",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 497,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 33,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "column_name": "userstatus",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 498,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 33,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:10:34"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 41,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 33,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 33, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "SELECT pcv.customer_preferences.associationtype,pcv.customer_preferences.associationrank , pcv.customer_preferences.associationvalue, pcv.customer_attributes.userstatus \r\nFROM pcv.customer_preferences \r\nINNER JOIN pcv.customer_attributes ON pcv.customer_attributes.userid = pcv.customer_preferences.userid and pcv.customer_preferences.associationtype = 'Brand'",
+ "table_name": "Top Brands",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:53:55"
+ },
+ "column_name": "predinmarket",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:46:58"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 477,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 24,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:53:55"
+ },
+ "column_name": "userid",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:46:58"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 478,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 24,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:46:58"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:46:58"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 32,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 24,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 24, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select predinmarket, userid from pcv.customer_attributes",
+ "table_name": "In Market Customers Breakdown",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:57:21"
+ },
+ "column_name": "userid",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:00:17"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 491,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 31,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:57:21"
+ },
+ "column_name": "usergender",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:00:17"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 492,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 31,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:00:17"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:00:17"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 39,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 31,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 31, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select userid, usergender from pcv.customer_attributes",
+ "table_name": "Gender Distribution",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:43:34"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:43:34"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 473,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 22,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:43:34"
+ },
+ "column_name": "inmarkethighcnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:43:34"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 474,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 22,
+ "type": "INT",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:43:34"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:43:34"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 30,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 22,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 22, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select loaddate , inmarkethighcnt from pcv.aggregatedcustomerdata",
+ "table_name": "In Market Customers",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:19:36"
+ },
+ "column_name": "repeatordercnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:19:36"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 505,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 36,
+ "type": "INT",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:19:36"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:19:36"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 506,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 36,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:19:36"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:19:36"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 44,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 36,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 36, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select repeatordercnt , loaddate from pcv.aggregatedcustomerdata",
+ "table_name": "Repeat Order Customers",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:55:02"
+ },
+ "column_name": "predengagement",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:56:51"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 483,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 27,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:55:02"
+ },
+ "column_name": "engagement",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:56:51"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 484,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 27,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:56:51"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:56:51"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 35,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 27,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 27, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "SELECT predengagement, userid as engagement\r\nfrom pcv.customer_attributes ORDER BY predengagement ASC",
+ "table_name": "Predictive Engagement",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:06:46"
+ },
+ "column_name": "addrcountry",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:05:06"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 493,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 32,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:06:46"
+ },
+ "column_name": "userstatus",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:05:06"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 494,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 32,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:05:06"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:05:06"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 40,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 32,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 32, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select addrcountry, userid from pcv.customer_attributes",
+ "table_name": "Top Locations",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:24:53"
+ },
+ "column_name": "avgordervalue",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:24:53"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 511,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 39,
+ "type": "INT",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:24:53"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:24:53"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 512,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 39,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:24:53"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:24:53"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 47,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 39,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 39, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select avgordervalue , loaddate from pcv.aggregatedcustomerdata",
+ "table_name": "Average Order Value",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:41:33"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:41:33"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 471,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 21,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:41:33"
+ },
+ "column_name": "avgeltv",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:41:33"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 472,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 21,
+ "type": "INT",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:41:33"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:41:33"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 29,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 21,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 21, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select loaddate , avgeltv from pcv.aggregatedcustomerdata",
+ "table_name": "Avg Predictive LTV",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:17:50"
+ },
+ "column_name": "singleordercnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:17:50"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 503,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 35,
+ "type": "INT",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:17:50"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:17:50"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 504,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 35,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:17:50"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:17:50"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 43,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 35,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 35, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select singleordercnt, loaddate from pcv.aggregatedcustomerdata",
+ "table_name": "Single Order Customers",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:54:19"
+ },
+ "column_name": "prednexttranswindow",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:53:18"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 481,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 26,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T11:54:19"
+ },
+ "column_name": "userid",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:53:18"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 482,
+ "is_active": null,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 26,
+ "type": "STRING",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:53:18"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:53:18"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 34,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 26,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 26, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "SELECT prednexttranswindow, userid \r\nfrom pcv.customer_attributes ORDER BY prednexttranswindow ASC",
+ "table_name": "Next Transaction Window",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:23:08"
+ },
+ "column_name": "avgbasketsize",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:23:08"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 509,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 38,
+ "type": "INT",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:23:08"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:23:08"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 510,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 38,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T10:23:08"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T10:23:08"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 46,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 38,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 38, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select avgbasketsize , loaddate from pcv.aggregatedcustomerdata",
+ "table_name": "Average Basket Size",
+ "template_params": "{}"
+ }
+ },
+ {
+ "__SqlaTable__": {
+ "cache_timeout": null,
+ "columns": [
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:39:24"
+ },
+ "column_name": "loaddate",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:39:24"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 469,
+ "is_active": true,
+ "is_dttm": true,
+ "python_date_format": null,
+ "table_id": 20,
+ "type": "DATETIME",
+ "verbose_name": null
+ }
+ },
+ {
+ "__TableColumn__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:39:24"
+ },
+ "column_name": "lapsedcnt",
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:39:24"
+ },
+ "description": null,
+ "expression": null,
+ "filterable": true,
+ "groupby": true,
+ "id": 470,
+ "is_active": true,
+ "is_dttm": false,
+ "python_date_format": null,
+ "table_id": 20,
+ "type": "INT",
+ "verbose_name": null
+ }
+ }
+ ],
+ "database_id": 1,
+ "default_endpoint": null,
+ "description": null,
+ "fetch_values_predicate": null,
+ "filter_select_enabled": false,
+ "main_dttm_col": null,
+ "metrics": [
+ {
+ "__SqlMetric__": {
+ "changed_by_fk": 1,
+ "changed_on": {
+ "__datetime__": "2019-09-27T07:39:24"
+ },
+ "created_by_fk": 1,
+ "created_on": {
+ "__datetime__": "2019-09-27T07:39:24"
+ },
+ "d3format": null,
+ "description": null,
+ "expression": "count(*)",
+ "id": 28,
+ "metric_name": "count",
+ "metric_type": null,
+ "table_id": 20,
+ "verbose_name": null,
+ "warning_text": null
+ }
+ }
+ ],
+ "offset": 0,
+ "params": "{\"remote_id\": 20, \"database_name\": \"examples\"}",
+ "schema": "pcv",
+ "sql": "select loaddate , lapsedcnt from pcv.aggregatedcustomerdata",
+ "table_name": "Lapsed Customers",
+ "template_params": "{}"
+ }
+ }
+ ]
+}
diff --git a/pcv_datasources.yml b/pcv_datasources.yml
new file mode 100644
index 000000000000..f42b5a8823c0
--- /dev/null
+++ b/pcv_datasources.yml
@@ -0,0 +1,263 @@
+databases:
+- allow_run_async: true
+ database_name: dashboards
+ extra: "{\r\n \"metadata_params\": {},\r\n \"engine_params\": {\"pool_recycle\"\
+ : 90, \"pool_timeout\": 900, \"pool_size\": 1, \"max_overflow\": 1},\r\n \"\
+ metadata_cache_timeout\": {},\r\n \"schemas_allowed_for_csv_upload\": []\r\n\
+ }"
+ tables:
+ - columns:
+ - column_name: addrcountry
+ type: STRING
+ - column_name: userstatus
+ type: STRING
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select addrcountry, userid from pcv.customer_attributes
+ table_name: Top Locations
+ template_params: '{}'
+ - columns:
+ - column_name: usergender
+ type: STRING
+ - column_name: userid
+ type: STRING
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select userid, usergender from pcv.customer_attributes
+ table_name: Gender Distribution
+ template_params: '{}'
+ - columns:
+ - column_name: associationvalue
+ type: STRING
+ - column_name: associationtype
+ type: STRING
+ - column_name: userstatus
+ type: STRING
+ - column_name: associationrank
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: "SELECT pcv.customer_preferences.associationtype,pcv.customer_preferences.associationrank\
+ \ , pcv.customer_preferences.associationvalue, pcv.customer_attributes.userstatus \r\nFROM\
+ \ pcv.customer_preferences \r\nINNER JOIN pcv.customer_attributes ON pcv.customer_attributes.userid\
+ \ = pcv.customer_preferences.userid and pcv.customer_preferences.associationtype\
+ \ = 'Brand'"
+ table_name: Top Brands
+ template_params: '{}'
+ - columns:
+ - column_name: predengagement
+ type: STRING
+ - column_name: engagement
+ type: STRING
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: "SELECT predengagement, userid as engagement\r\nfrom pcv.customer_attributes\
+ \ ORDER BY predengagement ASC"
+ table_name: Predictive Engagement
+ template_params: '{}'
+ - columns:
+ - column_name: prednexttranswindow
+ type: STRING
+ - column_name: userid
+ type: STRING
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: "SELECT prednexttranswindow, userid \r\nfrom pcv.customer_attributes ORDER\
+ \ BY prednexttranswindow ASC"
+ table_name: Next Transaction Window
+ template_params: '{}'
+ - columns:
+ - column_name: predinmarket
+ type: STRING
+ - column_name: userid
+ type: STRING
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select predinmarket, userid from pcv.customer_attributes
+ table_name: In Market Customers Breakdown
+ template_params: '{}'
+ - columns:
+ - column_name: predchurnrisk
+ type: STRING
+ - column_name: userid
+ type: STRING
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select predchurnrisk , userid from pcv.customer_attributes
+ table_name: At Risk Customers Breakdown
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: avgordervalue
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select avgordervalue , loaddate from pcv.aggregatedcustomerdata
+ table_name: Average Order Value
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: avgbasketsize
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select avgbasketsize , loaddate from pcv.aggregatedcustomerdata
+ table_name: Average Basket Size
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: avgordergapcnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select avgordergapcnt , loaddate from pcv.aggregatedcustomerdata
+ table_name: Average Gap Between Orders
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: repeatordercnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select repeatordercnt , loaddate from pcv.aggregatedcustomerdata
+ table_name: Repeat Order Customers
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: singleordercnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select singleordercnt, loaddate from pcv.aggregatedcustomerdata
+ table_name: Single Order Customers
+ template_params: '{}'
+ - columns:
+ - column_name: associationvalue
+ type: STRING
+ - column_name: associationtype
+ type: STRING
+ - column_name: userid
+ type: STRING
+ - column_name: associationrank
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: "select associationtype , userid , associationvalue , associationrank from\
+ \ pcv.customer_preferences where associationtype = 'Product Recommendation'\
+ \ \r\nORDER by associationrank asc limit 10"
+ table_name: Top Products
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: highriskcnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select loaddate , highriskcnt from pcv.aggregatedcustomerdata
+ table_name: High Risk Customers
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: inmarkethighcnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select loaddate , inmarkethighcnt from pcv.aggregatedcustomerdata
+ table_name: In Market Customers
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: avgeltv
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select loaddate , avgeltv from pcv.aggregatedcustomerdata
+ table_name: Avg Predictive LTV
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: lapsedcnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select loaddate , lapsedcnt from pcv.aggregatedcustomerdata
+ table_name: Lapsed Customers
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: activecnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select loaddate , activecnt from pcv.aggregatedcustomerdata
+ table_name: Active Customers
+ template_params: '{}'
+ - columns:
+ - column_name: loaddate
+ is_dttm: true
+ type: DATETIME
+ - column_name: totalcustomercnt
+ type: INT
+ metrics:
+ - expression: count(*)
+ metric_name: count
+ schema: pcv
+ sql: select loaddate, totalcustomercnt from pcv.aggregatedcustomerdata
+ table_name: Total Customer
+ template_params: '{}'
diff --git a/setup.py b/setup.py
index 222b9b8c3fef..ee451e42648c 100644
--- a/setup.py
+++ b/setup.py
@@ -69,6 +69,7 @@ def get_git_sha():
zip_safe=False,
scripts=["superset/bin/superset"],
install_requires=[
+ "ais-service-discovery~=0.0.9",
"backoff>=1.8.0",
"bleach>=3.0.2, <4.0.0",
"celery>=4.3.0, <5.0.0",
diff --git a/superset/assets/images/superset-logo@2x.png b/superset/assets/images/superset-logo@2x.png
index 839f61798d5e..c30b583d708c 100644
Binary files a/superset/assets/images/superset-logo@2x.png and b/superset/assets/images/superset-logo@2x.png differ
diff --git a/superset/assets/src/components/FilterableTable/FilterableTableStyles.css b/superset/assets/src/components/FilterableTable/FilterableTableStyles.css
index 4bf21072cf46..8363a77f4bd2 100644
--- a/superset/assets/src/components/FilterableTable/FilterableTableStyles.css
+++ b/superset/assets/src/components/FilterableTable/FilterableTableStyles.css
@@ -89,6 +89,6 @@
color: #aaa;
}
.cell-text-for-measuring {
- font-family: Helvetica, Arial, sans-serif;
+ font-family: Montserrat;
font-size: 12px;
}
diff --git a/superset/assets/src/components/VictoryTheme.js b/superset/assets/src/components/VictoryTheme.js
index e0b35dfae3f8..878bd42a63f3 100644
--- a/superset/assets/src/components/VictoryTheme.js
+++ b/superset/assets/src/components/VictoryTheme.js
@@ -18,7 +18,7 @@
*/
const { assign } = Object;
-const A11Y_BABU = '#00A699';
+const A11Y_BABU = '#265FE5';
const AXIS_LINE_GRAY = '#484848';
// Colors
@@ -51,7 +51,7 @@ const baseProps = {
// Labels
const baseLabelStyles = {
- fontFamily: sansSerif,
+ fontFamily: "Montserrat",
fontSize,
letterSpacing,
padding: 10,
diff --git a/superset/assets/src/dashboard/components/Dashboard.jsx b/superset/assets/src/dashboard/components/Dashboard.jsx
index 334704e4c697..573844258317 100644
--- a/superset/assets/src/dashboard/components/Dashboard.jsx
+++ b/superset/assets/src/dashboard/components/Dashboard.jsx
@@ -193,7 +193,9 @@ class Dashboard extends React.PureComponent {
return (
`, ``, and ``.
@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
-@font-family-base: @font-family-sans-serif;
+@font-family-base: @font-family-montserrat;
@font-size-base: 14px;
@font-size-large: ceil((@font-size-base * 1.25)); // ~18px
diff --git a/superset/assets/stylesheets/less/index.less b/superset/assets/stylesheets/less/index.less
index b1fc604323c0..9508c2d31fd3 100644
--- a/superset/assets/stylesheets/less/index.less
+++ b/superset/assets/stylesheets/less/index.less
@@ -22,6 +22,8 @@
@import "./cosmo/variables.less";
@import "./cosmo/bootswatch.less";
+@import (css) url("https://fonts.googleapis.com/css?family=Montserrat");
+
@stroke-primary: @brand-primary;
body {
diff --git a/superset/assets/stylesheets/superset.less b/superset/assets/stylesheets/superset.less
index a8aa49a4ba08..a8fcf306da72 100644
--- a/superset/assets/stylesheets/superset.less
+++ b/superset/assets/stylesheets/superset.less
@@ -258,7 +258,7 @@ table.table-no-hover tr:hover {
}
.editable-title.datasource-sql-expression {
- font-family: @font-family-monospace;
+ font-family: @font-family-montserrat;
font-size: 95%;
display: inline-block;
min-width: @datasource-sql-expression-width;
diff --git a/superset/config.py b/superset/config.py
index f92246f42866..161147b82a0c 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -35,6 +35,8 @@
from superset.stats_logger import DummyStatsLogger
from superset.utils.logging_configurator import DefaultLoggingConfigurator
+from werkzeug.contrib.cache import RedisCache
+from .custom_auth import CustomSecurityManager
# Realtime stats logger, a StatsD implementation exists
STATS_LOGGER = DummyStatsLogger()
@@ -70,8 +72,8 @@ def _try_json_readfile(filepath):
PACKAGE_JSON_FILE
)
-ROW_LIMIT = 50000
-VIZ_ROW_LIMIT = 10000
+ROW_LIMIT = 50000000
+VIZ_ROW_LIMIT = 10000000
# max rows retrieved by filter select auto complete
FILTER_SELECT_ROW_LIMIT = 10000
SUPERSET_WORKERS = 2 # deprecated
@@ -84,21 +86,26 @@ def _try_json_readfile(filepath):
# [load balancer / proxy / envoy / kong / ...] timeout settings.
# You should also make sure to configure your WSGI server
# (gunicorn, nginx, apache, ...) timeout setting to be <= to this setting
-SUPERSET_WEBSERVER_TIMEOUT = 60
+SUPERSET_WEBSERVER_TIMEOUT = 120
SUPERSET_DASHBOARD_POSITION_DATA_LIMIT = 65535
EMAIL_NOTIFICATIONS = False
-CUSTOM_SECURITY_MANAGER = None
+CUSTOM_SECURITY_MANAGER = CustomSecurityManager
SQLALCHEMY_TRACK_MODIFICATIONS = False
# ---------------------------------------------------------
+TENANT = os.environ['TENANT']
# Your App secret key
-SECRET_KEY = "\2\1thisismyscretkey\1\2\e\y\y\h" # noqa
+SECRET_KEY = "\2\1thisis{}secretkey\1\2\e\y\y\h".format(TENANT) # noqa
+
+REDIS_ENDPOINT = os.environ['REDIS_ENDPOINT']
+SQLALCHEMY_ENGINE_OPTIONS = json.loads(os.environ['SQLALCHEMY_ENGINE_OPTIONS'])
# The SQLAlchemy connection string.
-SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(DATA_DIR, "superset.db")
-# SQLALCHEMY_DATABASE_URI = 'mysql://myapp@localhost/myapp'
-# SQLALCHEMY_DATABASE_URI = 'postgresql://root:password@localhost/myapp'
+SQLALCHEMY_DATABASE_URI = os.environ['SQLALCHEMY_DATABASE_URI']
+# SQLALCHEMY_DATABASE_URI="sqlite:///" + os.path.join(DATA_DIR, "superset.db")
+# SQLALCHEMY_DATABASE_URI='mysql://myapp@localhost/myapp'
+# SQLALCHEMY_DATABASE_URI='postgresql://root:password@localhost/myapp'
# In order to hook up a custom password store for all SQLACHEMY connections
# implement a function that takes a single argument of type 'sqla.engine.url',
@@ -136,11 +143,11 @@ def _try_json_readfile(filepath):
# GLOBALS FOR APP Builder
# ------------------------------
# Uncomment to setup Your App name
-APP_NAME = "Superset"
+APP_NAME = "{}-Superset".format(TENANT)
# Uncomment to setup an App icon
APP_ICON = "/static/assets/images/superset-logo@2x.png"
-APP_ICON_WIDTH = 126
+APP_ICON_WIDTH = 60
# Uncomment to specify where clicking the logo would take the user
# e.g. setting it to '/welcome' would take the user to '/superset/welcome'
@@ -168,7 +175,7 @@ def _try_json_readfile(filepath):
AUTH_TYPE = AUTH_DB
# Uncomment to setup Full admin role name
-# AUTH_ROLE_ADMIN = 'Admin'
+AUTH_ROLE_ADMIN = 'Admin'
# Uncomment to setup Public role name, no authentication needed
# AUTH_ROLE_PUBLIC = 'Public'
@@ -262,12 +269,22 @@ def _try_json_readfile(filepath):
# IMG_SIZE = (300, 200, True)
CACHE_DEFAULT_TIMEOUT = 60 * 60 * 24
-CACHE_CONFIG = {"CACHE_TYPE": "null"}
+CACHE_CONFIG = {
+ 'CACHE_TYPE': 'redis',
+ 'CACHE_DEFAULT_TIMEOUT': 300,
+ 'CACHE_KEY_PREFIX': '{}_superset_'.format(TENANT),
+ 'CACHE_REDIS_HOST': 'redis',
+ 'CACHE_REDIS_PORT': 6379,
+ 'CACHE_REDIS_DB': 1,
+ 'CACHE_REDIS_URL': 'redis://{}/1'.format(REDIS_ENDPOINT)
+}
TABLE_NAMES_CACHE_CONFIG = {"CACHE_TYPE": "null"}
# CORS Options
-ENABLE_CORS = False
-CORS_OPTIONS = {}
+ENABLE_CORS = True
+CORS_OPTIONS = {
+ 'origins': '*',
+}
# Chrome allows up to 6 open connections per domain at a time. When there are more
# than 6 slices in dashboard, a lot of time fetch requests are queued up and wait for
@@ -406,26 +423,20 @@ def _try_json_readfile(filepath):
class CeleryConfig(object):
- BROKER_URL = "sqla+sqlite:///celerydb.sqlite"
- CELERY_IMPORTS = ("superset.sql_lab", "superset.tasks")
- CELERY_RESULT_BACKEND = "db+sqlite:///celery_results.sqlite"
- CELERYD_LOG_LEVEL = "DEBUG"
- CELERYD_PREFETCH_MULTIPLIER = 1
- CELERY_ACKS_LATE = False
- CELERY_ANNOTATIONS = {
- "sql_lab.get_sql_results": {"rate_limit": "100/s"},
- "email_reports.send": {
- "rate_limit": "1/s",
- "time_limit": 120,
- "soft_time_limit": 150,
- "ignore_result": True,
- },
- }
+ BROKER_URL = 'redis://{}/0'.format(REDIS_ENDPOINT)
+ CELERY_IMPORTS = ('superset.sql_lab', 'superset.tasks')
+ CELERY_RESULT_BACKEND = 'redis://{}/0'.format(REDIS_ENDPOINT)
+ CELERY_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}
CELERYBEAT_SCHEDULE = {
- "email_reports.schedule_hourly": {
- "task": "email_reports.schedule_hourly",
- "schedule": crontab(minute=1, hour="*"),
- }
+ 'cache-warmup-hourly': {
+ 'task': 'cache-warmup',
+ 'schedule': crontab(minute=0, hour='*'), # hourly
+ 'kwargs': {
+ 'strategy_name': 'top_n_dashboards',
+ 'top_n': 5,
+ 'since': '7 days ago',
+ },
+ },
}
@@ -457,7 +468,12 @@ class CeleryConfig(object):
# An instantiated derivative of werkzeug.contrib.cache.BaseCache
# if enabled, it can be used to store the results of long-running queries
# in SQL Lab by using the "Run Async" button/feature
-RESULTS_BACKEND = None
+[redis_host, redis_port] = REDIS_ENDPOINT.split(':')
+RESULTS_BACKEND = RedisCache(
+ host=redis_host,
+ port=int(redis_port),
+ key_prefix='{}_superset_results'.format(TENANT),
+)
# Use PyArrow and MessagePack for async query results serialization,
# rather than JSON. This feature requires additional testing from the
diff --git a/superset/custom_auth.py b/superset/custom_auth.py
new file mode 100644
index 000000000000..16982b0c8931
--- /dev/null
+++ b/superset/custom_auth.py
@@ -0,0 +1,70 @@
+from flask import redirect, g, flash, request, app
+from flask_appbuilder.security.views import UserDBModelView, AuthDBView
+from superset.security import SupersetSecurityManager
+from flask_appbuilder.security.views import expose
+from flask_appbuilder.security.manager import BaseSecurityManager
+from flask_login import login_user, logout_user
+from ais_service_discovery import call
+from datetime import timedelta, datetime
+from json import loads
+from os import environ
+
+
+app.permanent_session_lifetime = timedelta(minutes=60)
+
+
+def has_resource_access(privileges):
+ for config in privileges['level']['tenant']['tenants']:
+ if config['tenant'] == environ['TENANT']:
+ for resource in config['resources']:
+ if ('appId' in resource) and resource['appId'] == 'customerAi':
+ return True
+ return False
+
+
+class CustomAuthDBView(AuthDBView):
+
+ @expose('/login/', methods=['GET', 'POST'])
+ def login(self):
+ redirect_url = self.appbuilder.get_url_for_index
+ user = 'guest'
+ try:
+ if request.args.get('redirect') is not None:
+ redirect_url = request.args.get('redirect')
+
+ if request.args.get('authToken') is not None:
+ token = 'Bearer {}'.format(request.args.get('authToken'))
+ auth_response = loads(call(
+ 'ais-{}'.format(environ['STAGE']),
+ 'authentication',
+ 'auth', {
+ 'authorizationToken': token
+ }))['context']
+ if not auth_response['tenant'] == environ['TENANT']:
+ raise Exception('Tenant mismatch in token')
+ if auth_response['role'] in ['tenantManager', 'tenantAdmin']:
+ user = 'admin'
+ else:
+ privileges = loads(auth_response['privileges'])
+ if not has_resource_access(privileges):
+ raise Exception('Insufficient Resource Permissions')
+ user = self.appbuilder.sm.find_user(user)
+ login_user(user, remember=False,
+ duration=timedelta(
+ auth_response['exp'] - int(
+ datetime.now().timestamp())))
+ return redirect(redirect_url)
+ elif g.user is not None and g.user.is_authenticated:
+ return redirect(redirect_url)
+ else:
+ raise Exception('Login is valid only through "authToken"')
+ except Exception as e:
+ flash(e, 'warning')
+ return super(CustomAuthDBView, self).login()
+
+
+class CustomSecurityManager(SupersetSecurityManager):
+ authdbview = CustomAuthDBView
+
+ def __init__(self, appbuilder):
+ super(CustomSecurityManager, self).__init__(appbuilder)
diff --git a/superset/models/core.py b/superset/models/core.py
index e3dcafa0a701..c152686e4218 100755
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -861,7 +861,7 @@ def get_effective_user(self, url, user_name=None):
return effective_username
@utils.memoized(watch=("impersonate_user", "sqlalchemy_uri_decrypted", "extra"))
- def get_sqla_engine(self, schema=None, nullpool=True, user_name=None, source=None):
+ def get_sqla_engine(self, schema=None, nullpool=False, user_name=None, source=None):
extra = self.get_extra()
url = make_url(self.sqlalchemy_uri_decrypted)
url = self.db_engine_spec.adjust_database_uri(url, schema)
diff --git a/superset/security.py b/superset/security.py
index 8c95f8147118..f786c74bf190 100644
--- a/superset/security.py
+++ b/superset/security.py
@@ -100,6 +100,9 @@ class SupersetSecurityManager(SecurityManager):
"ResetPasswordView",
"RoleModelView",
"Security",
+ "Sources",
+ "Dashboards",
+ "Charts",
} | USER_MODEL_VIEWS
ALPHA_ONLY_VIEW_MENUS = {"Upload a CSV"}
@@ -111,6 +114,9 @@ class SupersetSecurityManager(SecurityManager):
"can_override_role_permissions",
"can_approve",
"can_update_role",
+ "can_edit",
+ "can_explore",
+ "can_csv"
}
READ_ONLY_PERMISSION = {"can_show", "can_list"}
@@ -131,6 +137,8 @@ class SupersetSecurityManager(SecurityManager):
ACCESSIBLE_PERMS = {"can_userinfo"}
+ GAMMA_ACCESSIBLE_PERMS = {"all_datasource_access"}
+
def get_schema_perm(
self, database: Union["Database", str], schema: Optional[str] = None
) -> Optional[str]:
@@ -649,6 +657,16 @@ def _is_accessible_to_all(self, pvm: PermissionModelView) -> bool:
return pvm.permission.name in self.ACCESSIBLE_PERMS
+ def _is_accessible_to_gamma(self, pvm: PermissionModelView) -> bool:
+ """
+ Return True if the FAB permission/view is accessible to gamma users, False
+ otherwise.
+
+ :param pvm: The FAB permission/view
+ :returns: Whether the FAB object is accessible to gamma users
+ """
+ return pvm.permission.name in self.GAMMA_ACCESSIBLE_PERMS
+
def _is_admin_pvm(self, pvm: PermissionModelView) -> bool:
"""
Return True if the FAB permission/view is Admin user related, False
@@ -686,7 +704,7 @@ def _is_gamma_pvm(self, pvm: PermissionModelView) -> bool:
self._is_user_defined_permission(pvm)
or self._is_admin_only(pvm)
or self._is_alpha_only(pvm)
- ) or self._is_accessible_to_all(pvm)
+ ) or self._is_accessible_to_all(pvm) or self._is_accessible_to_gamma(pvm)
def _is_sql_lab_pvm(self, pvm: PermissionModelView) -> bool:
"""
@@ -791,3 +809,6 @@ def assert_datasource_permission(self, datasource: "BaseDatasource") -> None:
self.get_datasource_access_error_msg(datasource),
self.get_datasource_access_link(datasource),
)
+
+ def contains_gamma_role(self, roles) -> None:
+ return "Gamma" in roles
diff --git a/superset/templates/appbuilder/navbar.html b/superset/templates/appbuilder/navbar.html
index 29c22411299e..4fd2d59c0980 100644
--- a/superset/templates/appbuilder/navbar.html
+++ b/superset/templates/appbuilder/navbar.html
@@ -30,20 +30,14 @@
-
-
-
+
-
+
\ No newline at end of file
diff --git a/superset/templates/appbuilder/navbar_right.html b/superset/templates/appbuilder/navbar_right.html
index 73c545e3974a..2f2520f1f300 100644
--- a/superset/templates/appbuilder/navbar_right.html
+++ b/superset/templates/appbuilder/navbar_right.html
@@ -21,81 +21,72 @@
{% set documentation_url = appbuilder.app.config.get('DOCUMENTATION_URL') %}
{% set locale = session['locale'] %}
{% if not locale %}
- {% set locale = 'en' %}
+{% set locale = 'en' %}
{% endif %}
-
-{% if not current_user.is_anonymous %}
-
-
-
-
+{% set roles = []%}
+{% for role in current_user.roles %}
+{% set roles = roles.append(role.name) %}
+{% endfor %}
+{% if not current_user.is_anonymous and not ('Gamma' in roles)%}
+
+
+
+
{% endif %}
{% if documentation_url %}
-
+
{% endif %}
{% if bug_report_url %}
-
+
{% endif %}
{% if languages.keys()|length > 1 %}
-
-
-
-
-
+
+
+
+
+
{% endif %}
{% if not current_user.is_anonymous %}
-
-
-
-
-
-
+
+
+
+
+
+
{% else %}
-
+
{{_("Login")}}
-{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/superset/templates/superset/basic.html b/superset/templates/superset/basic.html
index 6c1ff626c752..290075d8a8e4 100644
--- a/superset/templates/superset/basic.html
+++ b/superset/templates/superset/basic.html
@@ -18,86 +18,85 @@
#}
{% import 'appbuilder/general/lib.html' as lib %}
-
-
- {% block title %}
- {% if title %}
- {{ title }}
- {% elif appbuilder and appbuilder.app_name %}
- {{ appbuilder.app_name }}
- {% endif %}
- {% endblock %}
-
- {% block head_meta %}{% endblock %}
- {% block head_css %}
-
-
-
- {% for entry in get_unloaded_chunks(css_manifest('theme'), loaded_chunks) %}
-
- {% endfor %}
+
+
+ {% block title %}
+ {% if title %}
+ {{ title }}
+ {% elif appbuilder and appbuilder.app_name %}
+ {{ appbuilder.app_name }}
+ {% endif %}
+ {% endblock %}
+
+ {% block head_meta %}{% endblock %}
+ {% block head_css %}
+
+
+
+
- {% if entry %}
- {% set entry_files = css_manifest(entry) %}
- {% for entry in get_unloaded_chunks(entry_files, loaded_chunks) %}
-
- {% endfor %}
- {% endif %}
+ {% for entry in get_unloaded_chunks(css_manifest('theme'), loaded_chunks) %}
+
+ {% endfor %}
- {% endblock %}
+ {% if entry %}
+ {% set entry_files = css_manifest(entry) %}
+ {% for entry in get_unloaded_chunks(entry_files, loaded_chunks) %}
+
+ {% endfor %}
+ {% endif %}
- {% with filename="theme" %}
- {% include "superset/partials/_script_tag.html" %}
- {% endwith %}
+ {% endblock %}
-
-
+ {% with filename="theme" %}
+ {% include "superset/partials/_script_tag.html" %}
+ {% endwith %}
-
- {% block navbar %}
- {% if not standalone_mode %}
-
- {% include 'appbuilder/navbar.html' %}
-
- {% endif %}
- {% endblock %}
+
+
- {% block body %}
-
-
-
- {% endblock %}
+
+ {% block navbar %}
+ {% if not standalone_mode %}
+
+ {% include 'appbuilder/navbar.html' %}
+
+ {% endif %}
+ {% endblock %}
-
-
-
-