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 ( - + ); } diff --git a/superset/assets/src/dashboard/components/DashboardBuilder.jsx b/superset/assets/src/dashboard/components/DashboardBuilder.jsx index de9a94eddd23..0d3f29f974ca 100644 --- a/superset/assets/src/dashboard/components/DashboardBuilder.jsx +++ b/superset/assets/src/dashboard/components/DashboardBuilder.jsx @@ -193,7 +193,7 @@ class DashboardBuilder extends React.Component { > {({ dropIndicatorProps }) => (
- + {!this.props.charts_only_mode && } {dropIndicatorProps &&
} {topLevelTabs && (
@@ -306,14 +306,14 @@ class Header extends React.PureComponent { canSave={userCanSaveAs} /> - + {!isGammaUser && - + }
@@ -391,18 +391,17 @@ class Header extends React.PureComponent {
)} - {!editMode && !hasUnsavedChanges && ( + {!editMode && !hasUnsavedChanges && userCanEdit && ( )} - + isGammaUser={isGammaUser} + />}
); diff --git a/superset/assets/src/dashboard/components/SliceHeader.jsx b/superset/assets/src/dashboard/components/SliceHeader.jsx index 100a0703c46b..08d55a47335d 100644 --- a/superset/assets/src/dashboard/components/SliceHeader.jsx +++ b/superset/assets/src/dashboard/components/SliceHeader.jsx @@ -96,6 +96,7 @@ class SliceHeader extends React.PureComponent { componentId, filters, addDangerToast, + isGammaUser } = this.props; return ( @@ -148,6 +149,7 @@ class SliceHeader extends React.PureComponent { componentId={componentId} filters={filters} addDangerToast={addDangerToast} + isGammaUser={isGammaUser} /> )} diff --git a/superset/assets/src/dashboard/components/SliceHeaderControls.jsx b/superset/assets/src/dashboard/components/SliceHeaderControls.jsx index 65565f07cb29..b5fc7c2c0ffd 100644 --- a/superset/assets/src/dashboard/components/SliceHeaderControls.jsx +++ b/superset/assets/src/dashboard/components/SliceHeaderControls.jsx @@ -110,13 +110,13 @@ class SliceHeaderControls extends React.PureComponent { filters, componentId, addDangerToast, + isGammaUser } = this.props; const cachedWhen = moment.utc(cachedDttm).fromNow(); const updatedWhen = updatedDttm ? moment.utc(updatedDttm).fromNow() : ''; const refreshTooltip = isCached ? t('Cached %s', cachedWhen) : (updatedWhen && t('Fetched %s', updatedWhen)) || ''; - return ( - + {!isGammaUser && - + } - - {t('Force refresh')} -
{refreshTooltip}
-
+ {!isGammaUser && ( +
+ + {t('Force refresh')} +
{refreshTooltip}
+
+ +
+ ) + } - {slice.description && ( @@ -159,7 +164,7 @@ class SliceHeaderControls extends React.PureComponent { )} - {t('Share chart')}} - /> + />}
); diff --git a/superset/assets/src/dashboard/components/gridComponents/Chart.jsx b/superset/assets/src/dashboard/components/gridComponents/Chart.jsx index 4d34cc64b7c7..be5e810828ff 100644 --- a/superset/assets/src/dashboard/components/gridComponents/Chart.jsx +++ b/superset/assets/src/dashboard/components/gridComponents/Chart.jsx @@ -224,6 +224,7 @@ class Chart extends React.Component { supersetCanCSV, sliceCanEdit, addDangerToast, + isGammaUser } = this.props; const { width } = this.state; @@ -262,6 +263,7 @@ class Chart extends React.Component { componentId={componentId} filters={filters} addDangerToast={addDangerToast} + isGammaUser={isGammaUser} /> {/* diff --git a/superset/assets/src/dashboard/containers/Chart.jsx b/superset/assets/src/dashboard/containers/Chart.jsx index 5f0b107270cd..2ea2bdb12a8e 100644 --- a/superset/assets/src/dashboard/containers/Chart.jsx +++ b/superset/assets/src/dashboard/containers/Chart.jsx @@ -72,6 +72,7 @@ function mapStateToProps( supersetCanExplore: !!dashboardInfo.superset_can_explore, supersetCanCSV: !!dashboardInfo.superset_can_csv, sliceCanEdit: !!dashboardInfo.slice_can_edit, + isGammaUser: dashboardInfo.isGammaUser, }; } diff --git a/superset/assets/src/dashboard/reducers/getInitialState.js b/superset/assets/src/dashboard/reducers/getInitialState.js index 85a62e383983..5becdc1dee93 100644 --- a/superset/assets/src/dashboard/reducers/getInitialState.js +++ b/superset/assets/src/dashboard/reducers/getInitialState.js @@ -46,7 +46,7 @@ import getLocationHash from '../util/getLocationHash'; import newComponentFactory from '../util/newComponentFactory'; import { TIME_RANGE } from '../../visualizations/FilterBox/FilterBox'; -export default function(bootstrapData) { +export default function (bootstrapData) { const { user_id, datasources, common, editMode } = bootstrapData; const dashboard = { ...bootstrapData.dashboard_data }; @@ -239,11 +239,13 @@ export default function(bootstrapData) { dashboard.metadata.timed_refresh_immune_slices, }, userId: user_id, + isGammaUser: bootstrapData.isGammaUser, dash_edit_perm: dashboard.dash_edit_perm, dash_save_perm: dashboard.dash_save_perm, superset_can_explore: dashboard.superset_can_explore, superset_can_csv: dashboard.superset_can_csv, slice_can_edit: dashboard.slice_can_edit, + charts_only_mode: dashboard.charts_only_mode, common: { flash_messages: common.flash_messages, conf: common.conf, diff --git a/superset/assets/src/dashboard/stylesheets/grid.less b/superset/assets/src/dashboard/stylesheets/grid.less index 270f8ae3705c..6bc14c63792d 100644 --- a/superset/assets/src/dashboard/stylesheets/grid.less +++ b/superset/assets/src/dashboard/stylesheets/grid.less @@ -18,7 +18,6 @@ */ .grid-container { position: relative; - margin: 24px 36px 24px; /* without this, the grid will not get smaller upon toggling the builder panel on */ min-width: 0; width: 100%; diff --git a/superset/assets/src/welcome/Welcome.jsx b/superset/assets/src/welcome/Welcome.jsx index db1a632fd5f3..0d27d6851b00 100644 --- a/superset/assets/src/welcome/Welcome.jsx +++ b/superset/assets/src/welcome/Welcome.jsx @@ -40,6 +40,8 @@ export default class Welcome extends React.PureComponent { this.setState({ search: event.target.value }); } render() { + const { roles } = this.props.user; + const isGammaUser = Object.keys(roles).filter((role) => role === "Gamma").length > 0 ? true : false; return (
@@ -62,7 +64,7 @@ export default class Welcome extends React.PureComponent { - + {!isGammaUser &&

{t('Recently Viewed')}

@@ -70,8 +72,8 @@ export default class Welcome extends React.PureComponent {
-
- + } + {!isGammaUser &&

{t('Favorites')}

@@ -79,7 +81,7 @@ export default class Welcome extends React.PureComponent {
-
+
}
); diff --git a/superset/assets/stylesheets/less/cosmo/variables.less b/superset/assets/stylesheets/less/cosmo/variables.less index 7b979c224525..e46e022bdf63 100644 --- a/superset/assets/stylesheets/less/cosmo/variables.less +++ b/superset/assets/stylesheets/less/cosmo/variables.less @@ -32,7 +32,7 @@ @gray-light: lighten(@gray-base, 70%); @gray-lighter: lighten(@gray-base, 95%); -@brand-primary: #00A699; +@brand-primary: #265FE5; @brand-success: #4AC15F; @brand-info: lighten(#2AB7CA, 15%); @brand-warning: #FED766; @@ -59,12 +59,12 @@ // //## Font, line-height, and color for body text, headings, and more. -@font-family-sans-serif: Helvetica, Arial; +@font-family-montserrat: Montserrat; @font-family-serif: Georgia, "Times New Roman", Times, serif; //** Default monospace fonts for ``, ``, 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 @@
         
         
       
-      
-        {{ appbuilder.app_name }}
-      
+      {{ appbuilder.app_name }}
     
     
   
-
+
\ 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 %} - -