0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-24 00:47:50 +01:00
* remove django query tests

* remove funnel and caching check

* remove ee available var

* remove is_clickhouse_enabled

* remove abstract tests

* change primary db

* missing func

* unnecessary test

* try new e2e ci

* func arg

* remove param

* ci

* remove plugins in docker

* background

* change ur;

* add kafka url

* add step

* update docker

* primary docker file

* mount volumes correctly

* one more

* remove postgres tests

* remove foss

* remove all  is_clickhouse_neabled

* remove irrelelvant test

* remove extra arg

* remove var

* arg

* add foss comment

* add foss comment

* plugin server config

* Update posthog/utils.py

Co-authored-by: Karl-Aksel Puulmann <macobo@users.noreply.github.com>

* migrate commands

* comment

* add clickhouse to pg tests

* change script

* change ordering

* deepsource

* restore foss tests

* test remove KAFKA_ENABLED from CI

* always wait

* up proper resources

* use one conftest

* restore

* remove unnecessary tests

* remove more pg

* log event tests

* fix more tests

* more tests

* type

* fix more tests

* last test

* typing

* account for shared class setup

* temp test cloud

* restore cloud master checkout

* adjust contexts

* backwards

Co-authored-by: Karl-Aksel Puulmann <macobo@users.noreply.github.com>
Co-authored-by: yakkomajuri <yakko.majuri@gmail.com>
This commit is contained in:
Eric Duong 2022-01-18 14:32:28 -05:00 committed by GitHub
parent cbb9b22d0b
commit a71e899605
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
146 changed files with 1042 additions and 2631 deletions

View File

@ -59,9 +59,9 @@ services:
- '9009:9009' - '9009:9009'
volumes: volumes:
- ../ee/idl:/idl - ../ee/idl:/idl
- ../docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d - ./docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
- ../docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml - ./docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml
- ../docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml - ./docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml
- clickhouse-data:/var/lib/clickhouse/data - clickhouse-data:/var/lib/clickhouse/data
# Needed for 1. clickhouse distributed queries 2. kafka replication # Needed for 1. clickhouse distributed queries 2. kafka replication

View File

@ -22,7 +22,6 @@ jobs:
SAML_DISABLED: '1' SAML_DISABLED: '1'
DATABASE_URL: 'postgres://posthog:posthog@localhost:5432/posthog_test' DATABASE_URL: 'postgres://posthog:posthog@localhost:5432/posthog_test'
REDIS_URL: 'redis://localhost' REDIS_URL: 'redis://localhost'
PRIMARY_DB: 'clickhouse'
DEBUG: '1' DEBUG: '1'
CLICKHOUSE_DATABASE: posthog CLICKHOUSE_DATABASE: posthog
CLICKHOUSE_HOST: ${{ secrets.BENCHMARKS_CLICKHOUSE_HOST }} CLICKHOUSE_HOST: ${{ secrets.BENCHMARKS_CLICKHOUSE_HOST }}
@ -91,7 +90,7 @@ jobs:
- name: Set up PostHog - name: Set up PostHog
run: | run: |
./bin/docker-migrate & wait python manage.py migrate & wait
python manage.py setup_dev --no-data python manage.py setup_dev --no-data
- name: Configure benchmarks - name: Configure benchmarks

View File

@ -156,8 +156,8 @@ jobs:
- name: Start stack with Docker Compose - name: Start stack with Docker Compose
run: | run: |
docker-compose -f ee/docker-compose.ch.yml down docker-compose -f docker-compose.dev.yml down
docker-compose -f ee/docker-compose.ch.yml up -d ${{ matrix.foss && 'db' || 'db clickhouse zookeeper kafka' }} & docker-compose -f docker-compose.dev.yml up -d db clickhouse zookeeper kafka &
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v2
@ -209,26 +209,20 @@ jobs:
touch frontend/dist/shared_dashboard.html touch frontend/dist/shared_dashboard.html
- name: Wait for Clickhouse & Kafka - name: Wait for Clickhouse & Kafka
if: ${{ !matrix.foss }}
run: bin/check_kafka_clickhouse_up run: bin/check_kafka_clickhouse_up
- name: Run FOSS tests - name: Run FOSS tests
if: ${{ matrix.foss }} if: ${{ matrix.foss }}
run: | run: |
rm -rf ee/
pytest -m "not ee" posthog/ --cov --cov-report=xml:coverage-postgres.xml pytest -m "not ee" posthog/ --cov --cov-report=xml:coverage-postgres.xml
- name: Run SAML tests - name: Run SAML tests
if: ${{ matrix.saml }} if: ${{ matrix.saml }}
env:
PRIMARY_DB: 'clickhouse'
run: | run: |
pytest ee -m "saml_only" pytest ee -m "saml_only"
- name: Run ee/ tests - name: Run ee/ tests
if: ${{ matrix.ee }} if: ${{ matrix.ee }}
env:
PRIMARY_DB: 'clickhouse'
run: | run: |
pytest ee -m "not saml_only" \ pytest ee -m "not saml_only" \
--splits ${{ matrix.concurrency }} \ --splits ${{ matrix.concurrency }} \
@ -239,8 +233,6 @@ jobs:
- name: Run pytest.mark.ee tests - name: Run pytest.mark.ee tests
if: ${{ matrix.ee && matrix.group == '1' }} if: ${{ matrix.ee && matrix.group == '1' }}
env:
PRIMARY_DB: 'clickhouse'
run: | run: |
pytest posthog -m "ee" pytest posthog -m "ee"
@ -282,8 +274,8 @@ jobs:
cat requirements.txt >> deploy/requirements.txt cat requirements.txt >> deploy/requirements.txt
- name: Start stack with Docker Compose - name: Start stack with Docker Compose
run: | run: |
docker-compose -f deploy/ee/docker-compose.ch.yml down docker-compose -f deploy/docker-compose.dev.yml down
docker-compose -f deploy/ee/docker-compose.ch.yml up -d db clickhouse zookeeper kafka & docker-compose -f deploy/docker-compose.dev.yml up -d db clickhouse zookeeper kafka &
- name: Set up Python 3.8 - name: Set up Python 3.8
uses: actions/setup-python@v2 uses: actions/setup-python@v2
with: with:
@ -351,8 +343,6 @@ jobs:
touch frontend/dist/shared_dashboard.html touch frontend/dist/shared_dashboard.html
- name: Run cloud tests (posthog-cloud) - name: Run cloud tests (posthog-cloud)
env:
PRIMARY_DB: 'clickhouse'
run: | run: |
source .env.template source .env.template
cd deploy cd deploy

View File

@ -60,11 +60,22 @@ jobs:
--health-retries 5 --health-retries 5
env: env:
REDIS_URL: 'redis://localhost' REDIS_URL: 'redis://localhost'
CLICKHOUSE_HOST: 'localhost'
CLICKHOUSE_DATABASE: 'posthog_test'
KAFKA_HOSTS: 'kafka:9092'
steps: steps:
- name: Check out Django server for database setup - name: Check out Django server for database setup
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Fix Kafka Hostname
run: |
sudo bash -c 'echo "127.0.0.1 kafka zookeeper" >> /etc/hosts'
ping -c 1 kafka
ping -c 1 zookeeper
- name: Start Kafka, ClickHouse, Zookeeper
run: docker-compose -f docker-compose.dev.yml up -d zookeeper kafka clickhouse
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v2
with: with:
@ -130,11 +141,22 @@ jobs:
--health-retries 5 --health-retries 5
env: env:
REDIS_URL: 'redis://localhost' REDIS_URL: 'redis://localhost'
CLICKHOUSE_HOST: 'localhost'
CLICKHOUSE_DATABASE: 'posthog_test'
KAFKA_HOSTS: 'kafka:9092'
steps: steps:
- name: Check out Django server for database setup - name: Check out Django server for database setup
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Fix Kafka Hostname
run: |
sudo bash -c 'echo "127.0.0.1 kafka zookeeper" >> /etc/hosts'
ping -c 1 kafka
ping -c 1 zookeeper
- name: Start Kafka, ClickHouse, Zookeeper
run: docker-compose -f docker-compose.dev.yml up -d zookeeper kafka clickhouse
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v2
with: with:
@ -215,7 +237,7 @@ jobs:
ping -c 1 kafka ping -c 1 kafka
ping -c 1 zookeeper ping -c 1 zookeeper
- name: Start Kafka, ClickHouse, Zookeeper - name: Start Kafka, ClickHouse, Zookeeper
run: docker-compose -f ee/docker-compose.ch.yml up -d zookeeper kafka clickhouse run: docker-compose -f docker-compose.dev.yml up -d zookeeper kafka clickhouse
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v2
@ -245,7 +267,6 @@ jobs:
env: env:
SECRET_KEY: 'abcdef' # unsafe - for testing only SECRET_KEY: 'abcdef' # unsafe - for testing only
DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/posthog' DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/posthog'
PRIMARY_DB: 'clickhouse'
TEST: 'true' TEST: 'true'
run: python manage.py setup_test_environment run: python manage.py setup_test_environment
@ -298,7 +319,7 @@ jobs:
ping -c 1 kafka ping -c 1 kafka
ping -c 1 zookeeper ping -c 1 zookeeper
- name: Start Kafka, ClickHouse, Zookeeper - name: Start Kafka, ClickHouse, Zookeeper
run: docker-compose -f ee/docker-compose.ch.yml up -d zookeeper kafka clickhouse run: docker-compose -f docker-compose.dev.yml up -d zookeeper kafka clickhouse
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v2
@ -328,7 +349,6 @@ jobs:
env: env:
SECRET_KEY: 'abcdef' # unsafe - for testing only SECRET_KEY: 'abcdef' # unsafe - for testing only
DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/posthog' DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/posthog'
PRIMARY_DB: 'clickhouse'
TEST: 'true' TEST: 'true'
run: python manage.py setup_test_environment run: python manage.py setup_test_environment

View File

@ -17,7 +17,6 @@ env:
EMAIL_HOST: 'email.test.posthog.net' # used to test password resets EMAIL_HOST: 'email.test.posthog.net' # used to test password resets
SITE_URL: 'test.posthog.net' # used to test password resets SITE_URL: 'test.posthog.net' # used to test password resets
NO_RESTART_LOOP: 1 NO_RESTART_LOOP: 1
PRIMARY_DB: clickhouse
CLICKHOUSE_SECURE: 0 CLICKHOUSE_SECURE: 0
jobs: jobs:
@ -50,10 +49,9 @@ jobs:
yarn add cypress@6.7.0 cypress-terminal-report@2.1.0 @cypress/react@4.16.4 @cypress/webpack-preprocessor@5.7.0 yarn add cypress@6.7.0 cypress-terminal-report@2.1.0 @cypress/react@4.16.4 @cypress/webpack-preprocessor@5.7.0
cd plugin-server cd plugin-server
yarn install --frozen-lockfile yarn install --frozen-lockfile
cypress: cypress:
name: Cypress E2E tests (${{ strategy.job-index }}) name: Cypress E2E tests (${{ strategy.job-index }})
if: ${{ github.ref != 'refs/heads/master' }} # Don't run on master, we only cace about node_modules cache if: ${{ github.ref != 'refs/heads/master' }} # Don't run on master, we only cace about node_modules cache
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
needs: [cypress_prep] needs: [cypress_prep]
@ -70,9 +68,8 @@ jobs:
- name: Start stack with Docker Compose - name: Start stack with Docker Compose
run: | run: |
docker-compose -f ee/docker-compose.ch.yml down docker-compose -f docker-compose.dev.yml down
docker-compose -f ee/docker-compose.ch.yml up -d db clickhouse zookeeper kafka redis & docker-compose -f docker-compose.dev.yml up -d db clickhouse zookeeper kafka redis &
- name: Add kafka host to /etc/hosts for kafka connectivity - name: Add kafka host to /etc/hosts for kafka connectivity
run: sudo echo "127.0.0.1 kafka" | sudo tee -a /etc/hosts run: sudo echo "127.0.0.1 kafka" | sudo tee -a /etc/hosts
@ -107,8 +104,8 @@ jobs:
${{ runner.os }}-cypress-node-modules-3- ${{ runner.os }}-cypress-node-modules-3-
- name: Yarn install deps - name: Yarn install deps
# NOTE: we always try to run yarn install, as we're using a cache # NOTE: we always try to run yarn install, as we're using a cache
# from the prep phase that hasn't been proven to be correct. We # from the prep phase that hasn't been proven to be correct. We
# should still get some cache benefits. # should still get some cache benefits.
run: | run: |
yarn install --frozen-lockfile yarn install --frozen-lockfile
yarn add cypress@6.7.0 cypress-terminal-report@2.1.0 @cypress/react@4.16.4 @cypress/webpack-preprocessor@5.7.0 yarn add cypress@6.7.0 cypress-terminal-report@2.1.0 @cypress/react@4.16.4 @cypress/webpack-preprocessor@5.7.0
@ -123,11 +120,9 @@ jobs:
yarn build yarn build
- name: Boot PostHog - name: Boot PostHog
run: | run: |
python manage.py collectstatic --noinput & python manage.py collectstatic --noinput
./bin/docker-migrate &
wait
bin/check_kafka_clickhouse_up bin/check_kafka_clickhouse_up
python manage.py migrate_clickhouse ./bin/migrate
python manage.py setup_dev python manage.py setup_dev
mkdir -p /tmp/logs mkdir -p /tmp/logs
./bin/docker-worker &> /tmp/logs/worker.txt & ./bin/docker-worker &> /tmp/logs/worker.txt &

View File

@ -3,10 +3,11 @@
name: Docker FOSS release image name: Docker FOSS release image
on: # TODO: Don't sync until ee code relocation is done
push: # on:
tags: # push:
- '*.**' # tags:
# - '*.**'
jobs: jobs:
build-push: build-push:

View File

@ -1,10 +1,11 @@
name: Sync PostHog FOSS name: Sync PostHog FOSS
on: # TODO: Don't sync until the ee code relocation is done
push: # on:
branches: # push:
- master # branches:
- main # - master
# - main
jobs: jobs:
repo-sync: repo-sync:

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
set -e set -e
./bin/docker-migrate ./bin/migrate
./bin/docker-worker & ./bin/docker-worker &
./bin/docker-server ./bin/docker-server

2
bin/docker-migrate Executable file → Normal file
View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
set -e set -e
python manage.py migrate python manage.py migrate

View File

@ -25,8 +25,8 @@ export PGPASSWORD="${PGPASSWORD:=posthog}"
export PGPORT="${PGPORT:=5432}" export PGPORT="${PGPORT:=5432}"
export DATABASE_URL="postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:${PGPORT}/${DATABASE}" export DATABASE_URL="postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:${PGPORT}/${DATABASE}"
nc -z localhost 9092 || ( echo -e "\033[0;31mKafka isn't running. Please run\n\tdocker compose -f ee/docker-compose.ch.arm64.yml up zookeeper kafka clickhouse db redis\nI'll wait while you do that.\033[0m" ; bin/check_kafka_clickhouse_up ) nc -z localhost 9092 || ( echo -e "\033[0;31mKafka isn't running. Please run\n\tdocker compose -f docker-compose.arm64.yml up zookeeper kafka clickhouse db redis\nI'll wait while you do that.\033[0m" ; bin/check_kafka_clickhouse_up )
wget -nv -t1 --spider 'http://localhost:8123/' || ( echo -e "\033[0;31mClickhouse isn't running. Please run\n\tdocker compose -f ee/docker-compose.ch.arm64.yml up zookeeper kafka clickhouse db redis.\nI'll wait while you do that.\033[0m" ; bin/check_kafka_clickhouse_up ) wget -nv -t1 --spider 'http://localhost:8123/' || ( echo -e "\033[0;31mClickhouse isn't running. Please run\n\tdocker compose -f docker-compose.arm64.yml up zookeeper kafka clickhouse db redis.\nI'll wait while you do that.\033[0m" ; bin/check_kafka_clickhouse_up )
trap "trap - SIGTERM && yarn remove cypress cypress-terminal-report @cypress/react @cypress/webpack-preprocessor && kill -- -$$" SIGINT SIGTERM EXIT trap "trap - SIGTERM && yarn remove cypress cypress-terminal-report @cypress/react @cypress/webpack-preprocessor && kill -- -$$" SIGINT SIGTERM EXIT

View File

@ -1,4 +1,141 @@
import pytest import pytest
from infi.clickhouse_orm import Database
from ee.clickhouse.client import sync_execute
from ee.clickhouse.sql.dead_letter_queue import (
DEAD_LETTER_QUEUE_TABLE_MV_SQL,
KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL,
TRUNCATE_DEAD_LETTER_QUEUE_TABLE_MV_SQL,
)
from posthog.settings import (
CLICKHOUSE_DATABASE,
CLICKHOUSE_HTTP_URL,
CLICKHOUSE_PASSWORD,
CLICKHOUSE_USER,
CLICKHOUSE_VERIFY,
)
from posthog.test.base import TestMixin
def create_clickhouse_tables(num_tables: int):
# Reset clickhouse tables to default before running test
# Mostly so that test runs locally work correctly
from ee.clickhouse.sql.cohort import CREATE_COHORTPEOPLE_TABLE_SQL
from ee.clickhouse.sql.dead_letter_queue import DEAD_LETTER_QUEUE_TABLE_SQL
from ee.clickhouse.sql.events import EVENTS_TABLE_SQL
from ee.clickhouse.sql.groups import GROUPS_TABLE_SQL
from ee.clickhouse.sql.person import (
PERSON_DISTINCT_ID2_TABLE_SQL,
PERSON_STATIC_COHORT_TABLE_SQL,
PERSONS_DISTINCT_ID_TABLE_SQL,
PERSONS_TABLE_SQL,
)
from ee.clickhouse.sql.plugin_log_entries import PLUGIN_LOG_ENTRIES_TABLE_SQL
from ee.clickhouse.sql.session_recording_events import SESSION_RECORDING_EVENTS_TABLE_SQL
# REMEMBER TO ADD ANY NEW CLICKHOUSE TABLES TO THIS ARRAY!
TABLES_TO_CREATE_DROP = [
EVENTS_TABLE_SQL(),
PERSONS_TABLE_SQL(),
PERSONS_DISTINCT_ID_TABLE_SQL(),
PERSON_DISTINCT_ID2_TABLE_SQL(),
PERSON_STATIC_COHORT_TABLE_SQL(),
SESSION_RECORDING_EVENTS_TABLE_SQL(),
PLUGIN_LOG_ENTRIES_TABLE_SQL(),
CREATE_COHORTPEOPLE_TABLE_SQL(),
KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL,
DEAD_LETTER_QUEUE_TABLE_SQL(),
DEAD_LETTER_QUEUE_TABLE_MV_SQL,
GROUPS_TABLE_SQL(),
]
if num_tables == len(TABLES_TO_CREATE_DROP):
return
for item in TABLES_TO_CREATE_DROP:
sync_execute(item)
def reset_clickhouse_tables():
# Reset clickhouse tables to default before running test
# Mostly so that test runs locally work correctly
from ee.clickhouse.sql.cohort import TRUNCATE_COHORTPEOPLE_TABLE_SQL
from ee.clickhouse.sql.dead_letter_queue import TRUNCATE_DEAD_LETTER_QUEUE_TABLE_SQL
from ee.clickhouse.sql.events import TRUNCATE_EVENTS_TABLE_SQL
from ee.clickhouse.sql.groups import TRUNCATE_GROUPS_TABLE_SQL
from ee.clickhouse.sql.person import (
TRUNCATE_PERSON_DISTINCT_ID2_TABLE_SQL,
TRUNCATE_PERSON_DISTINCT_ID_TABLE_SQL,
TRUNCATE_PERSON_STATIC_COHORT_TABLE_SQL,
TRUNCATE_PERSON_TABLE_SQL,
)
from ee.clickhouse.sql.plugin_log_entries import TRUNCATE_PLUGIN_LOG_ENTRIES_TABLE_SQL
from ee.clickhouse.sql.session_recording_events import TRUNCATE_SESSION_RECORDING_EVENTS_TABLE_SQL
# REMEMBER TO ADD ANY NEW CLICKHOUSE TABLES TO THIS ARRAY!
TABLES_TO_CREATE_DROP = [
TRUNCATE_EVENTS_TABLE_SQL,
TRUNCATE_PERSON_TABLE_SQL,
TRUNCATE_PERSON_DISTINCT_ID_TABLE_SQL,
TRUNCATE_PERSON_DISTINCT_ID2_TABLE_SQL,
TRUNCATE_PERSON_STATIC_COHORT_TABLE_SQL,
TRUNCATE_SESSION_RECORDING_EVENTS_TABLE_SQL,
TRUNCATE_PLUGIN_LOG_ENTRIES_TABLE_SQL,
TRUNCATE_COHORTPEOPLE_TABLE_SQL,
TRUNCATE_DEAD_LETTER_QUEUE_TABLE_SQL,
TRUNCATE_DEAD_LETTER_QUEUE_TABLE_MV_SQL,
TRUNCATE_GROUPS_TABLE_SQL,
]
for item in TABLES_TO_CREATE_DROP:
sync_execute(item)
@pytest.fixture(scope="package")
def django_db_setup(django_db_setup, django_db_keepdb):
database = Database(
CLICKHOUSE_DATABASE,
db_url=CLICKHOUSE_HTTP_URL,
username=CLICKHOUSE_USER,
password=CLICKHOUSE_PASSWORD,
verify_ssl_cert=CLICKHOUSE_VERIFY,
)
if not django_db_keepdb:
try:
database.drop_database()
except:
pass
database.create_database() # Create database if it doesn't exist
table_count = sync_execute(
"SELECT count() FROM system.tables WHERE database = %(database)s", {"database": CLICKHOUSE_DATABASE}
)[0][0]
create_clickhouse_tables(table_count)
yield
if django_db_keepdb:
reset_clickhouse_tables()
else:
try:
database.drop_database()
except:
pass
@pytest.fixture
def base_test_mixin_fixture():
kls = TestMixin()
kls.setUp()
kls.setUpTestData()
return kls
@pytest.fixture
def team(base_test_mixin_fixture):
return base_test_mixin_fixture.team
# :TRICKY: Integrate syrupy with unittest test cases # :TRICKY: Integrate syrupy with unittest test cases

View File

@ -8,7 +8,6 @@
"cloud": false, "cloud": false,
"available_social_auth_providers": { "google-oauth2": false, "github": false, "gitlab": false }, "available_social_auth_providers": { "google-oauth2": false, "github": false, "gitlab": false },
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0.0, "Africa/Abidjan": 0.0,

View File

@ -25,10 +25,10 @@ services:
- '9440:9440' - '9440:9440'
- '9009:9009' - '9009:9009'
volumes: volumes:
- ./idl:/idl - ./ee/idl:/idl
- ../docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d - ./docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
- ../docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml - ./docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml
- ../docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml - ./docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml
zookeeper: zookeeper:
image: zookeeper image: zookeeper
restart: always restart: always
@ -43,11 +43,11 @@ services:
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
worker: &worker worker: &worker
build: build:
context: ../ context: .
dockerfile: dev.Dockerfile dockerfile: dev.Dockerfile
command: ./bin/docker-worker-celery --with-scheduler command: ./bin/docker-worker-celery --with-scheduler
volumes: volumes:
- ..:/code - .:/code
environment: environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog' DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'
CLICKHOUSE_HOST: 'clickhouse' CLICKHOUSE_HOST: 'clickhouse'
@ -58,7 +58,6 @@ services:
REDIS_URL: 'redis://redis:6379/' REDIS_URL: 'redis://redis:6379/'
SECRET_KEY: 'alsdfjiosdajfklalsdjkf' SECRET_KEY: 'alsdfjiosdajfklalsdjkf'
DEBUG: 'true' DEBUG: 'true'
PRIMARY_DB: 'clickhouse'
PGHOST: db PGHOST: db
PGUSER: posthog PGUSER: posthog
PGPASSWORD: posthog PGPASSWORD: posthog
@ -80,11 +79,11 @@ services:
- '8234:8234' - '8234:8234'
plugins: plugins:
build: build:
context: ../ context: .
dockerfile: dev.Dockerfile dockerfile: dev.Dockerfile
command: ./bin/plugin-server --no-restart-loop command: ./bin/plugin-server --no-restart-loop
volumes: volumes:
- ..:/code - .:/code
restart: on-failure restart: on-failure
environment: environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog' DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'

View File

@ -3,7 +3,6 @@ version: '3'
services: services:
db: db:
image: postgres:12-alpine image: postgres:12-alpine
container_name: posthog_db
environment: environment:
POSTGRES_USER: posthog POSTGRES_USER: posthog
POSTGRES_DB: posthog POSTGRES_DB: posthog
@ -11,21 +10,53 @@ services:
ports: ports:
- '5432:5432' - '5432:5432'
redis: redis:
image: 'redis:5-alpine' image: 'redis:alpine'
container_name: posthog_redis
ports: ports:
- '6379:6379' - '6379:6379'
backend: &backend clickhouse:
# KEEP CLICKHOUSE-SERVER VERSION IN SYNC WITH
# https://github.com/PostHog/charts-clickhouse/blob/main/charts/posthog/templates/clickhouse_instance.yaml#L88
image: yandex/clickhouse-server:21.6.5
depends_on:
- kafka
- zookeeper
ports:
- '8123:8123'
- '9000:9000'
- '9440:9440'
- '9009:9009'
volumes:
- ./ee/idl:/idl
- ./docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
- ./docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml
- ./docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml
zookeeper:
image: wurstmeister/zookeeper
kafka:
image: wurstmeister/kafka
depends_on:
- zookeeper
ports:
- '9092:9092'
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
worker: &worker
build: build:
context: . context: .
dockerfile: dev.Dockerfile dockerfile: dev.Dockerfile
command: ./bin/docker-backend command: ./bin/docker-worker-celery --with-scheduler
volumes: volumes:
- .:/code - .:/code
environment: environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog' DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'
CLICKHOUSE_HOST: 'clickhouse'
CLICKHOUSE_DATABASE: 'posthog'
CLICKHOUSE_SECURE: 'false'
CLICKHOUSE_VERIFY: 'false'
KAFKA_URL: 'kafka://kafka'
REDIS_URL: 'redis://redis:6379/' REDIS_URL: 'redis://redis:6379/'
SECRET_KEY: '<randomly generated secret key>' SECRET_KEY: 'alsdfjiosdajfklalsdjkf'
DEBUG: 'true' DEBUG: 'true'
PGHOST: db PGHOST: db
PGUSER: posthog PGUSER: posthog
@ -33,21 +64,40 @@ services:
depends_on: depends_on:
- db - db
- redis - redis
- clickhouse
- kafka
links: links:
- db:db - db:db
- redis:redis - redis:redis
- clickhouse:clickhouse
- kafka:kafka
web:
<<: *worker
command: '${CH_WEB_SCRIPT:-./ee/bin/docker-ch-dev-web}'
ports: ports:
- '8000:8000' - '8000:8000'
frontend:
<<: *backend
command: ./bin/docker-frontend
ports:
- '8234:8234' - '8234:8234'
worker: plugins:
<<: *backend build:
command: ./bin/docker-worker context: .
ports: [] dockerfile: dev.Dockerfile
command: ./bin/plugin-server --no-restart-loop
volumes:
- .:/code
restart: on-failure
environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'
KAFKA_ENABLED: 'true'
KAFKA_HOSTS: 'kafka:9092'
REDIS_URL: 'redis://redis:6379/'
CLICKHOUSE_HOST: 'clickhouse'
depends_on: depends_on:
- db - db
- redis - redis
- backend - clickhouse
- kafka
links:
- db:db
- redis:redis
- clickhouse:clickhouse
- kafka:kafka

View File

@ -1,34 +0,0 @@
version: '3'
services:
db:
image: postgres:alpine
container_name: posthog_db
environment:
POSTGRES_USER: posthog
POSTGRES_DB: posthog
POSTGRES_PASSWORD: posthog
redis:
image: 'redis:alpine'
container_name: posthog_redis
web:
container_name: posthog_server
build:
context: .
dockerfile: production.Dockerfile
command: ./bin/docker & tail -f /dev/null
ports:
- '8000:8000'
environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'
REDIS_URL: 'redis://redis:6379/'
SECRET_KEY: '<randomly generated secret key>'
DEBUG: 1
DISABLE_SECURE_SSL_REDIRECT: 1
OPT_OUT_CAPTURE: 1
depends_on:
- db
- redis
links:
- db:db
- redis:redis

View File

@ -61,7 +61,6 @@ services:
KAFKA_URL: 'kafka://kafka' KAFKA_URL: 'kafka://kafka'
REDIS_URL: 'redis://redis:6379/' REDIS_URL: 'redis://redis:6379/'
SECRET_KEY: ${POSTHOG_SECRET} SECRET_KEY: ${POSTHOG_SECRET}
PRIMARY_DB: 'clickhouse'
PGHOST: db PGHOST: db
PGUSER: posthog PGUSER: posthog
PGPASSWORD: posthog PGPASSWORD: posthog

View File

@ -3,11 +3,11 @@ version: '3'
services: services:
test: test:
build: build:
context: ../ context: .
dockerfile: dev.Dockerfile dockerfile: dev.Dockerfile
command: ./ee/bin/docker-ch-test command: ./ee/bin/docker-ch-test
volumes: volumes:
- ..:/code - .:/code
environment: environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog' DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'
CLICKHOUSE_HOST: 'clickhouse' CLICKHOUSE_HOST: 'clickhouse'
@ -17,7 +17,6 @@ services:
REDIS_URL: 'redis://redis:6379/' REDIS_URL: 'redis://redis:6379/'
SECRET_KEY: 'alsdfjiosdajfklalsdjkf' SECRET_KEY: 'alsdfjiosdajfklalsdjkf'
DEBUG: 'true' DEBUG: 'true'
PRIMARY_DB: 'clickhouse'
TEST: 'true' TEST: 'true'
depends_on: depends_on:
- db - db

View File

@ -11,19 +11,59 @@ services:
redis: redis:
container_name: posthog_redis container_name: posthog_redis
image: redis:6-alpine image: redis:6-alpine
clickhouse:
# KEEP CLICKHOUSE-SERVER VERSION IN SYNC WITH
# https://github.com/PostHog/charts-clickhouse/blob/main/charts/posthog/templates/clickhouse_instance.yaml#L88
image: yandex/clickhouse-server:21.6.5
depends_on:
- kafka
- zookeeper
ports:
- '8123:8123'
- '9000:9000'
- '9440:9440'
- '9009:9009'
volumes:
- ./ee/idl:/idl
- ./docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
- ./docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml
- ./docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml
zookeeper:
image: wurstmeister/zookeeper
kafka:
image: wurstmeister/kafka
depends_on:
- zookeeper
ports:
- '9092:9092'
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
web: web:
container_name: posthog_web container_name: posthog_web
depends_on: depends_on:
- db - db
- redis - redis
- clickhouse
- kafka
environment: environment:
DATABASE_URL: postgres://posthog:posthog@db:5432/posthog DATABASE_URL: postgres://posthog:posthog@db:5432/posthog
REDIS_URL: redis://redis:6379/ REDIS_URL: redis://redis:6379/
KAFKA_URL: 'kafka://kafka'
CLICKHOUSE_HOST: 'clickhouse'
CLICKHOUSE_DATABASE: 'posthog'
CLICKHOUSE_SECURE: 'false'
CLICKHOUSE_VERIFY: 'false'
SECRET_KEY: <randomly generated secret key> SECRET_KEY: <randomly generated secret key>
PGHOST: db
PGUSER: posthog
PGPASSWORD: posthog
image: posthog/posthog:latest image: posthog/posthog:latest
links: links:
- db:db - db:db
- redis:redis - redis:redis
- clickhouse:clickhouse
- kafka:kafka
ports: ports:
- 8000:8000 - 8000:8000
- 80:8000 - 80:8000

View File

@ -4,7 +4,6 @@ from django.urls.base import resolve
from loginas.utils import is_impersonated_session from loginas.utils import is_impersonated_session
from posthog.internal_metrics import incr from posthog.internal_metrics import incr
from posthog.utils import is_clickhouse_enabled
class CHQueries(object): class CHQueries(object):
@ -23,11 +22,7 @@ class CHQueries(object):
route = resolve(request.path) route = resolve(request.path)
route_id = f"{route.route} ({route.func.__name__})" route_id = f"{route.route} ({route.func.__name__})"
client._request_information = { client._request_information = {
"save": ( "save": (request.user.pk and (request.user.is_staff or is_impersonated_session(request) or settings.DEBUG)),
is_clickhouse_enabled()
and request.user.pk
and (request.user.is_staff or is_impersonated_session(request) or settings.DEBUG)
),
"user_id": request.user.pk, "user_id": request.user.pk,
"kind": "request", "kind": "request",
"id": route_id, "id": route_id,

View File

@ -22,9 +22,8 @@ from ee.kafka_client.topics import KAFKA_PERSON, KAFKA_PERSON_DISTINCT_ID, KAFKA
from posthog.models.person import Person, PersonDistinctId from posthog.models.person import Person, PersonDistinctId
from posthog.models.utils import UUIDT from posthog.models.utils import UUIDT
from posthog.settings import TEST from posthog.settings import TEST
from posthog.utils import is_clickhouse_enabled
if is_clickhouse_enabled() and TEST: if TEST:
# :KLUDGE: Hooks are kept around for tests. All other code goes through plugin-server or the other methods explicitly # :KLUDGE: Hooks are kept around for tests. All other code goes through plugin-server or the other methods explicitly
@receiver(post_save, sender=Person) @receiver(post_save, sender=Person)

View File

@ -68,18 +68,6 @@ class TestFilters(PGTestFilters):
{"properties": [{"type": "precalculated-cohort", "key": "id", "value": cohort.pk, "operator": None},]}, {"properties": [{"type": "precalculated-cohort", "key": "id", "value": cohort.pk, "operator": None},]},
) )
def test_simplify_not_ee(self):
cohort = Cohort.objects.create(
team=self.team,
groups=[{"properties": [{"key": "email", "operator": "icontains", "value": ".com", "type": "person"}]}],
)
filter = Filter(data={"properties": [{"type": "cohort", "key": "id", "value": cohort.pk}]})
self.assertEqual(
filter.simplify(self.team, is_clickhouse_enabled=False).properties_to_dict(),
{"properties": [{"type": "cohort", "key": "id", "value": cohort.pk, "operator": None}]},
)
def test_simplify_static_cohort(self): def test_simplify_static_cohort(self):
cohort = Cohort.objects.create(team=self.team, groups=[], is_static=True) cohort = Cohort.objects.create(team=self.team, groups=[], is_static=True)
filter = Filter(data={"properties": [{"type": "cohort", "key": "id", "value": cohort.pk}]}) filter = Filter(data={"properties": [{"type": "cohort", "key": "id", "value": cohort.pk}]})

View File

@ -1,5 +1,5 @@
import json
import urllib.parse import urllib.parse
import uuid
from abc import ABC from abc import ABC
from typing import Any, Dict, List, Optional, Tuple, Union, cast from typing import Any, Dict, List, Optional, Tuple, Union, cast
@ -26,11 +26,10 @@ from posthog.constants import (
TREND_FILTER_TYPE_ACTIONS, TREND_FILTER_TYPE_ACTIONS,
) )
from posthog.models import Entity, Filter, Team from posthog.models import Entity, Filter, Team
from posthog.queries.funnel import Funnel
from posthog.utils import relative_date_parse from posthog.utils import relative_date_parse
class ClickhouseFunnelBase(ABC, Funnel): class ClickhouseFunnelBase(ABC):
_filter: Filter _filter: Filter
_team: Team _team: Team
_include_timestamp: Optional[bool] _include_timestamp: Optional[bool]
@ -81,6 +80,21 @@ class ClickhouseFunnelBase(ABC, Funnel):
results = self._exec_query() results = self._exec_query()
return self._format_results(results) return self._format_results(results)
def _serialize_step(self, step: Entity, count: int, people: Optional[List[uuid.UUID]] = None) -> Dict[str, Any]:
if step.type == TREND_FILTER_TYPE_ACTIONS:
name = step.get_action().name
else:
name = step.id
return {
"action_id": step.id,
"name": name,
"custom_name": step.custom_name,
"order": step.order,
"people": people if people else [],
"count": count,
"type": step.type,
}
def _update_filters(self): def _update_filters(self):
# format default dates # format default dates
data: Dict[str, Any] = {} data: Dict[str, Any] = {}

View File

@ -8,7 +8,6 @@ from ee.clickhouse.queries.trends.clickhouse_trends import ClickhouseTrends
from posthog.constants import TRENDS_CUMULATIVE, TRENDS_PIE from posthog.constants import TRENDS_CUMULATIVE, TRENDS_PIE
from posthog.models import Cohort, Person from posthog.models import Cohort, Person
from posthog.models.filters.filter import Filter from posthog.models.filters.filter import Filter
from posthog.queries.abstract_test.test_interval import AbstractIntervalTest
from posthog.test.base import APIBaseTest from posthog.test.base import APIBaseTest
@ -17,7 +16,7 @@ def _create_event(**kwargs):
create_event(**kwargs) create_event(**kwargs)
class TestFormula(AbstractIntervalTest, APIBaseTest): class TestFormula(APIBaseTest):
CLASS_DATA_LEVEL_SETUP = False CLASS_DATA_LEVEL_SETUP = False
def setUp(self): def setUp(self):

View File

@ -15,7 +15,6 @@ from posthog.settings import (
CLICKHOUSE_VERIFY, CLICKHOUSE_VERIFY,
) )
from posthog.test.base import TestMixin from posthog.test.base import TestMixin
from posthog.utils import is_clickhouse_enabled
def create_clickhouse_tables(num_tables: int): def create_clickhouse_tables(num_tables: int):
@ -92,39 +91,37 @@ def reset_clickhouse_tables():
sync_execute(item) sync_execute(item)
if is_clickhouse_enabled(): @pytest.fixture(scope="package")
def django_db_setup(django_db_setup, django_db_keepdb):
database = Database(
CLICKHOUSE_DATABASE,
db_url=CLICKHOUSE_HTTP_URL,
username=CLICKHOUSE_USER,
password=CLICKHOUSE_PASSWORD,
verify_ssl_cert=CLICKHOUSE_VERIFY,
)
@pytest.fixture(scope="package") if not django_db_keepdb:
def django_db_setup(django_db_setup, django_db_keepdb): try:
database = Database( database.drop_database()
CLICKHOUSE_DATABASE, except:
db_url=CLICKHOUSE_HTTP_URL, pass
username=CLICKHOUSE_USER,
password=CLICKHOUSE_PASSWORD,
verify_ssl_cert=CLICKHOUSE_VERIFY,
)
if not django_db_keepdb: database.create_database() # Create database if it doesn't exist
try: table_count = sync_execute(
database.drop_database() "SELECT count() FROM system.tables WHERE database = %(database)s", {"database": CLICKHOUSE_DATABASE}
except: )[0][0]
pass create_clickhouse_tables(table_count)
database.create_database() # Create database if it doesn't exist yield
table_count = sync_execute(
"SELECT count() FROM system.tables WHERE database = %(database)s", {"database": CLICKHOUSE_DATABASE}
)[0][0]
create_clickhouse_tables(table_count)
yield if django_db_keepdb:
reset_clickhouse_tables()
if django_db_keepdb: else:
reset_clickhouse_tables() try:
else: database.drop_database()
try: except:
database.drop_database() pass
except:
pass
@pytest.fixture @pytest.fixture

View File

@ -1,104 +0,0 @@
version: '3'
services:
db:
image: postgres:12-alpine
environment:
POSTGRES_USER: posthog
POSTGRES_DB: posthog
POSTGRES_PASSWORD: posthog
ports:
- '5432:5432'
redis:
image: 'redis:alpine'
ports:
- '6379:6379'
clickhouse:
# KEEP CLICKHOUSE-SERVER VERSION IN SYNC WITH
# https://github.com/PostHog/charts-clickhouse/blob/main/charts/posthog/templates/clickhouse_instance.yaml#L88
image: yandex/clickhouse-server:21.6.5
depends_on:
- kafka
- zookeeper
ports:
- '8123:8123'
- '9000:9000'
- '9440:9440'
- '9009:9009'
volumes:
- ./idl:/idl
- ../docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
- ../docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml
- ../docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml
zookeeper:
image: wurstmeister/zookeeper
kafka:
image: wurstmeister/kafka
depends_on:
- zookeeper
ports:
- '9092:9092'
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
worker: &worker
build:
context: ../
dockerfile: dev.Dockerfile
command: ./bin/docker-worker-celery --with-scheduler
volumes:
- ..:/code
environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'
CLICKHOUSE_HOST: 'clickhouse'
CLICKHOUSE_DATABASE: 'posthog'
CLICKHOUSE_SECURE: 'false'
CLICKHOUSE_VERIFY: 'false'
KAFKA_URL: 'kafka://kafka'
REDIS_URL: 'redis://redis:6379/'
SECRET_KEY: 'alsdfjiosdajfklalsdjkf'
DEBUG: 'true'
PRIMARY_DB: 'clickhouse'
PGHOST: db
PGUSER: posthog
PGPASSWORD: posthog
depends_on:
- db
- redis
- clickhouse
- kafka
links:
- db:db
- redis:redis
- clickhouse:clickhouse
- kafka:kafka
web:
<<: *worker
command: '${CH_WEB_SCRIPT:-./ee/bin/docker-ch-dev-web}'
ports:
- '8000:8000'
- '8234:8234'
plugins:
build:
context: ../
dockerfile: dev.Dockerfile
command: ./bin/plugin-server --no-restart-loop
volumes:
- ..:/code
restart: on-failure
environment:
DATABASE_URL: 'postgres://posthog:posthog@db:5432/posthog'
KAFKA_ENABLED: 'true'
KAFKA_HOSTS: 'kafka:9092'
REDIS_URL: 'redis://redis:6379/'
CLICKHOUSE_HOST: 'clickhouse'
depends_on:
- db
- redis
- clickhouse
- kafka
links:
- db:db
- redis:redis
- clickhouse:clickhouse
- kafka:kafka

View File

@ -1,7 +1,5 @@
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from posthog.utils import is_clickhouse_enabled
class Command(BaseCommand): class Command(BaseCommand):
help = "Set up databases for non-Python tests that depend on the Django server" help = "Set up databases for non-Python tests that depend on the Django server"
@ -13,28 +11,27 @@ class Command(BaseCommand):
test_runner.setup_databases() test_runner.setup_databases()
test_runner.setup_test_environment() test_runner.setup_test_environment()
if is_clickhouse_enabled(): from infi.clickhouse_orm import Database
from infi.clickhouse_orm import Database
from posthog.settings import ( from posthog.settings import (
CLICKHOUSE_DATABASE, CLICKHOUSE_DATABASE,
CLICKHOUSE_HTTP_URL, CLICKHOUSE_HTTP_URL,
CLICKHOUSE_PASSWORD, CLICKHOUSE_PASSWORD,
CLICKHOUSE_REPLICATION, CLICKHOUSE_REPLICATION,
CLICKHOUSE_USER, CLICKHOUSE_USER,
CLICKHOUSE_VERIFY, CLICKHOUSE_VERIFY,
) )
database = Database( database = Database(
CLICKHOUSE_DATABASE, CLICKHOUSE_DATABASE,
db_url=CLICKHOUSE_HTTP_URL, db_url=CLICKHOUSE_HTTP_URL,
username=CLICKHOUSE_USER, username=CLICKHOUSE_USER,
password=CLICKHOUSE_PASSWORD, password=CLICKHOUSE_PASSWORD,
verify_ssl_cert=CLICKHOUSE_VERIFY, verify_ssl_cert=CLICKHOUSE_VERIFY,
) )
try: try:
database.create_database() database.create_database()
except: except:
pass pass
database.migrate("ee.clickhouse.migrations", replicated=CLICKHOUSE_REPLICATION) database.migrate("ee.clickhouse.migrations", replicated=CLICKHOUSE_REPLICATION)

View File

@ -30,7 +30,7 @@ def create_event_clickhouse(
) )
class TestOrganizationUsageReport(ClickhouseTestMixin, factory_org_usage_report(create_person, create_event_clickhouse, send_all_org_usage_reports, {"EE_AVAILABLE": True, "USE_TZ": False, "PRIMARY_DB": AnalyticsDBMS.CLICKHOUSE})): # type: ignore class TestOrganizationUsageReport(ClickhouseTestMixin, factory_org_usage_report(create_person, create_event_clickhouse, send_all_org_usage_reports, {"USE_TZ": False, "PRIMARY_DB": AnalyticsDBMS.CLICKHOUSE})): # type: ignore
def test_groups_usage(self): def test_groups_usage(self):
GroupTypeMapping.objects.create(team=self.team, group_type="organization", group_type_index=0) GroupTypeMapping.objects.create(team=self.team, group_type="organization", group_type_index=0)
GroupTypeMapping.objects.create(team=self.team, group_type="company", group_type_index=1) GroupTypeMapping.objects.create(team=self.team, group_type="company", group_type_index=1)

View File

@ -106,7 +106,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": {}, "available_timezones": {},
"opt_out_capture": false, "opt_out_capture": false,

View File

@ -77,7 +77,7 @@ export const mockAPI = (
export function defaultAPIMocks({ pathname, searchParams }: APIRoute, availableFeatures: AvailableFeature[] = []): any { export function defaultAPIMocks({ pathname, searchParams }: APIRoute, availableFeatures: AvailableFeature[] = []): any {
const organization = { ...MOCK_DEFAULT_ORGANIZATION, available_features: availableFeatures } const organization = { ...MOCK_DEFAULT_ORGANIZATION, available_features: availableFeatures }
if (pathname === '_preflight/') { if (pathname === '_preflight/') {
return { is_clickhouse_enabled: true } return {}
} else if (pathname === 'api/users/@me/') { } else if (pathname === 'api/users/@me/') {
return { return {
organization, organization,

View File

@ -11,7 +11,6 @@ import {
TableOutlined, TableOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import { ChartDisplayType, FilterType, FunnelVizType, InsightType } from '~/types' import { ChartDisplayType, FilterType, FunnelVizType, InsightType } from '~/types'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { ANTD_TOOLTIP_PLACEMENTS } from 'lib/utils' import { ANTD_TOOLTIP_PLACEMENTS } from 'lib/utils'
import { insightLogic } from 'scenes/insights/insightLogic' import { insightLogic } from 'scenes/insights/insightLogic'
@ -25,7 +24,6 @@ export function ChartFilter({ filters, onChange, disabled }: ChartFilterProps):
const { insightProps } = useValues(insightLogic) const { insightProps } = useValues(insightLogic)
const { chartFilter } = useValues(chartFilterLogic(insightProps)) const { chartFilter } = useValues(chartFilterLogic(insightProps))
const { setChartFilter } = useActions(chartFilterLogic(insightProps)) const { setChartFilter } = useActions(chartFilterLogic(insightProps))
const { preflight } = useValues(preflightLogic)
const cumulativeDisabled = filters.insight === InsightType.STICKINESS || filters.insight === InsightType.RETENTION const cumulativeDisabled = filters.insight === InsightType.STICKINESS || filters.insight === InsightType.RETENTION
const tableDisabled = false const tableDisabled = false
@ -58,28 +56,21 @@ export function ChartFilter({ filters, onChange, disabled }: ChartFilterProps):
const options = const options =
filters.insight === InsightType.FUNNELS filters.insight === InsightType.FUNNELS
? preflight?.is_clickhouse_enabled ? [
? [ {
{ value: FunnelVizType.Steps,
value: FunnelVizType.Steps, label: <Label icon={<OrderedListOutlined />}>Steps</Label>,
label: <Label icon={<OrderedListOutlined />}>Steps</Label>, },
}, {
{ value: FunnelVizType.Trends,
value: FunnelVizType.Trends, label: (
label: ( <Label icon={<LineChartOutlined />}>
<Label icon={<LineChartOutlined />}> Trends
Trends <WarningTag>BETA</WarningTag>
<WarningTag>BETA</WarningTag> </Label>
</Label> ),
), },
}, ]
]
: [
{
value: FunnelVizType.Steps,
label: <Label icon={<OrderedListOutlined />}>Steps</Label>,
},
]
: [ : [
{ {
label: 'Line Chart', label: 'Line Chart',

View File

@ -20,24 +20,22 @@ export const groupsAccessLogic = kea<groupsAccessLogicType<GroupsAccessStatus>>(
teamLogic, teamLogic,
['currentTeam'], ['currentTeam'],
preflightLogic, preflightLogic,
['clickhouseEnabled', 'preflight'], ['preflight'],
userLogic, userLogic,
['hasAvailableFeature', 'upgradeLink'], ['hasAvailableFeature', 'upgradeLink'],
], ],
}, },
selectors: { selectors: {
groupsCanBeEnabled: [(s) => [s.clickhouseEnabled], (clickhouseEnabled) => clickhouseEnabled],
groupsEnabled: [ groupsEnabled: [
(s) => [s.groupsCanBeEnabled, s.hasAvailableFeature], (s) => [s.hasAvailableFeature],
(groupsCanBeEnabled, hasAvailableFeature) => (hasAvailableFeature) => hasAvailableFeature(AvailableFeature.GROUP_ANALYTICS),
groupsCanBeEnabled && hasAvailableFeature(AvailableFeature.GROUP_ANALYTICS),
], ],
// Used to toggle various introduction views related to groups // Used to toggle various introduction views related to groups
groupsAccessStatus: [ groupsAccessStatus: [
(s) => [s.groupsCanBeEnabled, s.groupsEnabled, s.currentTeam, s.preflight], (s) => [s.groupsEnabled, s.currentTeam, s.preflight],
(canBeEnabled, isEnabled, currentTeam, preflight): GroupsAccessStatus => { (isEnabled, currentTeam, preflight): GroupsAccessStatus => {
const hasGroups = currentTeam?.has_group_types const hasGroups = currentTeam?.has_group_types
if (!canBeEnabled || preflight?.instance_preferences?.disable_paid_fs) { if (preflight?.instance_preferences?.disable_paid_fs) {
return GroupsAccessStatus.Hidden return GroupsAccessStatus.Hidden
} else if (isEnabled && hasGroups) { } else if (isEnabled && hasGroups) {
return GroupsAccessStatus.AlreadyUsing return GroupsAccessStatus.AlreadyUsing

View File

@ -35,7 +35,6 @@ export const preflightLogic = kea<preflightLogicType<PreflightMode>>({
(preflight): boolean => (preflight): boolean =>
Boolean(preflight && Object.values(preflight.available_social_auth_providers).filter((i) => i).length), Boolean(preflight && Object.values(preflight.available_social_auth_providers).filter((i) => i).length),
], ],
clickhouseEnabled: [(s) => [s.preflight], (preflight): boolean => !!preflight?.is_clickhouse_enabled],
realm: [ realm: [
(s) => [s.preflight], (s) => [s.preflight],
(preflight): Realm | null => { (preflight): Realm | null => {
@ -82,8 +81,6 @@ export const preflightLogic = kea<preflightLogicType<PreflightMode>>({
posthog.register({ posthog.register({
posthog_version: values.preflight.posthog_version, posthog_version: values.preflight.posthog_version,
realm: values.realm, realm: values.realm,
is_clickhouse_enabled: values.preflight.is_clickhouse_enabled,
ee_available: values.preflight.ee_available,
email_service_available: values.preflight.email_service_available, email_service_available: values.preflight.email_service_available,
}) })

View File

@ -5,7 +5,6 @@ import { router } from 'kea-router'
import { eventsTableLogic } from 'scenes/events/eventsTableLogic' import { eventsTableLogic } from 'scenes/events/eventsTableLogic'
import { EventsTable } from 'scenes/events' import { EventsTable } from 'scenes/events'
import { urls } from 'scenes/urls' import { urls } from 'scenes/urls'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { ActionType } from '~/types' import { ActionType } from '~/types'
import { dayjs } from 'lib/dayjs' import { dayjs } from 'lib/dayjs'
import { Spinner } from 'lib/components/Spinner/Spinner' import { Spinner } from 'lib/components/Spinner/Spinner'
@ -33,8 +32,6 @@ export function Action({ id }: { id?: ActionType['id'] } = {}): JSX.Element {
) )
const { action, isComplete } = useValues(actionLogic({ id, onComplete: fetchEvents })) const { action, isComplete } = useValues(actionLogic({ id, onComplete: fetchEvents }))
const { loadAction } = useActions(actionLogic({ id, onComplete: fetchEvents })) const { loadAction } = useActions(actionLogic({ id, onComplete: fetchEvents }))
const { preflight } = useValues(preflightLogic)
const isClickHouseEnabled = !!preflight?.is_clickhouse_enabled
return ( return (
<div> <div>
@ -61,25 +58,23 @@ export function Action({ id }: { id?: ActionType['id'] } = {}): JSX.Element {
)} )}
{isComplete && ( {isComplete && (
<div style={{ marginTop: 86 }}> <div style={{ marginTop: 86 }}>
{!isClickHouseEnabled ? ( <>
<> <h2 className="subtitle">Event List</h2>
<h2 className="subtitle">Event List</h2> <p className="text-muted">
<p className="text-muted"> List of the events that match this action.{' '}
List of the events that match this action.{' '} {action && (
{action && ( <>
<> This list was{' '}
This list was{' '} <b>
<b> calculated{' '}
calculated{' '} {action.last_calculated_at
{action.last_calculated_at ? dayjs(action.last_calculated_at).fromNow()
? dayjs(action.last_calculated_at).fromNow() : 'a while ago'}
: 'a while ago'} </b>
</b> </>
</> )}
)} </p>{' '}
</p>{' '} </>
</>
) : null}
{id && ( {id && (
<> <>
<PageHeader <PageHeader

View File

@ -184,7 +184,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,

View File

@ -184,7 +184,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,

View File

@ -2,13 +2,10 @@ import React from 'react'
import { Row, Col } from 'antd' import { Row, Col } from 'antd'
import { CohortType } from '~/types' import { CohortType } from '~/types'
import { TeamMemberID } from 'lib/components/TeamMemberID' import { TeamMemberID } from 'lib/components/TeamMemberID'
import { useValues } from 'kea'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { dayjs } from 'lib/dayjs' import { dayjs } from 'lib/dayjs'
export function CohortDetailsRow({ cohort }: { cohort: CohortType }): JSX.Element { export function CohortDetailsRow({ cohort }: { cohort: CohortType }): JSX.Element {
const { preflight } = useValues(preflightLogic) const columnSize = 12
const columnSize = preflight?.is_clickhouse_enabled ? 12 : 8
return ( return (
<Row justify="space-between" align="top" className="mt text-center"> <Row justify="space-between" align="top" className="mt text-center">
<Col span={columnSize}> <Col span={columnSize}>
@ -21,13 +18,11 @@ export function CohortDetailsRow({ cohort }: { cohort: CohortType }): JSX.Elemen
<TeamMemberID person={cohort.created_by} /> <TeamMemberID person={cohort.created_by} />
</div> </div>
</Col> </Col>
{!preflight?.is_clickhouse_enabled && ( <Col span={columnSize}>
<Col span={columnSize}> <label className="ant-form-item-label">Last calculated at</label>
<label className="ant-form-item-label">Last calculated at</label>
<div>{cohort.last_calculation ? dayjs(cohort.last_calculation).fromNow() : 'in progress'}</div> <div>{cohort.last_calculation ? dayjs(cohort.last_calculation).fromNow() : 'in progress'}</div>
</Col> </Col>
)}
</Row> </Row>
) )
} }

View File

@ -8,8 +8,6 @@ import { ACTION_TYPE, ENTITY_MATCH_TYPE, EVENT_TYPE, PROPERTY_MATCH_TYPE } from
import { PropertyFilters } from 'lib/components/PropertyFilters/PropertyFilters' import { PropertyFilters } from 'lib/components/PropertyFilters/PropertyFilters'
import { DeleteOutlined } from '@ant-design/icons' import { DeleteOutlined } from '@ant-design/icons'
import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types'
import { useValues } from 'kea'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
const { Option } = Select const { Option } = Select
@ -155,9 +153,6 @@ function EntityCriteriaRow({
setOpen(false) setOpen(false)
} }
const { preflight } = useValues(preflightLogic)
const COUNT_ENABLED = preflight?.is_clickhouse_enabled
return ( return (
<div style={{ marginTop: 16, width: '100%' }}> <div style={{ marginTop: 16, width: '100%' }}>
<Row gutter={8}> <Row gutter={8}>
@ -177,24 +172,20 @@ function EntityCriteriaRow({
</Button> </Button>
<CohortEntityFilterBox open={open} onSelect={onEntityChange} /> <CohortEntityFilterBox open={open} onSelect={onEntityChange} />
</Col> </Col>
{COUNT_ENABLED && ( <Col span={4}>
<> <OperatorSelect value={count_operator} onChange={onOperatorChange} />
<Col span={4}> </Col>
<OperatorSelect value={count_operator} onChange={onOperatorChange} /> <Col span={3}>
</Col> <Input
<Col span={3}> required
<Input value={count}
required data-attr="entity-count"
value={count} onChange={(e) => onEntityCountChange(parseInt(e.target.value))}
data-attr="entity-count" placeholder="1"
onChange={(e) => onEntityCountChange(parseInt(e.target.value))} type="number"
placeholder="1" />
type="number" </Col>
/> <Col style={{ display: 'flex', alignItems: 'center' }}>times in the last</Col>
</Col>
</>
)}
<Col style={{ display: 'flex', alignItems: 'center' }}>{COUNT_ENABLED && 'times '}in the last</Col>
<Col span={4}> <Col span={4}>
<DateIntervalSelect value={days} onChange={onDateIntervalChange} /> <DateIntervalSelect value={days} onChange={onDateIntervalChange} />
</Col> </Col>

View File

@ -239,7 +239,6 @@
"can_create_org": false, "can_create_org": false,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -3234,7 +3233,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -3359,7 +3357,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -3630,7 +3627,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -3778,7 +3774,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -3907,7 +3902,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -4038,7 +4032,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -4163,7 +4156,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -4462,7 +4454,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -4895,7 +4886,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5041,7 +5031,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5170,7 +5159,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5297,7 +5285,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5422,7 +5409,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5549,7 +5535,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5676,7 +5661,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5803,7 +5787,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -5928,7 +5911,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -6054,7 +6036,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -6334,7 +6315,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -6576,7 +6556,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -6701,7 +6680,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -6989,7 +6967,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -7118,7 +7095,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -7243,7 +7219,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -7653,7 +7628,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -7778,7 +7752,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -8066,7 +8039,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -8192,7 +8164,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -8317,7 +8288,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -8651,7 +8621,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -8777,7 +8746,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -8902,7 +8870,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -9235,7 +9202,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -9360,7 +9326,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -9485,7 +9450,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -9612,7 +9576,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -9739,7 +9702,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -9891,7 +9853,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -10035,7 +9996,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -10160,7 +10120,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -10301,7 +10260,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -10426,7 +10384,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -10551,7 +10508,6 @@
"is_demo_project": true, "is_demo_project": true,
"posthog_version": "1.29.1", "posthog_version": "1.29.1",
"realm": "hosted-clickhouse", "realm": "hosted-clickhouse",
"is_clickhouse_enabled": true,
"ee_available": true, "ee_available": true,
"email_service_available": false, "email_service_available": false,
"$active_feature_flags": [ "$active_feature_flags": [
@ -18402,16 +18358,6 @@
"updated_by": null, "updated_by": null,
"query_usage_30_day": 0 "query_usage_30_day": 0
}, },
{
"id": "017989da-7571-0001-bc1f-c48306dd7a5e",
"name": "is_clickhouse_enabled",
"description": null,
"tags": null,
"is_numerical": false,
"updated_at": null,
"updated_by": null,
"query_usage_30_day": null
},
{ {
"id": "01791516-32bb-0000-4094-b9829f5f9651", "id": "01791516-32bb-0000-4094-b9829f5f9651",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -104,7 +104,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -854,7 +853,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -1057,7 +1055,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -1144,7 +1141,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -1233,7 +1229,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -1469,7 +1464,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -1684,7 +1678,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -1788,7 +1781,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -1885,7 +1877,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -1972,7 +1963,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -2059,7 +2049,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -2146,7 +2135,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -2235,7 +2223,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -2505,7 +2492,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -2607,7 +2593,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -2703,7 +2688,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -2790,7 +2774,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -2879,7 +2862,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -3168,7 +3150,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -3264,7 +3245,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -3351,7 +3331,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -3438,7 +3417,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -3527,7 +3505,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -3817,7 +3794,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -3920,7 +3896,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -4016,7 +3991,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -4103,7 +4077,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -4192,7 +4165,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -4494,7 +4466,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -4597,7 +4568,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -4693,7 +4663,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -4780,7 +4749,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -4867,7 +4835,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -4954,7 +4921,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -5043,7 +5009,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -5239,7 +5204,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -5539,7 +5503,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -5642,7 +5605,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": true, "is_first_component_load": true,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -5738,7 +5700,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -5825,7 +5786,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -5913,7 +5873,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6002,7 +5961,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6091,7 +6049,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": true, "$feature_flag_response": true,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6180,7 +6137,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6269,7 +6225,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6358,7 +6313,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6447,7 +6401,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6598,7 +6551,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -6695,7 +6647,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"phjs-xhr-response-200": 7, "phjs-xhr-response-200": 7,
"phjs-batch-requests-e/": 4, "phjs-batch-requests-e/": 4,
"email_service_available": false, "email_service_available": false,
@ -6787,7 +6738,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -6885,7 +6835,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -6981,7 +6930,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -7069,7 +7017,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -7157,7 +7104,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -7244,7 +7190,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -7333,7 +7278,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -7615,7 +7559,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -7713,7 +7656,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -7805,7 +7747,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -7892,7 +7833,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -7981,7 +7921,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -8282,7 +8221,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -8378,7 +8316,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -8475,7 +8412,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": true, "is_first_component_load": true,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -8567,7 +8503,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -8655,7 +8590,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -8744,7 +8678,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": true, "$feature_flag_response": true,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -8833,7 +8766,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -8922,7 +8854,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -9011,7 +8942,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -9100,7 +9030,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -9251,7 +9180,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -9348,7 +9276,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"phjs-xhr-response-200": 7, "phjs-xhr-response-200": 7,
"phjs-batch-requests-e/": 4, "phjs-batch-requests-e/": 4,
"email_service_available": false, "email_service_available": false,
@ -9440,7 +9367,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -9538,7 +9464,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -9640,7 +9565,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -9736,7 +9660,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -9823,7 +9746,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -9912,7 +9834,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -10216,7 +10137,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -10320,7 +10240,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": false, "is_first_component_load": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -10417,7 +10336,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -10504,7 +10422,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -10591,7 +10508,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -10678,7 +10594,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -10767,7 +10682,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -11063,7 +10977,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -11161,7 +11074,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"is_first_component_load": true, "is_first_component_load": true,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11253,7 +11165,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -11341,7 +11252,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11430,7 +11340,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11519,7 +11428,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": true, "$feature_flag_response": true,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11608,7 +11516,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11697,7 +11604,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11786,7 +11692,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11875,7 +11780,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -11963,7 +11867,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -12118,7 +12021,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -12206,7 +12108,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"$feature_flag_response": false, "$feature_flag_response": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
@ -12294,7 +12195,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -12383,7 +12283,6 @@
"$active_feature_flags": ["4050-query-ui-optB"], "$active_feature_flags": ["4050-query-ui-optB"],
"$geoip_continent_code": "OC", "$geoip_continent_code": "OC",
"$geoip_continent_name": "Oceania", "$geoip_continent_name": "Oceania",
"is_clickhouse_enabled": false,
"email_service_available": false, "email_service_available": false,
"$geoip_subdivision_1_code": "NSW", "$geoip_subdivision_1_code": "NSW",
"$geoip_subdivision_1_name": "New South Wales", "$geoip_subdivision_1_name": "New South Wales",
@ -14023,12 +13922,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "0179fcb6-f7fa-0000-c78a-c7b289c94008",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "0179fcb6-f7d6-0000-2314-06df9faddf58", "id": "0179fcb6-f7d6-0000-2314-06df9faddf58",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -85,9 +85,7 @@ function Bar({
const [labelPosition, setLabelPosition] = useState<LabelPosition>('inside') const [labelPosition, setLabelPosition] = useState<LabelPosition>('inside')
const [labelVisible, setLabelVisible] = useState(true) const [labelVisible, setLabelVisible] = useState(true)
const LABEL_POSITION_OFFSET = 8 // Defined here and in SCSS const LABEL_POSITION_OFFSET = 8 // Defined here and in SCSS
const { insightProps } = useValues(insightLogic) const cursorType = !disabled ? 'pointer' : ''
const { clickhouseFeaturesEnabled } = useValues(funnelLogic(insightProps))
const cursorType = clickhouseFeaturesEnabled && !disabled ? 'pointer' : ''
const hasBreakdownSum = isBreakdown && typeof breakdownSumPercentage === 'number' const hasBreakdownSum = isBreakdown && typeof breakdownSumPercentage === 'number'
const shouldShowLabel = !isBreakdown || (hasBreakdownSum && labelVisible) const shouldShowLabel = !isBreakdown || (hasBreakdownSum && labelVisible)
@ -146,7 +144,7 @@ function Bar({
backgroundColor: getSeriesColor(breakdownIndex), backgroundColor: getSeriesColor(breakdownIndex),
}} }}
onClick={() => { onClick={() => {
if (clickhouseFeaturesEnabled && !disabled && onBarClick) { if (!disabled && onBarClick) {
onBarClick() onBarClick()
} }
}} }}
@ -296,7 +294,6 @@ export function FunnelBarGraph({ color = 'white' }: { color?: string }): JSX.Ele
visibleStepsWithConversionMetrics: steps, visibleStepsWithConversionMetrics: steps,
stepReference, stepReference,
barGraphLayout: layout, barGraphLayout: layout,
clickhouseFeaturesEnabled,
aggregationTargetLabel, aggregationTargetLabel,
isModalActive, isModalActive,
} = useValues(logic) } = useValues(logic)
@ -361,8 +358,7 @@ export function FunnelBarGraph({ color = 'white' }: { color?: string }): JSX.Ele
<EntityFilterInfo filter={getActionFilterFromFunnelStep(step)} /> <EntityFilterInfo filter={getActionFilterFromFunnelStep(step)} />
)} )}
</div> </div>
{clickhouseFeaturesEnabled && {filters.funnel_order_type !== StepOrderValue.UNORDERED &&
filters.funnel_order_type !== StepOrderValue.UNORDERED &&
stepIndex > 0 && stepIndex > 0 &&
step.action_id === steps[stepIndex - 1].action_id && <DuplicateStepIndicator />} step.action_id === steps[stepIndex - 1].action_id && <DuplicateStepIndicator />}
<FunnelStepDropdown index={stepIndex} /> <FunnelStepDropdown index={stepIndex} />
@ -479,9 +475,7 @@ export function FunnelBarGraph({ color = 'white' }: { color?: string }): JSX.Ele
onClick={() => openPersonsModalForStep({ step, converted: false })} // dropoff value for steps is negative onClick={() => openPersonsModalForStep({ step, converted: false })} // dropoff value for steps is negative
style={{ style={{
flex: `${1 - breakdownSum / basisStep.count} 1 0`, flex: `${1 - breakdownSum / basisStep.count} 1 0`,
cursor: `${ cursor: `${!dashboardItemId ? 'pointer' : ''}`,
clickhouseFeaturesEnabled && !dashboardItemId ? 'pointer' : ''
}`,
}} }}
/> />
</> </>
@ -546,9 +540,7 @@ export function FunnelBarGraph({ color = 'white' }: { color?: string }): JSX.Ele
onClick={() => openPersonsModalForStep({ step, converted: false })} // dropoff value for steps is negative onClick={() => openPersonsModalForStep({ step, converted: false })} // dropoff value for steps is negative
style={{ style={{
flex: `${1 - step.conversionRates.fromBasisStep} 1 0`, flex: `${1 - step.conversionRates.fromBasisStep} 1 0`,
cursor: `${ cursor: `${!dashboardItemId ? 'pointer' : ''}`,
clickhouseFeaturesEnabled && !dashboardItemId ? 'pointer' : ''
}`,
}} }}
/> />
</> </>

View File

@ -15,9 +15,7 @@ import { FunnelStepsPicker } from 'scenes/insights/InsightTabs/FunnelTab/FunnelS
export function FunnelCanvasLabel(): JSX.Element | null { export function FunnelCanvasLabel(): JSX.Element | null {
const { insightProps, filters, activeView } = useValues(insightLogic) const { insightProps, filters, activeView } = useValues(insightLogic)
const { conversionMetrics, clickhouseFeaturesEnabled, aggregationTargetLabel } = useValues( const { conversionMetrics, aggregationTargetLabel } = useValues(funnelLogic(insightProps))
funnelLogic(insightProps)
)
const { setChartFilter } = useActions(chartFilterLogic(insightProps)) const { setChartFilter } = useActions(chartFilterLogic(insightProps))
if (activeView !== InsightType.FUNNELS) { if (activeView !== InsightType.FUNNELS) {
@ -57,9 +55,7 @@ export function FunnelCanvasLabel(): JSX.Element | null {
<Button <Button
type="link" type="link"
onClick={() => setChartFilter(FunnelVizType.TimeToConvert)} onClick={() => setChartFilter(FunnelVizType.TimeToConvert)}
disabled={ disabled={filters.funnel_viz_type === FunnelVizType.TimeToConvert}
!clickhouseFeaturesEnabled || filters.funnel_viz_type === FunnelVizType.TimeToConvert
}
> >
<span className="l4">{humanFriendlyDuration(conversionMetrics.averageTime)}</span> <span className="l4">{humanFriendlyDuration(conversionMetrics.averageTime)}</span>
</Button> </Button>

View File

@ -249,18 +249,6 @@ describe('funnelLogic', () => {
await expectLogic(preflightLogic).toDispatchActions(['loadPreflightSuccess']) await expectLogic(preflightLogic).toDispatchActions(['loadPreflightSuccess'])
}) })
it('has clickhouse enabled once preflight loads', async () => {
await expectLogic()
.toDispatchActions(preflightLogic, ['loadPreflight'])
.toMatchValues(logic, {
clickhouseFeaturesEnabled: false,
})
.toDispatchActions(preflightLogic, ['loadPreflightSuccess'])
.toMatchValues(logic, {
clickhouseFeaturesEnabled: true,
})
})
it('sets filters after load if valid', async () => { it('sets filters after load if valid', async () => {
await expectLogic(logic) await expectLogic(logic)
.toDispatchActions(['loadResults']) .toDispatchActions(['loadResults'])
@ -979,11 +967,6 @@ describe('funnelLogic', () => {
}) })
describe('is modal active', () => { describe('is modal active', () => {
it('modal is inactive when clickhouse is not enabled', async () => {
await expectLogic().toDispatchActions(preflightLogic, ['loadPreflight']).toMatchValues(logic, {
isModalActive: false,
})
})
it('modal is inactive when viewed on dashboard', async () => { it('modal is inactive when viewed on dashboard', async () => {
await expectLogic(preflightLogic).toDispatchActions(['loadPreflightSuccess']) await expectLogic(preflightLogic).toDispatchActions(['loadPreflightSuccess'])
await router.actions.push(urls.dashboard('1')) await router.actions.push(urls.dashboard('1'))

View File

@ -37,7 +37,7 @@ import {
TrendResult, TrendResult,
} from '~/types' } from '~/types'
import { BinCountAuto, FEATURE_FLAGS, FunnelLayout } from 'lib/constants' import { BinCountAuto, FEATURE_FLAGS, FunnelLayout } from 'lib/constants'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { import {
aggregateBreakdownResult, aggregateBreakdownResult,
formatDisplayPercentage, formatDisplayPercentage,
@ -485,11 +485,6 @@ export const funnelLogic = kea<funnelLogicType<openPersonsModelProps>>({
(filters, lastFilters): boolean => !equal(cleanFilters(filters), cleanFilters(lastFilters)), (filters, lastFilters): boolean => !equal(cleanFilters(filters), cleanFilters(lastFilters)),
], ],
barGraphLayout: [() => [selectors.filters], ({ layout }): FunnelLayout => layout || FunnelLayout.vertical], barGraphLayout: [() => [selectors.filters], ({ layout }): FunnelLayout => layout || FunnelLayout.vertical],
clickhouseFeaturesEnabled: [
() => [preflightLogic.selectors.preflight],
// Controls auto-calculation of results and ability to break down values
(preflight): boolean => !!preflight?.is_clickhouse_enabled,
],
histogramGraphData: [ histogramGraphData: [
() => [selectors.timeConversionResults], () => [selectors.timeConversionResults],
(timeConversionResults: FunnelsTimeConversionBins) => { (timeConversionResults: FunnelsTimeConversionBins) => {
@ -1043,9 +1038,8 @@ export const funnelLogic = kea<funnelLogicType<openPersonsModelProps>>({
}, },
], ],
correlationAnalysisAvailable: [ correlationAnalysisAvailable: [
(s) => [s.hasAvailableFeature, s.clickhouseFeaturesEnabled], (s) => [s.hasAvailableFeature],
(hasAvailableFeature, clickhouseFeaturesEnabled): boolean => (hasAvailableFeature): boolean => hasAvailableFeature(AvailableFeature.CORRELATION_ANALYSIS),
clickhouseFeaturesEnabled && hasAvailableFeature(AvailableFeature.CORRELATION_ANALYSIS),
], ],
allProperties: [ allProperties: [
(s) => [s.inversePropertyNames, s.excludedPropertyNames], (s) => [s.inversePropertyNames, s.excludedPropertyNames],
@ -1136,10 +1130,7 @@ export const funnelLogic = kea<funnelLogicType<openPersonsModelProps>>({
return count return count
}, },
], ],
isModalActive: [ isModalActive: [(s) => [s.isViewedOnDashboard], (isViewedOnDashboard) => !isViewedOnDashboard],
(s) => [s.clickhouseFeaturesEnabled, s.isViewedOnDashboard],
(clickhouseFeaturesEnabled, isViewedOnDashboard) => clickhouseFeaturesEnabled && !isViewedOnDashboard,
],
incompletenessOffsetFromEnd: [ incompletenessOffsetFromEnd: [
(s) => [s.steps, s.conversionWindow], (s) => [s.steps, s.conversionWindow],
(steps, conversionWindow) => { (steps, conversionWindow) => {
@ -1174,13 +1165,6 @@ export const funnelLogic = kea<funnelLogicType<openPersonsModelProps>>({
}) })
}) })
// load the old people table
if (!values.clickhouseFeaturesEnabled) {
if ((values.stepsWithCount[0]?.people?.length ?? 0) > 0) {
actions.loadPeople(values.stepsWithCount)
}
}
// load correlation table after funnel. Maybe parallel? // load correlation table after funnel. Maybe parallel?
if ( if (
values.correlationAnalysisAvailable && values.correlationAnalysisAvailable &&

View File

@ -95,7 +95,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,

View File

@ -23,7 +23,6 @@ import {
} from '@ant-design/icons' } from '@ant-design/icons'
import { SelectGradientOverflow } from 'lib/components/SelectGradientOverflow' import { SelectGradientOverflow } from 'lib/components/SelectGradientOverflow'
import { BareEntity, entityFilterLogic } from '../entityFilterLogic' import { BareEntity, entityFilterLogic } from '../entityFilterLogic'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { propertyDefinitionsModel } from '~/models/propertyDefinitionsModel' import { propertyDefinitionsModel } from '~/models/propertyDefinitionsModel'
import { getEventNamesForAction, pluralize } from 'lib/utils' import { getEventNamesForAction, pluralize } from 'lib/utils'
import { SeriesGlyph, SeriesLetter } from 'lib/components/SeriesGlyph' import { SeriesGlyph, SeriesLetter } from 'lib/components/SeriesGlyph'
@ -471,14 +470,9 @@ function MathSelector({
const numericalNotice = `This can only be used on properties that have at least one number type occurence in your events.${ const numericalNotice = `This can only be used on properties that have at least one number type occurence in your events.${
areEventPropertiesNumericalAvailable ? '' : ' None have been found yet!' areEventPropertiesNumericalAvailable ? '' : ' None have been found yet!'
}` }`
const { preflight } = useValues(preflightLogic)
const { eventMathEntries, propertyMathEntries } = useValues(mathsLogic) const { eventMathEntries, propertyMathEntries } = useValues(mathsLogic)
let math_entries = eventMathEntries const math_entries = eventMathEntries
if (!preflight?.is_clickhouse_enabled) {
math_entries = math_entries.filter((item) => item[0] !== 'weekly_active' && item[0] !== 'monthly_active')
}
return ( return (
<Select <Select

View File

@ -95,7 +95,7 @@ export function InsightTimeoutState({ isLoading }: { isLoading: boolean }): JSX.
<li>Reduce the date range of your query.</li> <li>Reduce the date range of your query.</li>
<li>Remove some filters.</li> <li>Remove some filters.</li>
{!preflight?.cloud && <li>Increase the size of your database server.</li>} {!preflight?.cloud && <li>Increase the size of your database server.</li>}
{!preflight?.cloud && !preflight?.is_clickhouse_enabled && ( {!preflight?.cloud && (
<li> <li>
<a <a
data-attr="insight-timeout-upgrade-to-clickhouse" data-attr="insight-timeout-upgrade-to-clickhouse"
@ -208,7 +208,7 @@ export function InsightErrorState({ excludeDetail, title }: InsightErrorStatePro
export function FunnelSingleStepState(): JSX.Element { export function FunnelSingleStepState(): JSX.Element {
const { insightProps } = useValues(insightLogic) const { insightProps } = useValues(insightLogic)
const { filters, clickhouseFeaturesEnabled } = useValues(funnelLogic(insightProps)) const { filters } = useValues(funnelLogic(insightProps))
const { setFilters } = useActions(funnelLogic(insightProps)) const { setFilters } = useActions(funnelLogic(insightProps))
const { addFilter } = useActions(entityFilterLogic({ setFilters, filters, typeKey: 'EditFunnel-action' })) const { addFilter } = useActions(entityFilterLogic({ setFilters, filters, typeKey: 'EditFunnel-action' }))
@ -221,9 +221,7 @@ export function FunnelSingleStepState(): JSX.Element {
<h2 className="funnels-empty-state__title">Add another step!</h2> <h2 className="funnels-empty-state__title">Add another step!</h2>
<p className="funnels-empty-state__description"> <p className="funnels-empty-state__description">
Youre almost there! Funnels require at least two steps before calculating. Youre almost there! Funnels require at least two steps before calculating.
{clickhouseFeaturesEnabled {' Once you have two steps defined, additional changes will recalculate automatically.'}
? ' Once you have two steps defined, additional changes will recalculate automatically.'
: ''}
</p> </p>
<div className="mt text-center"> <div className="mt text-center">
<Button <Button

View File

@ -208,7 +208,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"US/Pacific": -8, "US/Pacific": -8,

View File

@ -223,7 +223,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"US/Pacific": -8, "US/Pacific": -8,

View File

@ -226,7 +226,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"US/Pacific": -8, "US/Pacific": -8,

View File

@ -238,7 +238,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"US/Pacific": -8, "US/Pacific": -8,

View File

@ -203,7 +203,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"US/Pacific": -8, "US/Pacific": -8,

View File

@ -200,7 +200,6 @@
"can_create_org": true, "can_create_org": true,
"email_service_available": false, "email_service_available": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"US/Pacific": -8, "US/Pacific": -8,

View File

@ -24,7 +24,6 @@ import {
} from 'scenes/insights/EmptyStates' } from 'scenes/insights/EmptyStates'
import { Loading } from 'lib/utils' import { Loading } from 'lib/utils'
import { funnelLogic } from 'scenes/funnels/funnelLogic' import { funnelLogic } from 'scenes/funnels/funnelLogic'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import clsx from 'clsx' import clsx from 'clsx'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { PathCanvasLabel } from 'scenes/paths/PathsLabel' import { PathCanvasLabel } from 'scenes/paths/PathsLabel'
@ -46,7 +45,6 @@ export function InsightContainer(
disableTable: false, disableTable: false,
} }
): JSX.Element { ): JSX.Element {
const { preflight } = useValues(preflightLogic)
const { featureFlags } = useValues(featureFlagLogic) const { featureFlags } = useValues(featureFlagLogic)
const { const {
insightProps, insightProps,
@ -103,7 +101,6 @@ export function InsightContainer(
function renderTable(): JSX.Element | null { function renderTable(): JSX.Element | null {
if ( if (
!preflight?.is_clickhouse_enabled &&
!showErrorMessage && !showErrorMessage &&
!showTimeoutMessage && !showTimeoutMessage &&
areFiltersValid && areFiltersValid &&
@ -114,7 +111,6 @@ export function InsightContainer(
} }
if ( if (
preflight?.is_clickhouse_enabled &&
activeView === InsightType.FUNNELS && activeView === InsightType.FUNNELS &&
!showErrorMessage && !showErrorMessage &&
!showTimeoutMessage && !showTimeoutMessage &&

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react' import React from 'react'
import { useValues, useActions, useMountedLogic } from 'kea' import { useValues, useActions, useMountedLogic } from 'kea'
import clsx from 'clsx' import clsx from 'clsx'
import { funnelLogic } from 'scenes/funnels/funnelLogic' import { funnelLogic } from 'scenes/funnels/funnelLogic'
@ -30,15 +30,10 @@ import { FunnelStepReferencePicker } from './FunnelStepReferencePicker'
export function FunnelTab(): JSX.Element { export function FunnelTab(): JSX.Element {
const { insightProps, allEventNames } = useValues(insightLogic) const { insightProps, allEventNames } = useValues(insightLogic)
const { loadResults } = useActions(insightLogic) const { loadResults } = useActions(insightLogic)
const { const { isStepsEmpty, filters, aggregationTargetLabel, filterSteps, advancedOptionsUsedCount } = useValues(
isStepsEmpty, funnelLogic(insightProps)
filters, )
clickhouseFeaturesEnabled, const { setFilters, toggleAdvancedMode, setStepReference } = useActions(funnelLogic(insightProps))
aggregationTargetLabel,
filterSteps,
advancedOptionsUsedCount,
} = useValues(funnelLogic(insightProps))
const { clearFunnel, setFilters, toggleAdvancedMode, setStepReference } = useActions(funnelLogic(insightProps))
const { featureFlags } = useValues(featureFlagLogic) const { featureFlags } = useValues(featureFlagLogic)
const { groupsTaxonomicTypes, showGroupsOptions } = useValues(groupsModel) const { groupsTaxonomicTypes, showGroupsOptions } = useValues(groupsModel)
const screens = useBreakpoint() const screens = useBreakpoint()
@ -60,7 +55,7 @@ export function FunnelTab(): JSX.Element {
<h4 className="secondary" style={{ marginBottom: 0 }}> <h4 className="secondary" style={{ marginBottom: 0 }}>
Query steps Query steps
</h4> </h4>
{clickhouseFeaturesEnabled && ( {
<div className="flex-center"> <div className="flex-center">
<span <span
style={{ style={{
@ -74,7 +69,7 @@ export function FunnelTab(): JSX.Element {
</span> </span>
<ToggleButtonChartFilter simpleMode /> <ToggleButtonChartFilter simpleMode />
</div> </div>
)} }
</Row> </Row>
<Card className="action-filters-bordered" bodyStyle={{ padding: 0 }}> <Card className="action-filters-bordered" bodyStyle={{ padding: 0 }}>
<ActionFilter <ActionFilter
@ -100,23 +95,6 @@ export function FunnelTab(): JSX.Element {
rowClassName="action-filters-bordered" rowClassName="action-filters-bordered"
/> />
<div className="mb-05" /> <div className="mb-05" />
{!clickhouseFeaturesEnabled && (
<>
<hr style={{ margin: '0', marginBottom: '0.5rem' }} />
<Row style={{ justifyContent: 'flex-end', paddingBottom: 8, paddingRight: 8 }}>
{!isStepsEmpty && (
<Button
type="link"
onClick={(): void => clearFunnel()}
data-attr="save-funnel-clear-button"
>
Clear
</Button>
)}
<CalculateFunnelButton style={{ marginLeft: 4 }} />
</Row>
</>
)}
</Card> </Card>
</form> </form>
</div> </div>
@ -168,7 +146,7 @@ export function FunnelTab(): JSX.Element {
eventNames={allEventNames} eventNames={allEventNames}
/> />
{clickhouseFeaturesEnabled && filters.funnel_viz_type === FunnelVizType.Steps && ( {filters.funnel_viz_type === FunnelVizType.Steps && (
<> <>
<hr /> <hr />
<h4 className="secondary"> <h4 className="secondary">
@ -191,7 +169,7 @@ export function FunnelTab(): JSX.Element {
</> </>
)} )}
{clickhouseFeaturesEnabled && ( {
<> <>
<hr /> <hr />
<div className="flex-center cursor-pointer" onClick={toggleAdvancedMode}> <div className="flex-center cursor-pointer" onClick={toggleAdvancedMode}>
@ -281,50 +259,8 @@ export function FunnelTab(): JSX.Element {
</div> </div>
)} )}
</> </>
)} }
</Col> </Col>
</Row> </Row>
) )
} }
function CalculateFunnelButton({ style }: { style: React.CSSProperties }): JSX.Element {
const { insightProps } = useValues(insightLogic)
const { filters, areFiltersValid, filtersDirty, clickhouseFeaturesEnabled, isLoading } = useValues(
funnelLogic(insightProps)
)
const [tooltipOpen, setTooltipOpen] = useState(false)
const shouldRecalculate = filtersDirty && areFiltersValid && !isLoading && !clickhouseFeaturesEnabled
// Only show tooltip after 3s of inactivity
useEffect(() => {
if (shouldRecalculate) {
const rerenderInterval = setTimeout(() => {
setTooltipOpen(true)
}, 3000)
return () => {
clearTimeout(rerenderInterval)
setTooltipOpen(false)
}
} else {
setTooltipOpen(false)
}
}, [shouldRecalculate, filters])
return (
<Tooltip
visible={tooltipOpen}
title="Your query has changed. Calculate your changes to see updates in the visualization."
>
<Button
style={style}
type={shouldRecalculate ? 'primary' : 'default'}
htmlType="submit"
disabled={!areFiltersValid}
data-attr="save-funnel-button"
>
Calculate
</Button>
</Tooltip>
)
}

View File

@ -21,7 +21,7 @@ export function ToggleButtonChartFilter({
simpleMode, simpleMode,
}: ToggleButtonChartFilterProps): JSX.Element | null { }: ToggleButtonChartFilterProps): JSX.Element | null {
const { insightProps } = useValues(insightLogic) const { insightProps } = useValues(insightLogic)
const { clickhouseFeaturesEnabled, aggregationTargetLabel } = useValues(funnelLogic(insightProps)) const { aggregationTargetLabel } = useValues(funnelLogic(insightProps))
const { chartFilter } = useValues(chartFilterLogic(insightProps)) const { chartFilter } = useValues(chartFilterLogic(insightProps))
const { setChartFilter } = useActions(chartFilterLogic(insightProps)) const { setChartFilter } = useActions(chartFilterLogic(insightProps))
const defaultDisplay = FunnelVizType.Steps const defaultDisplay = FunnelVizType.Steps
@ -38,14 +38,14 @@ export function ToggleButtonChartFilter({
label: 'Time to convert', label: 'Time to convert',
description: `Track how long it takes for ${aggregationTargetLabel.plural} to convert`, description: `Track how long it takes for ${aggregationTargetLabel.plural} to convert`,
icon: <ClockCircleOutlined />, icon: <ClockCircleOutlined />,
hidden: !clickhouseFeaturesEnabled, hidden: false,
}, },
{ {
key: FunnelVizType.Trends, key: FunnelVizType.Trends,
label: 'Historical trends', label: 'Historical trends',
description: "Track how this funnel's conversion rate is trending over time", description: "Track how this funnel's conversion rate is trending over time",
icon: <LineChartOutlined />, icon: <LineChartOutlined />,
hidden: !clickhouseFeaturesEnabled, hidden: false,
}, },
] ]

View File

@ -22,7 +22,7 @@ import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
export function RetentionTab(): JSX.Element { export function RetentionTab(): JSX.Element {
const { featureFlags } = useValues(featureFlagLogic) const { featureFlags } = useValues(featureFlagLogic)
const { insightProps, clickhouseFeaturesEnabled, allEventNames } = useValues(insightLogic) const { insightProps, allEventNames } = useValues(insightLogic)
const { groupsTaxonomicTypes, showGroupsOptions } = useValues(groupsModel) const { groupsTaxonomicTypes, showGroupsOptions } = useValues(groupsModel)
const { filters, actionFilterTargetEntity, actionFilterReturningEntity } = useValues( const { filters, actionFilterTargetEntity, actionFilterReturningEntity } = useValues(
retentionTableLogic(insightProps) retentionTableLogic(insightProps)
@ -171,8 +171,7 @@ export function RetentionTab(): JSX.Element {
/> />
<TestAccountFilter filters={filters} onChange={setFilters} /> <TestAccountFilter filters={filters} onChange={setFilters} />
{clickhouseFeaturesEnabled && {featureFlags[FEATURE_FLAGS.RETENTION_BREAKDOWN] &&
featureFlags[FEATURE_FLAGS.RETENTION_BREAKDOWN] &&
filters.display !== ACTIONS_LINE_GRAPH_LINEAR ? ( filters.display !== ACTIONS_LINE_GRAPH_LINEAR ? (
<> <>
<hr /> <hr />

View File

@ -10,7 +10,6 @@ import { trendsLogic } from '../../../trends/trendsLogic'
import { FilterType, InsightType } from '~/types' import { FilterType, InsightType } from '~/types'
import { Formula } from './Formula' import { Formula } from './Formula'
import { TestAccountFilter } from 'scenes/insights/TestAccountFilter' import { TestAccountFilter } from 'scenes/insights/TestAccountFilter'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import './TrendTab.scss' import './TrendTab.scss'
import useBreakpoint from 'antd/lib/grid/hooks/useBreakpoint' import useBreakpoint from 'antd/lib/grid/hooks/useBreakpoint'
import { GlobalFiltersTitle } from 'scenes/insights/common' import { GlobalFiltersTitle } from 'scenes/insights/common'
@ -27,7 +26,6 @@ export function TrendTab({ view }: TrendTabProps): JSX.Element {
const { insightProps, allEventNames } = useValues(insightLogic) const { insightProps, allEventNames } = useValues(insightLogic)
const { filters } = useValues(trendsLogic(insightProps)) const { filters } = useValues(trendsLogic(insightProps))
const { setFilters, toggleLifecycle } = useActions(trendsLogic(insightProps)) const { setFilters, toggleLifecycle } = useActions(trendsLogic(insightProps))
const { preflight } = useValues(preflightLogic)
const { groupsTaxonomicTypes } = useValues(groupsModel) const { groupsTaxonomicTypes } = useValues(groupsModel)
const [isUsingFormulas, setIsUsingFormulas] = useState(filters.formula ? true : false) const [isUsingFormulas, setIsUsingFormulas] = useState(filters.formula ? true : false)
const lifecycles = [ const lifecycles = [
@ -43,7 +41,7 @@ export function TrendTab({ view }: TrendTabProps): JSX.Element {
const screens = useBreakpoint() const screens = useBreakpoint()
const isSmallScreen = screens.xs || (screens.sm && !screens.md) const isSmallScreen = screens.xs || (screens.sm && !screens.md)
const isTrends = !filters.insight || filters.insight === InsightType.TRENDS const isTrends = !filters.insight || filters.insight === InsightType.TRENDS
const formulaAvailable = isTrends && preflight?.is_clickhouse_enabled const formulaAvailable = isTrends
const formulaEnabled = (filters.events?.length || 0) + (filters.actions?.length || 0) > 0 const formulaEnabled = (filters.events?.length || 0) + (filters.actions?.length || 0) > 0
return ( return (

View File

@ -374,7 +374,6 @@ const sampleContextData = {
}, },
current_user: { organization: { available_features: ['correlation_analysis'] } }, current_user: { organization: { available_features: ['correlation_analysis'] } },
preflight: { preflight: {
is_clickhouse_enabled: true,
instance_preferences: { disable_paid_fs: false }, instance_preferences: { disable_paid_fs: false },
}, },
default_event_name: '$pageview', default_event_name: '$pageview',

View File

@ -138,7 +138,6 @@ const sampleContextData = {
}, },
}, },
preflight: { preflight: {
is_clickhouse_enabled: true,
instance_preferences: { disable_paid_fs: false }, instance_preferences: { disable_paid_fs: false },
}, },
default_event_name: '$pageview', default_event_name: '$pageview',

View File

@ -132,7 +132,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -2643,12 +2642,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "0179fcb6-f7fa-0000-c78a-c7b289c94008",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "0179fcb6-f7d6-0000-2314-06df9faddf58", "id": "0179fcb6-f7d6-0000-2314-06df9faddf58",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -120,7 +120,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -2843,12 +2842,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "0179fcb6-f7fa-0000-c78a-c7b289c94008",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "0179fcb6-f7d6-0000-2314-06df9faddf58", "id": "0179fcb6-f7d6-0000-2314-06df9faddf58",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -115,7 +115,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -2611,12 +2610,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "0179fcb6-f7fa-0000-c78a-c7b289c94008",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "0179fcb6-f7d6-0000-2314-06df9faddf58", "id": "0179fcb6-f7d6-0000-2314-06df9faddf58",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -140,7 +140,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -2974,12 +2973,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "0179fcb6-f7fa-0000-c78a-c7b289c94008",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "0179fcb6-f7d6-0000-2314-06df9faddf58", "id": "0179fcb6-f7d6-0000-2314-06df9faddf58",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -118,7 +118,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -2601,12 +2600,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "0179fcb6-f7fa-0000-c78a-c7b289c94008",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "0179fcb6-f7d6-0000-2314-06df9faddf58", "id": "0179fcb6-f7d6-0000-2314-06df9faddf58",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -129,7 +129,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -2974,12 +2973,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "0179fcb6-f7fa-0000-c78a-c7b289c94008",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "0179fcb6-f7d6-0000-2314-06df9faddf58", "id": "0179fcb6-f7d6-0000-2314-06df9faddf58",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -25,7 +25,6 @@ import { filterTrendsClientSideParams, keyForInsightLogicProps } from 'scenes/in
import { cleanFilters } from 'scenes/insights/utils/cleanFilters' import { cleanFilters } from 'scenes/insights/utils/cleanFilters'
import { dashboardsModel } from '~/models/dashboardsModel' import { dashboardsModel } from '~/models/dashboardsModel'
import { pollFunnel } from 'scenes/funnels/funnelUtils' import { pollFunnel } from 'scenes/funnels/funnelUtils'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { extractObjectDiffKeys, findInsightFromMountedLogic, getInsightId } from './utils' import { extractObjectDiffKeys, findInsightFromMountedLogic, getInsightId } from './utils'
import { teamLogic } from '../teamLogic' import { teamLogic } from '../teamLogic'
import { Scene } from 'scenes/sceneTypes' import { Scene } from 'scenes/sceneTypes'
@ -440,10 +439,6 @@ export const insightLogic = kea<insightLogicType>({
(s) => [s.insight, s.activeView], (s) => [s.insight, s.activeView],
({ filters }, activeView) => filters?.insight || activeView || InsightType.TRENDS, ({ filters }, activeView) => filters?.insight || activeView || InsightType.TRENDS,
], ],
clickhouseFeaturesEnabled: [
() => [preflightLogic.selectors.preflight],
(preflight) => !!preflight?.is_clickhouse_enabled,
],
filtersChanged: [ filtersChanged: [
(s) => [s.savedFilters, s.filters], (s) => [s.savedFilters, s.filters],
(savedFilters, filters) => (savedFilters, filters) =>

View File

@ -116,7 +116,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -9773,16 +9772,6 @@
"updated_by": null, "updated_by": null,
"query_usage_30_day": 0 "query_usage_30_day": 0
}, },
{
"id": "017989da-7571-0001-bc1f-c48306dd7a5e",
"name": "is_clickhouse_enabled",
"description": null,
"tags": null,
"is_numerical": false,
"updated_at": null,
"updated_by": null,
"query_usage_30_day": null
},
{ {
"id": "01791516-32bb-0000-4094-b9829f5f9651", "id": "01791516-32bb-0000-4094-b9829f5f9651",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -116,7 +116,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": true,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -6424,16 +6423,6 @@
"updated_by": null, "updated_by": null,
"query_usage_30_day": 0 "query_usage_30_day": 0
}, },
{
"id": "017989da-7571-0001-bc1f-c48306dd7a5e",
"name": "is_clickhouse_enabled",
"description": null,
"tags": null,
"is_numerical": false,
"updated_at": null,
"updated_by": null,
"query_usage_30_day": null
},
{ {
"id": "01791516-32bb-0000-4094-b9829f5f9651", "id": "01791516-32bb-0000-4094-b9829f5f9651",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -15,7 +15,6 @@ import { DateFilter } from 'lib/components/DateFilter/DateFilter'
import { Tooltip } from 'lib/components/Tooltip' import { Tooltip } from 'lib/components/Tooltip'
import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types'
import { PropertyFilters } from 'lib/components/PropertyFilters/PropertyFilters' import { PropertyFilters } from 'lib/components/PropertyFilters/PropertyFilters'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import './SessionRecordingTable.scss' import './SessionRecordingTable.scss'
import { LemonTable, LemonTableColumns } from 'lib/components/LemonTable' import { LemonTable, LemonTableColumns } from 'lib/components/LemonTable'
import { TZLabel } from 'lib/components/TimezoneAware' import { TZLabel } from 'lib/components/TimezoneAware'
@ -74,7 +73,6 @@ export function SessionRecordingsTable({ personUUID, isPersonPage = false }: Ses
setDurationFilter, setDurationFilter,
enableFilter, enableFilter,
} = useActions(sessionRecordingsTableLogicInstance) } = useActions(sessionRecordingsTableLogicInstance)
const { preflight } = useValues(preflightLogic)
const columns: LemonTableColumns<SessionRecordingType> = [ const columns: LemonTableColumns<SessionRecordingType> = [
{ {
@ -151,7 +149,7 @@ export function SessionRecordingsTable({ personUUID, isPersonPage = false }: Ses
]} ]}
/> />
</div> </div>
{!isPersonPage && preflight?.is_clickhouse_enabled && ( {!isPersonPage && (
<div className="mt-2"> <div className="mt-2">
<Typography.Text strong> <Typography.Text strong>
{`Filter by persons and cohorts `} {`Filter by persons and cohorts `}

View File

@ -203,7 +203,6 @@
}, },
"can_create_org": false, "can_create_org": false,
"ee_available": true, "ee_available": true,
"is_clickhouse_enabled": false,
"db_backend": "postgres", "db_backend": "postgres",
"available_timezones": { "available_timezones": {
"Africa/Abidjan": 0, "Africa/Abidjan": 0,
@ -1618,12 +1617,6 @@
"is_numerical": false, "is_numerical": false,
"query_usage_30_day": null "query_usage_30_day": null
}, },
{
"id": "017c49bd-c5b5-0000-2339-428a6a70e29a",
"name": "is_clickhouse_enabled",
"is_numerical": false,
"query_usage_30_day": null
},
{ {
"id": "017c49bd-c542-0000-ab97-5484f63a8fc3", "id": "017c49bd-c542-0000-ab97-5484f63a8fc3",
"name": "is_demo_project", "name": "is_demo_project",

View File

@ -10,7 +10,6 @@ import './PersonsModal.scss'
import { PropertyKeyInfo } from 'lib/components/PropertyKeyInfo' import { PropertyKeyInfo } from 'lib/components/PropertyKeyInfo'
import { PropertiesTable } from 'lib/components/PropertiesTable' import { PropertiesTable } from 'lib/components/PropertiesTable'
import { DateDisplay } from 'lib/components/DateDisplay' import { DateDisplay } from 'lib/components/DateDisplay'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { PersonHeader } from '../persons/PersonHeader' import { PersonHeader } from '../persons/PersonHeader'
import api from '../../lib/api' import api from '../../lib/api'
import { LemonTable, LemonTableColumns } from 'lib/components/LemonTable' import { LemonTable, LemonTableColumns } from 'lib/components/LemonTable'
@ -45,7 +44,6 @@ export function PersonsModal({
firstLoadedPeople, firstLoadedPeople,
searchTerm, searchTerm,
isInitialLoad, isInitialLoad,
clickhouseFeaturesEnabled,
peopleParams, peopleParams,
actorLabel, actorLabel,
sessionRecordingId, sessionRecordingId,
@ -60,7 +58,6 @@ export function PersonsModal({
openRecordingModal, openRecordingModal,
closeRecordingModal, closeRecordingModal,
} = useActions(personsModalLogic) } = useActions(personsModalLogic)
const { preflight } = useValues(preflightLogic)
const { featureFlags } = useValues(featureFlagLogic) const { featureFlags } = useValues(featureFlagLogic)
const title = useMemo( const title = useMemo(
@ -96,7 +93,6 @@ export function PersonsModal({
const flaggedInsights = featureFlags[FEATURE_FLAGS.NEW_INSIGHT_COHORTS] const flaggedInsights = featureFlags[FEATURE_FLAGS.NEW_INSIGHT_COHORTS]
const isDownloadCsvAvailable: boolean = view === InsightType.TRENDS && showModalActions && !!people?.action const isDownloadCsvAvailable: boolean = view === InsightType.TRENDS && showModalActions && !!people?.action
const isSaveAsCohortAvailable = const isSaveAsCohortAvailable =
clickhouseFeaturesEnabled &&
(view === InsightType.TRENDS || (view === InsightType.TRENDS ||
view === InsightType.STICKINESS || view === InsightType.STICKINESS ||
(!!flaggedInsights && (view === InsightType.FUNNELS || view === InsightType.PATHS))) && // make sure flaggedInsights isn't evaluated as undefined (!!flaggedInsights && (view === InsightType.FUNNELS || view === InsightType.PATHS))) && // make sure flaggedInsights isn't evaluated as undefined
@ -158,25 +154,23 @@ export function PersonsModal({
) : ( ) : (
people && ( people && (
<> <>
{!preflight?.is_clickhouse_enabled && ( <Input.Search
<Input.Search allowClear
allowClear enterButton
enterButton placeholder="Search for persons by email, name, or ID"
placeholder="Search for persons by email, name, or ID" onChange={(e) => {
onChange={(e) => { setSearchTerm(e.target.value)
setSearchTerm(e.target.value) if (!e.target.value) {
if (!e.target.value) { setFirstLoadedActors(firstLoadedPeople)
setFirstLoadedActors(firstLoadedPeople)
}
}}
value={searchTerm}
onSearch={(term) =>
term
? setPersonsModalFilters(term, people, filters)
: setFirstLoadedActors(firstLoadedPeople)
} }
/> }}
)} value={searchTerm}
onSearch={(term) =>
term
? setPersonsModalFilters(term, people, filters)
: setFirstLoadedActors(firstLoadedPeople)
}
/>
{featureFlags[FEATURE_FLAGS.MULTI_POINT_PERSON_MODAL] && {featureFlags[FEATURE_FLAGS.MULTI_POINT_PERSON_MODAL] &&
!!people.crossDataset?.length && !!people.crossDataset?.length &&
people.seriesId !== undefined && ( people.seriesId !== undefined && (

View File

@ -15,7 +15,6 @@ import {
GraphDataset, GraphDataset,
} from '~/types' } from '~/types'
import { personsModalLogicType } from './personsModalLogicType' import { personsModalLogicType } from './personsModalLogicType'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic' import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { TrendActors } from 'scenes/trends/types' import { TrendActors } from 'scenes/trends/types'
@ -242,10 +241,6 @@ export const personsModalLogic = kea<personsModalLogicType<LoadPeopleFromUrlProp
(s) => [s.peopleLoading, s.loadingMorePeople], (s) => [s.peopleLoading, s.loadingMorePeople],
(peopleLoading, loadingMorePeople) => peopleLoading && !loadingMorePeople, (peopleLoading, loadingMorePeople) => peopleLoading && !loadingMorePeople,
], ],
clickhouseFeaturesEnabled: [
() => [preflightLogic.selectors.preflight],
(preflight) => !!preflight?.is_clickhouse_enabled,
],
isGroupType: [(s) => [s.people], (people) => people?.people?.[0] && isGroupType(people.people[0])], isGroupType: [(s) => [s.people], (people) => people?.people?.[0] && isGroupType(people.people[0])],
actorLabel: [ actorLabel: [
(s) => [s.people, s.isGroupType, s.groupTypes, s.aggregationLabel], (s) => [s.people, s.isGroupType, s.groupTypes, s.aggregationLabel],

View File

@ -1240,10 +1240,6 @@ export interface PreflightStatus {
/** Whether this is a managed demo environment. */ /** Whether this is a managed demo environment. */
demo: boolean demo: boolean
celery: boolean celery: boolean
/** Whether EE code is available (but not necessarily a license). */
ee_available?: boolean
/** Is ClickHouse used as the analytics database instead of Postgres. */
is_clickhouse_enabled?: boolean
realm: Realm realm: Realm
db_backend?: 'postgres' | 'clickhouse' db_backend?: 'postgres' | 'clickhouse'
available_social_auth_providers: AuthBackends available_social_auth_providers: AuthBackends

View File

@ -29,8 +29,8 @@
"start-docker": "yarn start-docker:esbuild", "start-docker": "yarn start-docker:esbuild",
"start-docker:esbuild": "yarn start-http:esbuild --host 0.0.0.0", "start-docker:esbuild": "yarn start-http:esbuild --host 0.0.0.0",
"start-docker:webpack": "yarn start-http:webpack --host 0.0.0.0", "start-docker:webpack": "yarn start-http:webpack --host 0.0.0.0",
"start-ch-dev": "concurrently -n DOCKER,ESBUILD,TYPEGEN -c red,blue,green \"docker-compose -f ee/docker-compose.ch.yml pull && CH_WEB_SCRIPT=./ee/bin/docker-ch-dev-backend docker-compose -f ee/docker-compose.ch.yml up\" \"yarn run start-http --host 0.0.0.0\" \"yarn run typegen:watch\"", "start-ch-dev": "concurrently -n DOCKER,ESBUILD,TYPEGEN -c red,blue,green \"docker-compose -f docker-compose.dev.yml pull && CH_WEB_SCRIPT=./ee/bin/docker-ch-dev-backend docker-compose -f docker-compose.dev.yml up\" \"yarn run start-http --host 0.0.0.0\" \"yarn run typegen:watch\"",
"clear-ch-dev": "docker compose -f ee/docker-compose.ch.yml stop && docker compose -f ee/docker-compose.ch.yml rm -v && docker compose -f ee/docker-compose.ch.yml down", "clear-ch-dev": "docker compose -f docker-compose.dev.yml stop && docker compose -f docker-compose.dev.yml rm -v && docker compose -f docker-compose.dev.yml down",
"clean": "rm -rf frontend/dist && mkdir frontend/dist", "clean": "rm -rf frontend/dist && mkdir frontend/dist",
"build": "yarn copy-scripts && yarn build:esbuild", "build": "yarn copy-scripts && yarn build:esbuild",
"build:webpack": "echo \"Building Webpack\" && NODE_ENV=production webpack --config webpack.config.js && cp -a frontend/public/* frontend/dist/", "build:webpack": "echo \"Building Webpack\" && NODE_ENV=production webpack --config webpack.config.js && cp -a frontend/public/* frontend/dist/",
@ -50,12 +50,12 @@
"storybook": "start-storybook -s .storybook/public -p 6006", "storybook": "start-storybook -s .storybook/public -p 6006",
"build-storybook": "build-storybook -s .storybook/public", "build-storybook": "build-storybook -s .storybook/public",
"arm64:build:clickhouse": "./docker/clickhouse-builder/build.sh", "arm64:build:clickhouse": "./docker/clickhouse-builder/build.sh",
"arm64:ch-dev:start": "concurrently -n DOCKER,ESBUILD,TYPEGEN -c red,blue,green \"docker-compose -f ee/docker-compose.ch.arm64.yml pull && CH_WEB_SCRIPT=./ee/bin/docker-ch-dev-backend docker-compose -f ee/docker-compose.ch.arm64.yml up\" \"yarn run start-http --host 0.0.0.0\" \"yarn run typegen:watch\"", "arm64:ch-dev:start": "concurrently -n DOCKER,ESBUILD,TYPEGEN -c red,blue,green \"docker-compose -f docker-compose.arm64.yml pull && CH_WEB_SCRIPT=./ee/bin/docker-ch-dev-backend docker-compose -f docker-compose.arm64.yml up\" \"yarn run start-http --host 0.0.0.0\" \"yarn run typegen:watch\"",
"arm64:ch-dev:clear": "docker compose -f ee/docker-compose.ch.arm64.yml stop && docker compose -f ee/docker-compose.ch.arm64.yml rm -v && docker compose -f ee/docker-compose.ch.arm64.yml down", "arm64:ch-dev:clear": "docker compose -f docker-compose.arm64.yml stop && docker compose -f docker-compose.arm64.yml rm -v && docker compose -f docker-compose.arm64.yml down",
"arm64:services": "yarn arm64:services:stop && yarn arm64:services:clean && yarn arm64:services:start", "arm64:services": "yarn arm64:services:stop && yarn arm64:services:clean && yarn arm64:services:start",
"arm64:services:start": "docker-compose -f ee/docker-compose.ch.arm64.yml up zookeeper kafka clickhouse", "arm64:services:start": "docker-compose -f docker-compose.arm64.yml up zookeeper kafka clickhouse",
"arm64:services:stop": "docker-compose -f ee/docker-compose.ch.arm64.yml down", "arm64:services:stop": "docker-compose -f docker-compose.arm64.yml down",
"arm64:services:clean": "docker-compose -f ee/docker-compose.ch.arm64.yml rm -v zookeeper kafka clickhouse", "arm64:services:clean": "docker-compose -f docker-compose.arm64.yml rm -v zookeeper kafka clickhouse",
"dev:migrate:postgres": "export DEBUG=1 PRIMARY_DB=clickhouse && source env/bin/activate && python manage.py migrate", "dev:migrate:postgres": "export DEBUG=1 PRIMARY_DB=clickhouse && source env/bin/activate && python manage.py migrate",
"dev:migrate:clickhouse": "export DEBUG=1 PRIMARY_DB=clickhouse && source env/bin/activate && python manage.py migrate_clickhouse" "dev:migrate:clickhouse": "export DEBUG=1 PRIMARY_DB=clickhouse && source env/bin/activate && python manage.py migrate_clickhouse"
}, },

View File

@ -35,9 +35,9 @@
"setup:test:ee": "yarn setup:test:postgres && yarn setup:test:clickhouse", "setup:test:ee": "yarn setup:test:postgres && yarn setup:test:clickhouse",
"setup:test:postgres": "cd .. && python manage.py setup_test_environment", "setup:test:postgres": "cd .. && python manage.py setup_test_environment",
"setup:test:clickhouse": "cd .. && unset KAFKA_URL && export TEST=1 PRIMARY_DB=clickhouse CLICKHOUSE_DATABASE=posthog_test && python manage.py migrate_clickhouse", "setup:test:clickhouse": "cd .. && unset KAFKA_URL && export TEST=1 PRIMARY_DB=clickhouse CLICKHOUSE_DATABASE=posthog_test && python manage.py migrate_clickhouse",
"services:start": "cd .. && docker-compose -f ee/docker-compose.ch.yml up zookeeper kafka clickhouse", "services:start": "cd .. && docker-compose -f docker-compose.dev.yml up zookeeper kafka clickhouse",
"services:stop": "cd .. && docker-compose -f ee/docker-compose.ch.yml down", "services:stop": "cd .. && docker-compose -f docker-compose.dev.yml down",
"services:clean": "cd .. && docker-compose -f ee/docker-compose.ch.yml rm -v zookeeper kafka clickhouse", "services:clean": "cd .. && docker-compose -f docker-compose.dev.yml rm -v zookeeper kafka clickhouse",
"services": "yarn services:stop && yarn services:clean && yarn services:start" "services": "yarn services:stop && yarn services:clean && yarn services:start"
}, },
"bin": { "bin": {

View File

@ -1,7 +1,6 @@
from rest_framework import decorators, exceptions from rest_framework import decorators, exceptions
from posthog.api.routing import DefaultRouterPlusPlus from posthog.api.routing import DefaultRouterPlusPlus
from posthog.utils import is_clickhouse_enabled
from . import ( from . import (
action, action,
@ -100,57 +99,36 @@ router.register(r"async_migrations", async_migration.AsyncMigrationsViewset, "as
router.register(r"instance_settings", instance_settings.InstanceSettingsViewset, "instance_settings") router.register(r"instance_settings", instance_settings.InstanceSettingsViewset, "instance_settings")
if is_clickhouse_enabled(): from ee.clickhouse.views.actions import ClickhouseActionsViewSet, LegacyClickhouseActionsViewSet
from ee.clickhouse.views.actions import ClickhouseActionsViewSet, LegacyClickhouseActionsViewSet from ee.clickhouse.views.cohort import ClickhouseCohortViewSet, LegacyClickhouseCohortViewSet
from ee.clickhouse.views.cohort import ClickhouseCohortViewSet, LegacyClickhouseCohortViewSet from ee.clickhouse.views.element import ClickhouseElementViewSet, LegacyClickhouseElementViewSet
from ee.clickhouse.views.element import ClickhouseElementViewSet, LegacyClickhouseElementViewSet from ee.clickhouse.views.events import ClickhouseEventsViewSet, LegacyClickhouseEventsViewSet
from ee.clickhouse.views.events import ClickhouseEventsViewSet, LegacyClickhouseEventsViewSet from ee.clickhouse.views.experiments import ClickhouseExperimentsViewSet
from ee.clickhouse.views.experiments import ClickhouseExperimentsViewSet from ee.clickhouse.views.groups import ClickhouseGroupsTypesView, ClickhouseGroupsView
from ee.clickhouse.views.groups import ClickhouseGroupsTypesView, ClickhouseGroupsView from ee.clickhouse.views.insights import ClickhouseInsightsViewSet, LegacyClickhouseInsightsViewSet
from ee.clickhouse.views.insights import ClickhouseInsightsViewSet, LegacyClickhouseInsightsViewSet from ee.clickhouse.views.paths import ClickhousePathsViewSet, LegacyClickhousePathsViewSet
from ee.clickhouse.views.paths import ClickhousePathsViewSet, LegacyClickhousePathsViewSet from ee.clickhouse.views.person import ClickhousePersonViewSet, LegacyClickhousePersonViewSet
from ee.clickhouse.views.person import ClickhousePersonViewSet, LegacyClickhousePersonViewSet from ee.clickhouse.views.session_recordings import ClickhouseSessionRecordingViewSet
from ee.clickhouse.views.session_recordings import ClickhouseSessionRecordingViewSet
# Legacy endpoints CH (to be removed eventually) # Legacy endpoints CH (to be removed eventually)
router.register(r"action", LegacyClickhouseActionsViewSet, basename="action") # Should be completely unused now router.register(r"action", LegacyClickhouseActionsViewSet, basename="action") # Should be completely unused now
router.register(r"event", LegacyClickhouseEventsViewSet, basename="event") # Should be completely unused now router.register(r"event", LegacyClickhouseEventsViewSet, basename="event") # Should be completely unused now
router.register(r"insight", LegacyClickhouseInsightsViewSet, basename="insight") # Should be completely unused now router.register(r"insight", LegacyClickhouseInsightsViewSet, basename="insight") # Should be completely unused now
router.register(r"person", LegacyClickhousePersonViewSet, basename="person") router.register(r"person", LegacyClickhousePersonViewSet, basename="person")
router.register(r"paths", LegacyClickhousePathsViewSet, basename="paths") router.register(r"paths", LegacyClickhousePathsViewSet, basename="paths")
router.register(r"element", LegacyClickhouseElementViewSet, basename="element") router.register(r"element", LegacyClickhouseElementViewSet, basename="element")
router.register(r"cohort", LegacyClickhouseCohortViewSet, basename="cohort") router.register(r"cohort", LegacyClickhouseCohortViewSet, basename="cohort")
# Nested endpoints CH # Nested endpoints CH
projects_router.register(r"actions", ClickhouseActionsViewSet, "project_actions", ["team_id"]) projects_router.register(r"actions", ClickhouseActionsViewSet, "project_actions", ["team_id"])
projects_router.register(r"events", ClickhouseEventsViewSet, "project_events", ["team_id"]) projects_router.register(r"events", ClickhouseEventsViewSet, "project_events", ["team_id"])
projects_router.register(r"groups", ClickhouseGroupsView, "project_groups", ["team_id"]) projects_router.register(r"groups", ClickhouseGroupsView, "project_groups", ["team_id"])
projects_router.register(r"groups_types", ClickhouseGroupsTypesView, "project_groups_types", ["team_id"]) projects_router.register(r"groups_types", ClickhouseGroupsTypesView, "project_groups_types", ["team_id"])
projects_router.register(r"insights", ClickhouseInsightsViewSet, "project_insights", ["team_id"]) projects_router.register(r"insights", ClickhouseInsightsViewSet, "project_insights", ["team_id"])
projects_router.register(r"persons", ClickhousePersonViewSet, "project_persons", ["team_id"]) projects_router.register(r"persons", ClickhousePersonViewSet, "project_persons", ["team_id"])
projects_router.register(r"paths", ClickhousePathsViewSet, "project_paths", ["team_id"]) projects_router.register(r"paths", ClickhousePathsViewSet, "project_paths", ["team_id"])
projects_router.register(r"elements", ClickhouseElementViewSet, "project_elements", ["team_id"]) projects_router.register(r"elements", ClickhouseElementViewSet, "project_elements", ["team_id"])
projects_router.register(r"cohorts", ClickhouseCohortViewSet, "project_cohorts", ["team_id"]) projects_router.register(r"cohorts", ClickhouseCohortViewSet, "project_cohorts", ["team_id"])
projects_router.register(r"experiments", ClickhouseExperimentsViewSet, "project_experiments", ["team_id"]) projects_router.register(r"experiments", ClickhouseExperimentsViewSet, "project_experiments", ["team_id"])
projects_router.register( projects_router.register(
r"session_recordings", ClickhouseSessionRecordingViewSet, "project_session_recordings", ["team_id"], r"session_recordings", ClickhouseSessionRecordingViewSet, "project_session_recordings", ["team_id"],
) )
else:
# Legacy endpoints PG (to be removed eventually)
router.register(r"insight", insight.LegacyInsightViewSet) # Should be completely unused now
router.register(r"action", action.LegacyActionViewSet) # Should be completely unused now
router.register(r"person", person.LegacyPersonViewSet)
router.register(r"event", event.LegacyEventViewSet) # Should be completely unused now
router.register(r"paths", paths.LegacyPathsViewSet, basename="paths")
router.register(r"element", element.LegacyElementViewSet)
router.register(r"cohort", cohort.LegacyCohortViewSet)
# Nested endpoints PG
projects_router.register(r"insights", insight.LegacyInsightViewSet, "project_insights", ["team_id"])
projects_router.register(r"actions", action.ActionViewSet, "project_actions", ["team_id"])
projects_router.register(r"persons", person.LegacyPersonViewSet, "project_persons", ["team_id"])
projects_router.register(r"events", event.LegacyEventViewSet, "project_events", ["team_id"])
projects_router.register(r"paths", paths.LegacyPathsViewSet, "project_paths", ["team_id"])
projects_router.register(r"elements", element.LegacyElementViewSet, "project_elements", ["team_id"])
projects_router.register(r"cohorts", cohort.LegacyCohortViewSet, "project_cohorts", ["team_id"])
projects_router.register(
r"session_recordings", session_recording.SessionRecordingViewSet, "project_session_recordings", ["team_id"],
)

View File

@ -39,7 +39,6 @@ from posthog.models.filters.stickiness_filter import StickinessFilter
from posthog.models.team import Team from posthog.models.team import Team
from posthog.permissions import ProjectMembershipNecessaryPermissions, TeamMemberAccessPermission from posthog.permissions import ProjectMembershipNecessaryPermissions, TeamMemberAccessPermission
from posthog.queries import base, retention, stickiness, trends from posthog.queries import base, retention, stickiness, trends
from posthog.tasks.calculate_action import calculate_action
from posthog.utils import generate_cache_key, get_safe_cache, should_refresh from posthog.utils import generate_cache_key, get_safe_cache, should_refresh
from .person import PersonSerializer, paginated_result from .person import PersonSerializer, paginated_result
@ -125,7 +124,6 @@ class ActionSerializer(serializers.HyperlinkedModelSerializer):
action=instance, **{key: value for key, value in step.items() if key not in ("isNew", "selection")}, action=instance, **{key: value for key, value in step.items() if key not in ("isNew", "selection")},
) )
calculate_action.delay(action_id=instance.pk)
report_user_action(validated_data["created_by"], "action created", instance.get_analytics_metadata()) report_user_action(validated_data["created_by"], "action created", instance.get_analytics_metadata())
return instance return instance
@ -152,7 +150,6 @@ class ActionSerializer(serializers.HyperlinkedModelSerializer):
) )
instance = super().update(instance, validated_data) instance = super().update(instance, validated_data)
calculate_action.delay(action_id=instance.pk)
instance.refresh_from_db() instance.refresh_from_db()
report_user_action( report_user_action(
self.context["request"].user, self.context["request"].user,

View File

@ -9,88 +9,88 @@ from django.http import JsonResponse
from django.utils import timezone from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from rest_framework import status from rest_framework import status
from sentry_sdk import capture_exception, configure_scope, push_scope from sentry_sdk import capture_exception, configure_scope
from sentry_sdk.api import capture_exception from sentry_sdk.api import capture_exception
from statshog.defaults.django import statsd from statshog.defaults.django import statsd
from ee.kafka_client.client import KafkaProducer
from ee.kafka_client.topics import KAFKA_DEAD_LETTER_QUEUE
from ee.settings import KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC
from posthog.api.utils import get_data, get_team, get_token from posthog.api.utils import get_data, get_team, get_token
from posthog.celery import app as celery_app
from posthog.exceptions import generate_exception_response from posthog.exceptions import generate_exception_response
from posthog.helpers.session_recording import preprocess_session_recording_events from posthog.helpers.session_recording import preprocess_session_recording_events
from posthog.models import Team from posthog.models import Team
from posthog.models.feature_flag import get_overridden_feature_flags from posthog.models.feature_flag import get_overridden_feature_flags
from posthog.models.utils import UUIDT from posthog.models.utils import UUIDT
from posthog.utils import cors_response, get_ip_address, is_clickhouse_enabled from posthog.utils import cors_response, get_ip_address
if is_clickhouse_enabled():
from ee.kafka_client.client import KafkaProducer
from ee.kafka_client.topics import KAFKA_DEAD_LETTER_QUEUE
from ee.settings import KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC
def parse_kafka_event_data( def parse_kafka_event_data(
distinct_id: str, distinct_id: str,
ip: Optional[str], ip: Optional[str],
site_url: str, site_url: str,
data: Dict, data: Dict,
team_id: Optional[int], team_id: Optional[int],
now: datetime, now: datetime,
sent_at: Optional[datetime], sent_at: Optional[datetime],
event_uuid: UUIDT, event_uuid: UUIDT,
) -> Dict: ) -> Dict:
return { return {
"uuid": str(event_uuid), "uuid": str(event_uuid),
"distinct_id": distinct_id, "distinct_id": distinct_id,
"ip": ip, "ip": ip,
"site_url": site_url, "site_url": site_url,
"data": json.dumps(data), "data": json.dumps(data),
"team_id": team_id, "team_id": team_id,
"now": now.isoformat(), "now": now.isoformat(),
"sent_at": sent_at.isoformat() if sent_at else "", "sent_at": sent_at.isoformat() if sent_at else "",
} }
def log_event(data: Dict, event_name: str) -> None:
if settings.DEBUG:
print(f"Logging event {event_name} to Kafka topic {KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC}")
# TODO: Handle Kafka being unavailable with exponential backoff retries
try:
KafkaProducer().produce(topic=KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC, data=data)
except Exception as e:
statsd.incr("capture_endpoint_log_event_error")
print(f"Failed to produce event to Kafka topic {KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC} with error:", e)
raise e
def log_event_to_dead_letter_queue(
raw_payload: Dict,
event_name: str,
event: Dict,
error_message: str,
error_location: str,
topic: str = KAFKA_DEAD_LETTER_QUEUE,
):
data = event.copy()
data["failure_timestamp"] = datetime.now().isoformat()
data["error_location"] = error_location
data["error"] = error_message
data["elements_chain"] = ""
data["id"] = str(UUIDT())
data["event"] = event_name
data["raw_payload"] = json.dumps(raw_payload)
data["now"] = datetime.fromisoformat(data["now"]).replace(tzinfo=None).isoformat() if data["now"] else None
data["event_uuid"] = event["uuid"]
del data["uuid"]
try:
KafkaProducer().produce(topic=topic, data=data)
statsd.incr(settings.EVENTS_DEAD_LETTER_QUEUE_STATSD_METRIC)
except Exception as e:
capture_exception(e)
statsd.incr("events_dead_letter_queue_produce_error")
def log_event(data: Dict, event_name: str) -> None:
if settings.DEBUG: if settings.DEBUG:
print(f"Logging event {event_name} to Kafka topic {KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC}") print("Failed to produce to events dead letter queue with error:", e)
# TODO: Handle Kafka being unavailable with exponential backoff retries
try:
KafkaProducer().produce(topic=KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC, data=data)
except Exception as e:
statsd.incr("capture_endpoint_log_event_error")
print(f"Failed to produce event to Kafka topic {KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC} with error:", e)
raise e
def log_event_to_dead_letter_queue(
raw_payload: Dict,
event_name: str,
event: Dict,
error_message: str,
error_location: str,
topic: str = KAFKA_DEAD_LETTER_QUEUE,
):
data = event.copy()
data["failure_timestamp"] = datetime.now().isoformat()
data["error_location"] = error_location
data["error"] = error_message
data["elements_chain"] = ""
data["id"] = str(UUIDT())
data["event"] = event_name
data["raw_payload"] = json.dumps(raw_payload)
data["now"] = datetime.fromisoformat(data["now"]).replace(tzinfo=None).isoformat() if data["now"] else None
data["event_uuid"] = event["uuid"]
del data["uuid"]
try:
KafkaProducer().produce(topic=topic, data=data)
statsd.incr(settings.EVENTS_DEAD_LETTER_QUEUE_STATSD_METRIC)
except Exception as e:
capture_exception(e)
statsd.incr("events_dead_letter_queue_produce_error")
if settings.DEBUG:
print("Failed to produce to events dead letter queue with error:", e)
def _datetime_from_seconds_or_millis(timestamp: str) -> datetime: def _datetime_from_seconds_or_millis(timestamp: str) -> datetime:
@ -173,7 +173,7 @@ def get_event(request):
return error_response return error_response
send_events_to_dead_letter_queue = False send_events_to_dead_letter_queue = False
if db_error and is_clickhouse_enabled(): if db_error:
send_events_to_dead_letter_queue = True send_events_to_dead_letter_queue = True
if isinstance(data, dict): if isinstance(data, dict):
@ -295,23 +295,14 @@ def get_distinct_id(event):
def capture_internal(event, distinct_id, ip, site_url, now, sent_at, team_id, event_uuid=UUIDT()) -> None: def capture_internal(event, distinct_id, ip, site_url, now, sent_at, team_id, event_uuid=UUIDT()) -> None:
if is_clickhouse_enabled(): parsed_event = parse_kafka_event_data(
parsed_event = parse_kafka_event_data( distinct_id=distinct_id,
distinct_id=distinct_id, ip=ip,
ip=ip, site_url=site_url,
site_url=site_url, data=event,
data=event, team_id=team_id,
team_id=team_id, now=now,
now=now, sent_at=sent_at,
sent_at=sent_at, event_uuid=event_uuid,
event_uuid=event_uuid, )
) log_event(parsed_event, event["event"])
log_event(parsed_event, event["event"])
else:
task_name = "posthog.tasks.process_event.process_event_with_plugins"
celery_queue = settings.PLUGINS_CELERY_QUEUE
celery_app.send_task(
name=task_name,
queue=celery_queue,
args=[distinct_id, ip, site_url, event, team_id, now.isoformat(), sent_at,],
)

View File

@ -24,8 +24,7 @@ from posthog.queries.stickiness import (
stickiness_format_intervals, stickiness_format_intervals,
stickiness_process_entity_type, stickiness_process_entity_type,
) )
from posthog.tasks.calculate_cohort import calculate_cohort, calculate_cohort_ch, calculate_cohort_from_list from posthog.tasks.calculate_cohort import calculate_cohort_ch, calculate_cohort_from_list
from posthog.utils import is_clickhouse_enabled
class CohortSerializer(serializers.ModelSerializer): class CohortSerializer(serializers.ModelSerializer):
@ -75,10 +74,7 @@ class CohortSerializer(serializers.ModelSerializer):
if cohort.is_static: if cohort.is_static:
self._handle_static(cohort, request) self._handle_static(cohort, request)
else: else:
if is_clickhouse_enabled(): calculate_cohort_ch.delay(cohort.id)
calculate_cohort_ch.delay(cohort.id)
else:
calculate_cohort.delay(cohort.id)
report_user_action(request.user, "cohort created", cohort.get_analytics_metadata()) report_user_action(request.user, "cohort created", cohort.get_analytics_metadata())
return cohort return cohort
@ -146,10 +142,7 @@ class CohortSerializer(serializers.ModelSerializer):
if request.FILES.get("csv"): if request.FILES.get("csv"):
self._calculate_static_by_csv(request.FILES["csv"], cohort) self._calculate_static_by_csv(request.FILES["csv"], cohort)
else: else:
if is_clickhouse_enabled(): calculate_cohort_ch.delay(cohort.id)
calculate_cohort_ch.delay(cohort.id)
else:
calculate_cohort.delay(cohort.id)
report_user_action( report_user_action(
request.user, request.user,

View File

@ -7,10 +7,8 @@ from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from posthog.async_migrations.status import async_migrations_ok
from posthog.gitsha import GIT_SHA from posthog.gitsha import GIT_SHA
from posthog.internal_metrics.team import get_internal_metrics_dashboards from posthog.internal_metrics.team import get_internal_metrics_dashboards
from posthog.models import Element, Event, SessionRecordingEvent
from posthog.permissions import OrganizationAdminAnyPermissions, SingleTenancyOrAdmin from posthog.permissions import OrganizationAdminAnyPermissions, SingleTenancyOrAdmin
from posthog.utils import ( from posthog.utils import (
dict_from_cursor_fetchall, dict_from_cursor_fetchall,
@ -19,9 +17,6 @@ from posthog.utils import (
get_plugin_server_version, get_plugin_server_version,
get_redis_info, get_redis_info,
get_redis_queue_depth, get_redis_queue_depth,
get_table_approx_count,
get_table_size,
is_clickhouse_enabled,
is_plugin_server_alive, is_plugin_server_alive,
is_postgres_alive, is_postgres_alive,
is_redis_alive, is_redis_alive,
@ -58,11 +53,7 @@ class InstanceStatusViewSet(viewsets.ViewSet):
) )
metrics.append( metrics.append(
{ {"key": "analytics_database", "metric": "Analytics database in use", "value": "ClickHouse",}
"key": "analytics_database",
"metric": "Analytics database in use",
"value": "ClickHouse" if is_clickhouse_enabled() else "Postgres",
}
) )
metrics.append( metrics.append(
@ -98,40 +89,9 @@ class InstanceStatusViewSet(viewsets.ViewSet):
} }
) )
# metrics.append( from ee.clickhouse.system_status import system_status
# {"key": "async_migrations_ok", "metric": "Async migrations up-to-date", "value": async_migrations_ok()}
# )
if not is_clickhouse_enabled(): metrics.extend(list(system_status()))
event_table_count = get_table_approx_count(Event._meta.db_table)
event_table_size = get_table_size(Event._meta.db_table)
element_table_count = get_table_approx_count(Element._meta.db_table)
element_table_size = get_table_size(Element._meta.db_table)
session_recording_event_table_count = get_table_approx_count(SessionRecordingEvent._meta.db_table)
session_recording_event_table_size = get_table_size(SessionRecordingEvent._meta.db_table)
metrics.append(
{
"metric": "Postgres elements table size",
"value": f"{element_table_count} rows (~{element_table_size})",
}
)
metrics.append(
{"metric": "Postgres events table size", "value": f"{event_table_count} rows (~{event_table_size})"}
)
metrics.append(
{
"metric": "Postgres session recording table size",
"value": f"{session_recording_event_table_count} rows (~{session_recording_event_table_size})",
}
)
if is_clickhouse_enabled():
from ee.clickhouse.system_status import system_status
metrics.extend(list(system_status()))
metrics.append({"key": "redis_alive", "metric": "Redis alive", "value": redis_alive}) metrics.append({"key": "redis_alive", "metric": "Redis alive", "value": redis_alive})
if redis_alive: if redis_alive:
@ -175,11 +135,10 @@ class InstanceStatusViewSet(viewsets.ViewSet):
def queries(self, request: Request) -> Response: def queries(self, request: Request) -> Response:
queries = {"postgres_running": self.get_postgres_running_queries()} queries = {"postgres_running": self.get_postgres_running_queries()}
if is_clickhouse_enabled(): from ee.clickhouse.system_status import get_clickhouse_running_queries, get_clickhouse_slow_log
from ee.clickhouse.system_status import get_clickhouse_running_queries, get_clickhouse_slow_log
queries["clickhouse_running"] = get_clickhouse_running_queries() queries["clickhouse_running"] = get_clickhouse_running_queries()
queries["clickhouse_slow_log"] = get_clickhouse_slow_log() queries["clickhouse_slow_log"] = get_clickhouse_slow_log()
return Response({"results": queries}) return Response({"results": queries})
@ -190,10 +149,10 @@ class InstanceStatusViewSet(viewsets.ViewSet):
) )
def analyze_ch_query(self, request: Request) -> Response: def analyze_ch_query(self, request: Request) -> Response:
response = {} response = {}
if is_clickhouse_enabled():
from ee.clickhouse.system_status import analyze_query
response["results"] = analyze_query(request.data["query"]) from ee.clickhouse.system_status import analyze_query
response["results"] = analyze_query(request.data["query"])
return Response(response) return Response(response)

View File

@ -8,7 +8,6 @@ from posthog.test.base import APIBaseTest
def factory_test_action_api(event_factory): def factory_test_action_api(event_factory):
@patch("posthog.tasks.calculate_action.calculate_action.delay")
class TestActionApi(APIBaseTest): class TestActionApi(APIBaseTest):
@patch("posthog.api.action.report_user_action") @patch("posthog.api.action.report_user_action")
def test_create_action(self, patch_capture, *args): def test_create_action(self, patch_capture, *args):
@ -270,7 +269,3 @@ def factory_test_action_api(event_factory):
self.assertEqual(response, {"count": 1}) self.assertEqual(response, {"count": 1})
return TestActionApi return TestActionApi
class TestAction(factory_test_action_api(Event.objects.create)): # type: ignore
pass

View File

@ -2,15 +2,13 @@ import json
from freezegun import freeze_time from freezegun import freeze_time
from posthog.constants import ENTITY_ID, ENTITY_MATH, ENTITY_TYPE, TRENDS_CUMULATIVE from posthog.constants import ENTITY_ID, ENTITY_TYPE, TRENDS_CUMULATIVE
from posthog.models import Action, ActionStep, Cohort, Event, Organization, Person from posthog.models import Action, ActionStep, Cohort, Event, Organization, Person
from posthog.queries.abstract_test.test_interval import AbstractIntervalTest
from posthog.tasks.calculate_action import calculate_actions_from_last_calculation
from posthog.test.base import APIBaseTest from posthog.test.base import APIBaseTest
def action_people_test_factory(event_factory, person_factory, action_factory, cohort_factory): def action_people_test_factory(event_factory, person_factory, action_factory, cohort_factory):
class TestActionPeople(AbstractIntervalTest, APIBaseTest): class TestActionPeople(APIBaseTest):
def _create_events(self, use_time=False): def _create_events(self, use_time=False):
action_factory(team=self.team, name="no events") action_factory(team=self.team, name="no events")
@ -185,7 +183,7 @@ def action_people_test_factory(event_factory, person_factory, action_factory, co
event_factory( event_factory(
team=self.team, event="sign up", distinct_id="person1", timestamp="2019-11-27T16:50:00Z", team=self.team, event="sign up", distinct_id="person1", timestamp="2019-11-27T16:50:00Z",
) )
calculate_actions_from_last_calculation()
return person1, person2, person3, person4, person5, person6, person7 return person1, person2, person3, person4, person5, person6, person7
def test_hour_interval(self): def test_hour_interval(self):
@ -270,7 +268,7 @@ def action_people_test_factory(event_factory, person_factory, action_factory, co
event_factory( event_factory(
team=self.team, event="sign up", distinct_id="outside_range", timestamp="2020-01-05T15:50:00Z", team=self.team, event="sign up", distinct_id="outside_range", timestamp="2020-01-05T15:50:00Z",
) )
calculate_actions_from_last_calculation()
# test people # test people
action_response = self.client.get( action_response = self.client.get(
f"/api/projects/{self.team.id}/actions/people/", f"/api/projects/{self.team.id}/actions/people/",
@ -314,7 +312,7 @@ def action_people_test_factory(event_factory, person_factory, action_factory, co
event_factory( event_factory(
team=self.team, event="sign up", distinct_id="outside_range", timestamp="2020-01-05T15:50:00Z", team=self.team, event="sign up", distinct_id="outside_range", timestamp="2020-01-05T15:50:00Z",
) )
calculate_actions_from_last_calculation()
# test people # test people
action_response = self.client.get( action_response = self.client.get(
f"/api/projects/{self.team.id}/actions/people/", f"/api/projects/{self.team.id}/actions/people/",
@ -627,25 +625,3 @@ def action_people_test_factory(event_factory, person_factory, action_factory, co
self.assertEqual(people["results"][0]["people"][0]["id"], person2.pk) self.assertEqual(people["results"][0]["people"][0]["id"], person2.pk)
return TestActionPeople return TestActionPeople
def _create_action(**kwargs):
team = kwargs.pop("team")
name = kwargs.pop("name")
action = Action.objects.create(team=team, name=name)
ActionStep.objects.create(action=action, event=name)
action.calculate_events()
return action
def _create_cohort(**kwargs):
team = kwargs.pop("team")
name = kwargs.pop("name")
groups = kwargs.pop("groups")
cohort = Cohort.objects.create(team=team, name=name, groups=groups)
cohort.calculate_people()
return cohort
class TestActionPeople(action_people_test_factory(Event.objects.create, Person.objects.create, _create_action, _create_cohort)): # type: ignore
pass

View File

@ -1,7 +1,8 @@
import base64 import base64
import gzip import gzip
import json import json
from datetime import timedelta from datetime import datetime, timedelta
from datetime import timezone as tz
from typing import Any, Dict, List, Union from typing import Any, Dict, List, Union
from unittest.mock import MagicMock, call, patch from unittest.mock import MagicMock, call, patch
from urllib.parse import quote from urllib.parse import quote
@ -44,21 +45,20 @@ class TestCapture(BaseTest):
return json.loads(base64.b64decode(data)) return json.loads(base64.b64decode(data))
def _to_arguments(self, patch_process_event_with_plugins: Any) -> dict: def _to_arguments(self, patch_process_event_with_plugins: Any) -> dict:
args = patch_process_event_with_plugins.call_args[1]["args"] args = patch_process_event_with_plugins.call_args[1]["data"]
distinct_id, ip, site_url, data, team_id, now, sent_at = args
return { return {
"distinct_id": distinct_id, "distinct_id": args["distinct_id"],
"ip": ip, "ip": args["ip"],
"site_url": site_url, "site_url": args["site_url"],
"data": data, "data": json.loads(args["data"]),
"team_id": team_id, "team_id": args["team_id"],
"now": now, "now": args["now"],
"sent_at": sent_at, "sent_at": args["sent_at"],
} }
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_capture_event(self, patch_process_event_with_plugins): def test_capture_event(self, kafka_produce):
data = { data = {
"event": "$autocapture", "event": "$autocapture",
"properties": { "properties": {
@ -75,7 +75,7 @@ class TestCapture(BaseTest):
with self.assertNumQueries(1): with self.assertNumQueries(1):
response = self.client.get("/e/?data=%s" % quote(self._to_json(data)), HTTP_ORIGIN="https://localhost",) response = self.client.get("/e/?data=%s" % quote(self._to_json(data)), HTTP_ORIGIN="https://localhost",)
self.assertEqual(response.get("access-control-allow-origin"), "https://localhost") self.assertEqual(response.get("access-control-allow-origin"), "https://localhost")
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
self.assertDictEqual( self.assertDictEqual(
@ -90,7 +90,7 @@ class TestCapture(BaseTest):
) )
@patch("posthog.api.capture.configure_scope") @patch("posthog.api.capture.configure_scope")
@patch("posthog.api.capture.celery_app.send_task", MagicMock()) @patch("ee.kafka_client.client._KafkaProducer.produce", MagicMock())
def test_capture_event_adds_library_to_sentry(self, patched_scope): def test_capture_event_adds_library_to_sentry(self, patched_scope):
mock_set_tag = mock_sentry_context_for_tagging(patched_scope) mock_set_tag = mock_sentry_context_for_tagging(patched_scope)
@ -115,7 +115,7 @@ class TestCapture(BaseTest):
mock_set_tag.assert_has_calls([call("library", "web"), call("library.version", "1.14.1")]) mock_set_tag.assert_has_calls([call("library", "web"), call("library.version", "1.14.1")])
@patch("posthog.api.capture.configure_scope") @patch("posthog.api.capture.configure_scope")
@patch("posthog.api.capture.celery_app.send_task", MagicMock()) @patch("ee.kafka_client.client._KafkaProducer.produce", MagicMock())
def test_capture_event_adds_unknown_to_sentry_when_no_properties_sent(self, patched_scope): def test_capture_event_adds_unknown_to_sentry_when_no_properties_sent(self, patched_scope):
mock_set_tag = mock_sentry_context_for_tagging(patched_scope) mock_set_tag = mock_sentry_context_for_tagging(patched_scope)
@ -137,8 +137,8 @@ class TestCapture(BaseTest):
mock_set_tag.assert_has_calls([call("library", "unknown"), call("library.version", "unknown")]) mock_set_tag.assert_has_calls([call("library", "unknown"), call("library.version", "unknown")])
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_personal_api_key(self, patch_process_event_with_plugins): def test_personal_api_key(self, kafka_produce):
key = PersonalAPIKey(label="X", user=self.user) key = PersonalAPIKey(label="X", user=self.user)
key.save() key.save()
data = { data = {
@ -158,7 +158,7 @@ class TestCapture(BaseTest):
with self.assertNumQueries(4): with self.assertNumQueries(4):
response = self.client.get("/e/?data=%s" % quote(self._to_json(data)), HTTP_ORIGIN="https://localhost",) response = self.client.get("/e/?data=%s" % quote(self._to_json(data)), HTTP_ORIGIN="https://localhost",)
self.assertEqual(response.get("access-control-allow-origin"), "https://localhost") self.assertEqual(response.get("access-control-allow-origin"), "https://localhost")
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
self.assertDictEqual( self.assertDictEqual(
@ -172,8 +172,8 @@ class TestCapture(BaseTest):
}, },
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_personal_api_key_from_batch_request(self, patch_process_event_with_plugins): def test_personal_api_key_from_batch_request(self, kafka_produce):
# Originally issue POSTHOG-2P8 # Originally issue POSTHOG-2P8
key = PersonalAPIKey(label="X", user=self.user) key = PersonalAPIKey(label="X", user=self.user)
key.save() key.save()
@ -195,7 +195,7 @@ class TestCapture(BaseTest):
response = self.client.get("/e/?data=%s" % quote(self._to_json(data))) response = self.client.get("/e/?data=%s" % quote(self._to_json(data)))
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
self.assertDictEqual( self.assertDictEqual(
@ -221,8 +221,8 @@ class TestCapture(BaseTest):
}, },
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_multiple_events(self, patch_process_event_with_plugins): def test_multiple_events(self, kafka_produce):
self.client.post( self.client.post(
"/track/", "/track/",
data={ data={
@ -235,10 +235,10 @@ class TestCapture(BaseTest):
"api_key": self.team.api_token, "api_key": self.team.api_token,
}, },
) )
self.assertEqual(patch_process_event_with_plugins.call_count, 2) self.assertEqual(kafka_produce.call_count, 2)
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_emojis_in_text(self, patch_process_event_with_plugins): def test_emojis_in_text(self, kafka_produce):
self.team.api_token = "xp9qT2VLY76JJg" self.team.api_token = "xp9qT2VLY76JJg"
self.team.save() self.team.save()
@ -249,14 +249,13 @@ class TestCapture(BaseTest):
"data": "eyJldmVudCI6ICIkd2ViX2V2ZW50IiwicHJvcGVydGllcyI6IHsiJG9zIjogIk1hYyBPUyBYIiwiJGJyb3dzZXIiOiAiQ2hyb21lIiwiJHJlZmVycmVyIjogImh0dHBzOi8vYXBwLmhpYmVybHkuY29tL2xvZ2luP25leHQ9LyIsIiRyZWZlcnJpbmdfZG9tYWluIjogImFwcC5oaWJlcmx5LmNvbSIsIiRjdXJyZW50X3VybCI6ICJodHRwczovL2FwcC5oaWJlcmx5LmNvbS8iLCIkYnJvd3Nlcl92ZXJzaW9uIjogNzksIiRzY3JlZW5faGVpZ2h0IjogMjE2MCwiJHNjcmVlbl93aWR0aCI6IDM4NDAsInBoX2xpYiI6ICJ3ZWIiLCIkbGliX3ZlcnNpb24iOiAiMi4zMy4xIiwiJGluc2VydF9pZCI6ICJnNGFoZXFtejVrY3AwZ2QyIiwidGltZSI6IDE1ODA0MTAzNjguMjY1LCJkaXN0aW5jdF9pZCI6IDYzLCIkZGV2aWNlX2lkIjogIjE2ZmQ1MmRkMDQ1NTMyLTA1YmNhOTRkOWI3OWFiLTM5NjM3YzBlLTFhZWFhMC0xNmZkNTJkZDA0NjQxZCIsIiRpbml0aWFsX3JlZmVycmVyIjogIiRkaXJlY3QiLCIkaW5pdGlhbF9yZWZlcnJpbmdfZG9tYWluIjogIiRkaXJlY3QiLCIkdXNlcl9pZCI6IDYzLCIkZXZlbnRfdHlwZSI6ICJjbGljayIsIiRjZV92ZXJzaW9uIjogMSwiJGhvc3QiOiAiYXBwLmhpYmVybHkuY29tIiwiJHBhdGhuYW1lIjogIi8iLCIkZWxlbWVudHMiOiBbCiAgICB7InRhZ19uYW1lIjogImJ1dHRvbiIsIiRlbF90ZXh0IjogIu2gve2yuyBXcml0aW5nIGNvZGUiLCJjbGFzc2VzIjogWwogICAgImJ0biIsCiAgICAiYnRuLXNlY29uZGFyeSIKXSwiYXR0cl9fY2xhc3MiOiAiYnRuIGJ0bi1zZWNvbmRhcnkiLCJhdHRyX19zdHlsZSI6ICJjdXJzb3I6IHBvaW50ZXI7IG1hcmdpbi1yaWdodDogOHB4OyBtYXJnaW4tYm90dG9tOiAxcmVtOyIsIm50aF9jaGlsZCI6IDIsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsImNsYXNzZXMiOiBbCiAgICAiZmVlZGJhY2stc3RlcCIsCiAgICAiZmVlZGJhY2stc3RlcC1zZWxlY3RlZCIKXSwiYXR0cl9fY2xhc3MiOiAiZmVlZGJhY2stc3RlcCBmZWVkYmFjay1zdGVwLXNlbGVjdGVkIiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJnaXZlLWZlZWRiYWNrIgpdLCJhdHRyX19jbGFzcyI6ICJnaXZlLWZlZWRiYWNrIiwiYXR0cl9fc3R5bGUiOiAid2lkdGg6IDkwJTsgbWFyZ2luOiAwcHggYXV0bzsgZm9udC1zaXplOiAxNXB4OyBwb3NpdGlvbjogcmVsYXRpdmU7IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiYXR0cl9fc3R5bGUiOiAib3ZlcmZsb3c6IGhpZGRlbjsiLCJudGhfY2hpbGQiOiAxLCJudGhfb2ZfdHlwZSI6IDF9LAogICAgeyJ0YWdfbmFtZSI6ICJkaXYiLCJjbGFzc2VzIjogWwogICAgIm1vZGFsLWJvZHkiCl0sImF0dHJfX2NsYXNzIjogIm1vZGFsLWJvZHkiLCJhdHRyX19zdHlsZSI6ICJmb250LXNpemU6IDE1cHg7IiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAyfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJtb2RhbC1jb250ZW50IgpdLCJhdHRyX19jbGFzcyI6ICJtb2RhbC1jb250ZW50IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJtb2RhbC1kaWFsb2ciLAogICAgIm1vZGFsLWxnIgpdLCJhdHRyX19jbGFzcyI6ICJtb2RhbC1kaWFsb2cgbW9kYWwtbGciLCJhdHRyX19yb2xlIjogImRvY3VtZW50IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJtb2RhbCIsCiAgICAiZmFkZSIsCiAgICAic2hvdyIKXSwiYXR0cl9fY2xhc3MiOiAibW9kYWwgZmFkZSBzaG93IiwiYXR0cl9fc3R5bGUiOiAiZGlzcGxheTogYmxvY2s7IiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAyfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJrLXBvcnRsZXRfX2JvZHkiLAogICAgIiIKXSwiYXR0cl9fY2xhc3MiOiAiay1wb3J0bGV0X19ib2R5ICIsImF0dHJfX3N0eWxlIjogInBhZGRpbmc6IDBweDsiLCJudGhfY2hpbGQiOiAyLCJudGhfb2ZfdHlwZSI6IDJ9LAogICAgeyJ0YWdfbmFtZSI6ICJkaXYiLCJjbGFzc2VzIjogWwogICAgImstcG9ydGxldCIsCiAgICAiay1wb3J0bGV0LS1oZWlnaHQtZmx1aWQiCl0sImF0dHJfX2NsYXNzIjogImstcG9ydGxldCBrLXBvcnRsZXQtLWhlaWdodC1mbHVpZCIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsImNsYXNzZXMiOiBbCiAgICAiY29sLWxnLTYiCl0sImF0dHJfX2NsYXNzIjogImNvbC1sZy02IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJyb3ciCl0sImF0dHJfX2NsYXNzIjogInJvdyIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsImF0dHJfX3N0eWxlIjogInBhZGRpbmc6IDQwcHggMzBweCAwcHg7IGJhY2tncm91bmQtY29sb3I6IHJnYigyMzksIDIzOSwgMjQ1KTsgbWFyZ2luLXRvcDogLTQwcHg7IG1pbi1oZWlnaHQ6IGNhbGMoMTAwdmggLSA0MHB4KTsiLCJudGhfY2hpbGQiOiAyLCJudGhfb2ZfdHlwZSI6IDJ9LAogICAgeyJ0YWdfbmFtZSI6ICJkaXYiLCJhdHRyX19zdHlsZSI6ICJtYXJnaW4tdG9wOiAwcHg7IiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAyfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJBcHAiCl0sImF0dHJfX2NsYXNzIjogIkFwcCIsImF0dHJfX3N0eWxlIjogImNvbG9yOiByZ2IoNTIsIDYxLCA2Mik7IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiYXR0cl9faWQiOiAicm9vdCIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImJvZHkiLCJudGhfY2hpbGQiOiAyLCJudGhfb2ZfdHlwZSI6IDF9Cl0sInRva2VuIjogInhwOXFUMlZMWTc2SkpnIn19" "data": "eyJldmVudCI6ICIkd2ViX2V2ZW50IiwicHJvcGVydGllcyI6IHsiJG9zIjogIk1hYyBPUyBYIiwiJGJyb3dzZXIiOiAiQ2hyb21lIiwiJHJlZmVycmVyIjogImh0dHBzOi8vYXBwLmhpYmVybHkuY29tL2xvZ2luP25leHQ9LyIsIiRyZWZlcnJpbmdfZG9tYWluIjogImFwcC5oaWJlcmx5LmNvbSIsIiRjdXJyZW50X3VybCI6ICJodHRwczovL2FwcC5oaWJlcmx5LmNvbS8iLCIkYnJvd3Nlcl92ZXJzaW9uIjogNzksIiRzY3JlZW5faGVpZ2h0IjogMjE2MCwiJHNjcmVlbl93aWR0aCI6IDM4NDAsInBoX2xpYiI6ICJ3ZWIiLCIkbGliX3ZlcnNpb24iOiAiMi4zMy4xIiwiJGluc2VydF9pZCI6ICJnNGFoZXFtejVrY3AwZ2QyIiwidGltZSI6IDE1ODA0MTAzNjguMjY1LCJkaXN0aW5jdF9pZCI6IDYzLCIkZGV2aWNlX2lkIjogIjE2ZmQ1MmRkMDQ1NTMyLTA1YmNhOTRkOWI3OWFiLTM5NjM3YzBlLTFhZWFhMC0xNmZkNTJkZDA0NjQxZCIsIiRpbml0aWFsX3JlZmVycmVyIjogIiRkaXJlY3QiLCIkaW5pdGlhbF9yZWZlcnJpbmdfZG9tYWluIjogIiRkaXJlY3QiLCIkdXNlcl9pZCI6IDYzLCIkZXZlbnRfdHlwZSI6ICJjbGljayIsIiRjZV92ZXJzaW9uIjogMSwiJGhvc3QiOiAiYXBwLmhpYmVybHkuY29tIiwiJHBhdGhuYW1lIjogIi8iLCIkZWxlbWVudHMiOiBbCiAgICB7InRhZ19uYW1lIjogImJ1dHRvbiIsIiRlbF90ZXh0IjogIu2gve2yuyBXcml0aW5nIGNvZGUiLCJjbGFzc2VzIjogWwogICAgImJ0biIsCiAgICAiYnRuLXNlY29uZGFyeSIKXSwiYXR0cl9fY2xhc3MiOiAiYnRuIGJ0bi1zZWNvbmRhcnkiLCJhdHRyX19zdHlsZSI6ICJjdXJzb3I6IHBvaW50ZXI7IG1hcmdpbi1yaWdodDogOHB4OyBtYXJnaW4tYm90dG9tOiAxcmVtOyIsIm50aF9jaGlsZCI6IDIsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsImNsYXNzZXMiOiBbCiAgICAiZmVlZGJhY2stc3RlcCIsCiAgICAiZmVlZGJhY2stc3RlcC1zZWxlY3RlZCIKXSwiYXR0cl9fY2xhc3MiOiAiZmVlZGJhY2stc3RlcCBmZWVkYmFjay1zdGVwLXNlbGVjdGVkIiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJnaXZlLWZlZWRiYWNrIgpdLCJhdHRyX19jbGFzcyI6ICJnaXZlLWZlZWRiYWNrIiwiYXR0cl9fc3R5bGUiOiAid2lkdGg6IDkwJTsgbWFyZ2luOiAwcHggYXV0bzsgZm9udC1zaXplOiAxNXB4OyBwb3NpdGlvbjogcmVsYXRpdmU7IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiYXR0cl9fc3R5bGUiOiAib3ZlcmZsb3c6IGhpZGRlbjsiLCJudGhfY2hpbGQiOiAxLCJudGhfb2ZfdHlwZSI6IDF9LAogICAgeyJ0YWdfbmFtZSI6ICJkaXYiLCJjbGFzc2VzIjogWwogICAgIm1vZGFsLWJvZHkiCl0sImF0dHJfX2NsYXNzIjogIm1vZGFsLWJvZHkiLCJhdHRyX19zdHlsZSI6ICJmb250LXNpemU6IDE1cHg7IiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAyfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJtb2RhbC1jb250ZW50IgpdLCJhdHRyX19jbGFzcyI6ICJtb2RhbC1jb250ZW50IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJtb2RhbC1kaWFsb2ciLAogICAgIm1vZGFsLWxnIgpdLCJhdHRyX19jbGFzcyI6ICJtb2RhbC1kaWFsb2cgbW9kYWwtbGciLCJhdHRyX19yb2xlIjogImRvY3VtZW50IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJtb2RhbCIsCiAgICAiZmFkZSIsCiAgICAic2hvdyIKXSwiYXR0cl9fY2xhc3MiOiAibW9kYWwgZmFkZSBzaG93IiwiYXR0cl9fc3R5bGUiOiAiZGlzcGxheTogYmxvY2s7IiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAyfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJrLXBvcnRsZXRfX2JvZHkiLAogICAgIiIKXSwiYXR0cl9fY2xhc3MiOiAiay1wb3J0bGV0X19ib2R5ICIsImF0dHJfX3N0eWxlIjogInBhZGRpbmc6IDBweDsiLCJudGhfY2hpbGQiOiAyLCJudGhfb2ZfdHlwZSI6IDJ9LAogICAgeyJ0YWdfbmFtZSI6ICJkaXYiLCJjbGFzc2VzIjogWwogICAgImstcG9ydGxldCIsCiAgICAiay1wb3J0bGV0LS1oZWlnaHQtZmx1aWQiCl0sImF0dHJfX2NsYXNzIjogImstcG9ydGxldCBrLXBvcnRsZXQtLWhlaWdodC1mbHVpZCIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsImNsYXNzZXMiOiBbCiAgICAiY29sLWxnLTYiCl0sImF0dHJfX2NsYXNzIjogImNvbC1sZy02IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJyb3ciCl0sImF0dHJfX2NsYXNzIjogInJvdyIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImRpdiIsImF0dHJfX3N0eWxlIjogInBhZGRpbmc6IDQwcHggMzBweCAwcHg7IGJhY2tncm91bmQtY29sb3I6IHJnYigyMzksIDIzOSwgMjQ1KTsgbWFyZ2luLXRvcDogLTQwcHg7IG1pbi1oZWlnaHQ6IGNhbGMoMTAwdmggLSA0MHB4KTsiLCJudGhfY2hpbGQiOiAyLCJudGhfb2ZfdHlwZSI6IDJ9LAogICAgeyJ0YWdfbmFtZSI6ICJkaXYiLCJhdHRyX19zdHlsZSI6ICJtYXJnaW4tdG9wOiAwcHg7IiwibnRoX2NoaWxkIjogMiwibnRoX29mX3R5cGUiOiAyfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiY2xhc3NlcyI6IFsKICAgICJBcHAiCl0sImF0dHJfX2NsYXNzIjogIkFwcCIsImF0dHJfX3N0eWxlIjogImNvbG9yOiByZ2IoNTIsIDYxLCA2Mik7IiwibnRoX2NoaWxkIjogMSwibnRoX29mX3R5cGUiOiAxfSwKICAgIHsidGFnX25hbWUiOiAiZGl2IiwiYXR0cl9faWQiOiAicm9vdCIsIm50aF9jaGlsZCI6IDEsIm50aF9vZl90eXBlIjogMX0sCiAgICB7InRhZ19uYW1lIjogImJvZHkiLCJudGhfY2hpbGQiOiAyLCJudGhfb2ZfdHlwZSI6IDF9Cl0sInRva2VuIjogInhwOXFUMlZMWTc2SkpnIn19"
}, },
) )
properties = json.loads(kafka_produce.call_args[1]["data"]["data"])["properties"]
self.assertEqual( self.assertEqual(
patch_process_event_with_plugins.call_args[1]["args"][3]["properties"]["$elements"][0]["$el_text"], properties["$elements"][0]["$el_text"], "💻 Writing code",
"💻 Writing code",
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_js_gzip(self, patch_process_event_with_plugins): def test_js_gzip(self, kafka_produce):
self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4" self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4"
self.team.save() self.team.save()
@ -266,14 +265,16 @@ class TestCapture(BaseTest):
content_type="text/plain", content_type="text/plain",
) )
self.assertEqual(patch_process_event_with_plugins.call_count, 1) self.assertEqual(kafka_produce.call_count, 1)
self.assertEqual(patch_process_event_with_plugins.call_args[1]["args"][3]["event"], "my-event")
data = json.loads(kafka_produce.call_args[1]["data"]["data"])
self.assertEqual(data["event"], "my-event")
self.assertEqual( self.assertEqual(
patch_process_event_with_plugins.call_args[1]["args"][3]["properties"]["prop"], "💻 Writing code", data["properties"]["prop"], "💻 Writing code",
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_js_gzip_with_no_content_type(self, patch_process_event_with_plugins): def test_js_gzip_with_no_content_type(self, kafka_produce):
"IE11 sometimes does not send content_type" "IE11 sometimes does not send content_type"
self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4" self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4"
@ -285,14 +286,16 @@ class TestCapture(BaseTest):
content_type="", content_type="",
) )
self.assertEqual(patch_process_event_with_plugins.call_count, 1) self.assertEqual(kafka_produce.call_count, 1)
self.assertEqual(patch_process_event_with_plugins.call_args[1]["args"][3]["event"], "my-event")
data = json.loads(kafka_produce.call_args[1]["data"]["data"])
self.assertEqual(data["event"], "my-event")
self.assertEqual( self.assertEqual(
patch_process_event_with_plugins.call_args[1]["args"][3]["properties"]["prop"], "💻 Writing code", data["properties"]["prop"], "💻 Writing code",
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_invalid_gzip(self, patch_process_event_with_plugins): def test_invalid_gzip(self, kafka_produce):
self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4" self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4"
self.team.save() self.team.save()
@ -308,10 +311,10 @@ class TestCapture(BaseTest):
code="invalid_payload", code="invalid_payload",
), ),
) )
self.assertEqual(patch_process_event_with_plugins.call_count, 0) self.assertEqual(kafka_produce.call_count, 0)
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_invalid_lz64(self, patch_process_event_with_plugins): def test_invalid_lz64(self, kafka_produce):
self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4" self.team.api_token = "rnEnwNvmHphTu5rFG4gWDDs49t00Vk50tDOeDdedMb4"
self.team.save() self.team.save()
@ -324,20 +327,21 @@ class TestCapture(BaseTest):
"Malformed request data: Failed to decompress data.", code="invalid_payload", "Malformed request data: Failed to decompress data.", code="invalid_payload",
), ),
) )
self.assertEqual(patch_process_event_with_plugins.call_count, 0) self.assertEqual(kafka_produce.call_count, 0)
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_incorrect_padding(self, patch_process_event_with_plugins): def test_incorrect_padding(self, kafka_produce):
response = self.client.get( response = self.client.get(
"/e/?data=eyJldmVudCI6IndoYXRldmVmciIsInByb3BlcnRpZXMiOnsidG9rZW4iOiJ0b2tlbjEyMyIsImRpc3RpbmN0X2lkIjoiYXNkZiJ9fQ", "/e/?data=eyJldmVudCI6IndoYXRldmVmciIsInByb3BlcnRpZXMiOnsidG9rZW4iOiJ0b2tlbjEyMyIsImRpc3RpbmN0X2lkIjoiYXNkZiJ9fQ",
content_type="application/json", content_type="application/json",
HTTP_REFERER="https://localhost", HTTP_REFERER="https://localhost",
) )
self.assertEqual(response.json()["status"], 1) self.assertEqual(response.json()["status"], 1)
self.assertEqual(patch_process_event_with_plugins.call_args[1]["args"][3]["event"], "whatevefr") data = json.loads(kafka_produce.call_args[1]["data"]["data"])
self.assertEqual(data["event"], "whatevefr")
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_empty_request_returns_an_error(self, patch_process_event_with_plugins): def test_empty_request_returns_an_error(self, kafka_produce):
""" """
Empty requests that fail silently cause confusion as to whether they were successful or not. Empty requests that fail silently cause confusion as to whether they were successful or not.
""" """
@ -345,20 +349,20 @@ class TestCapture(BaseTest):
# Empty GET # Empty GET
response = self.client.get("/e/?data=", content_type="application/json", HTTP_ORIGIN="https://localhost",) response = self.client.get("/e/?data=", content_type="application/json", HTTP_ORIGIN="https://localhost",)
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertEqual(patch_process_event_with_plugins.call_count, 0) self.assertEqual(kafka_produce.call_count, 0)
# Empty POST # Empty POST
response = self.client.post("/e/", {}, content_type="application/json", HTTP_ORIGIN="https://localhost",) response = self.client.post("/e/", {}, content_type="application/json", HTTP_ORIGIN="https://localhost",)
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertEqual(patch_process_event_with_plugins.call_count, 0) self.assertEqual(kafka_produce.call_count, 0)
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_batch(self, patch_process_event_with_plugins): def test_batch(self, kafka_produce):
data = {"type": "capture", "event": "user signed up", "distinct_id": "2"} data = {"type": "capture", "event": "user signed up", "distinct_id": "2"}
response = self.client.post( response = self.client.post(
"/batch/", data={"api_key": self.team.api_token, "batch": [data]}, content_type="application/json", "/batch/", data={"api_key": self.team.api_token, "batch": [data]}, content_type="application/json",
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
self.assertDictEqual( self.assertDictEqual(
@ -372,8 +376,8 @@ class TestCapture(BaseTest):
}, },
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_batch_with_invalid_event(self, patch_process_event_with_plugins): def test_batch_with_invalid_event(self, kafka_produce):
data = [ data = [
{"type": "capture", "event": "event1", "distinct_id": "2"}, {"type": "capture", "event": "event1", "distinct_id": "2"},
{"type": "capture", "event": "event2"}, # invalid {"type": "capture", "event": "event2"}, # invalid
@ -387,13 +391,13 @@ class TestCapture(BaseTest):
# We should return a 200 but not process the invalid event # We should return a 200 but not process the invalid event
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(patch_process_event_with_plugins.call_count, 4) self.assertEqual(kafka_produce.call_count, 4)
events_processed = [call.kwargs["args"][3]["event"] for call in patch_process_event_with_plugins.call_args_list] events_processed = [json.loads(call.kwargs["data"]["data"])["event"] for call in kafka_produce.call_args_list]
self.assertEqual(events_processed, ["event1", "event3", "event4", "event5"]) # event2 not processed self.assertEqual(events_processed, ["event1", "event3", "event4", "event5"]) # event2 not processed
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_batch_gzip_header(self, patch_process_event_with_plugins): def test_batch_gzip_header(self, kafka_produce):
data = { data = {
"api_key": self.team.api_token, "api_key": self.team.api_token,
"batch": [{"type": "capture", "event": "user signed up", "distinct_id": "2",}], "batch": [{"type": "capture", "event": "user signed up", "distinct_id": "2",}],
@ -407,7 +411,7 @@ class TestCapture(BaseTest):
HTTP_CONTENT_ENCODING="gzip", HTTP_CONTENT_ENCODING="gzip",
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
self.assertDictEqual( self.assertDictEqual(
@ -421,8 +425,8 @@ class TestCapture(BaseTest):
}, },
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_batch_gzip_param(self, patch_process_event_with_plugins): def test_batch_gzip_param(self, kafka_produce):
data = { data = {
"api_key": self.team.api_token, "api_key": self.team.api_token,
"batch": [{"type": "capture", "event": "user signed up", "distinct_id": "2"}], "batch": [{"type": "capture", "event": "user signed up", "distinct_id": "2"}],
@ -435,7 +439,7 @@ class TestCapture(BaseTest):
content_type="application/json", content_type="application/json",
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
self.assertDictEqual( self.assertDictEqual(
@ -449,8 +453,8 @@ class TestCapture(BaseTest):
}, },
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_batch_lzstring(self, patch_process_event_with_plugins): def test_batch_lzstring(self, kafka_produce):
data = { data = {
"api_key": self.team.api_token, "api_key": self.team.api_token,
"batch": [{"type": "capture", "event": "user signed up", "distinct_id": "2"}], "batch": [{"type": "capture", "event": "user signed up", "distinct_id": "2"}],
@ -464,7 +468,7 @@ class TestCapture(BaseTest):
HTTP_CONTENT_ENCODING="lz64", HTTP_CONTENT_ENCODING="lz64",
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
self.assertDictEqual( self.assertDictEqual(
@ -478,8 +482,8 @@ class TestCapture(BaseTest):
}, },
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_lz64_with_emoji(self, patch_process_event_with_plugins): def test_lz64_with_emoji(self, kafka_produce):
self.team.api_token = "KZZZeIpycLH-tKobLBET2NOg7wgJF2KqDL5yWU_7tZw" self.team.api_token = "KZZZeIpycLH-tKobLBET2NOg7wgJF2KqDL5yWU_7tZw"
self.team.save() self.team.save()
response = self.client.post( response = self.client.post(
@ -489,7 +493,7 @@ class TestCapture(BaseTest):
HTTP_CONTENT_ENCODING="lz64", HTTP_CONTENT_ENCODING="lz64",
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(arguments["data"]["event"], "🤓") self.assertEqual(arguments["data"]["event"], "🤓")
def test_batch_incorrect_token(self): def test_batch_incorrect_token(self):
@ -546,8 +550,8 @@ class TestCapture(BaseTest):
self.assertEqual(statsd_incr_first_call.args[0], "invalid_event") self.assertEqual(statsd_incr_first_call.args[0], "invalid_event")
self.assertEqual(statsd_incr_first_call.kwargs, {"tags": {"error": "missing_distinct_id"}}) self.assertEqual(statsd_incr_first_call.kwargs, {"tags": {"error": "missing_distinct_id"}})
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_engage(self, patch_process_event_with_plugins): def test_engage(self, kafka_produce):
response = self.client.get( response = self.client.get(
"/engage/?data=%s" "/engage/?data=%s"
% quote( % quote(
@ -564,7 +568,7 @@ class TestCapture(BaseTest):
content_type="application/json", content_type="application/json",
HTTP_ORIGIN="https://localhost", HTTP_ORIGIN="https://localhost",
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(arguments["data"]["event"], "$identify") self.assertEqual(arguments["data"]["event"], "$identify")
arguments.pop("now") # can't compare fakedate arguments.pop("now") # can't compare fakedate
arguments.pop("sent_at") # can't compare fakedate arguments.pop("sent_at") # can't compare fakedate
@ -574,8 +578,8 @@ class TestCapture(BaseTest):
{"distinct_id": "3", "ip": "127.0.0.1", "site_url": "http://testserver", "team_id": self.team.pk,}, {"distinct_id": "3", "ip": "127.0.0.1", "site_url": "http://testserver", "team_id": self.team.pk,},
) )
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_python_library(self, patch_process_event_with_plugins): def test_python_library(self, kafka_produce):
self.client.post( self.client.post(
"/track/", "/track/",
data={ data={
@ -583,11 +587,11 @@ class TestCapture(BaseTest):
"api_key": self.team.api_token, # main difference in this test "api_key": self.team.api_token, # main difference in this test
}, },
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(arguments["team_id"], self.team.pk) self.assertEqual(arguments["team_id"], self.team.pk)
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_base64_decode_variations(self, patch_process_event_with_plugins): def test_base64_decode_variations(self, kafka_produce):
base64 = "eyJldmVudCI6IiRwYWdldmlldyIsInByb3BlcnRpZXMiOnsiZGlzdGluY3RfaWQiOiJlZWVlZWVlZ8+lZWVlZWUifX0=" base64 = "eyJldmVudCI6IiRwYWdldmlldyIsInByb3BlcnRpZXMiOnsiZGlzdGluY3RfaWQiOiJlZWVlZWVlZ8+lZWVlZWUifX0="
dict = self._dict_from_b64(base64) dict = self._dict_from_b64(base64)
self.assertDictEqual( self.assertDictEqual(
@ -598,7 +602,7 @@ class TestCapture(BaseTest):
self.client.post( self.client.post(
"/track/", data={"data": base64, "api_key": self.team.api_token,}, # main difference in this test "/track/", data={"data": base64, "api_key": self.team.api_token,}, # main difference in this test
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(arguments["team_id"], self.team.pk) self.assertEqual(arguments["team_id"], self.team.pk)
self.assertEqual(arguments["distinct_id"], "eeeeeeegϥeeeee") self.assertEqual(arguments["distinct_id"], "eeeeeeegϥeeeee")
@ -607,12 +611,12 @@ class TestCapture(BaseTest):
"/track/", "/track/",
data={"data": base64.replace("+", " "), "api_key": self.team.api_token,}, # main difference in this test data={"data": base64.replace("+", " "), "api_key": self.team.api_token,}, # main difference in this test
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(arguments["team_id"], self.team.pk) self.assertEqual(arguments["team_id"], self.team.pk)
self.assertEqual(arguments["distinct_id"], "eeeeeeegϥeeeee") self.assertEqual(arguments["distinct_id"], "eeeeeeegϥeeeee")
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_js_library_underscore_sent_at(self, patch_process_event_with_plugins): def test_js_library_underscore_sent_at(self, kafka_produce):
now = timezone.now() now = timezone.now()
tomorrow = now + timedelta(days=1, hours=2) tomorrow = now + timedelta(days=1, hours=2)
tomorrow_sent_at = now + timedelta(days=1, hours=2, minutes=10) tomorrow_sent_at = now + timedelta(days=1, hours=2, minutes=10)
@ -629,19 +633,19 @@ class TestCapture(BaseTest):
HTTP_ORIGIN="https://localhost", HTTP_ORIGIN="https://localhost",
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate
# right time sent as sent_at to process_event # right time sent as sent_at to process_event
self.assertEqual(arguments["sent_at"].tzinfo, timezone.utc) sent_at = datetime.fromisoformat(arguments["sent_at"])
self.assertEqual(sent_at.tzinfo, tz.utc)
timediff = arguments["sent_at"].timestamp() - tomorrow_sent_at.timestamp() timediff = sent_at.timestamp() - tomorrow_sent_at.timestamp()
self.assertLess(abs(timediff), 1) self.assertLess(abs(timediff), 1)
self.assertEqual(arguments["data"]["timestamp"], tomorrow.isoformat()) self.assertEqual(arguments["data"]["timestamp"], tomorrow.isoformat())
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_long_distinct_id(self, patch_process_event_with_plugins): def test_long_distinct_id(self, kafka_produce):
now = timezone.now() now = timezone.now()
tomorrow = now + timedelta(days=1, hours=2) tomorrow = now + timedelta(days=1, hours=2)
tomorrow_sent_at = now + timedelta(days=1, hours=2, minutes=10) tomorrow_sent_at = now + timedelta(days=1, hours=2, minutes=10)
@ -657,11 +661,11 @@ class TestCapture(BaseTest):
content_type="application/json", content_type="application/json",
HTTP_ORIGIN="https://localhost", HTTP_ORIGIN="https://localhost",
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(len(arguments["distinct_id"]), 200) self.assertEqual(len(arguments["distinct_id"]), 200)
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_sent_at_field(self, patch_process_event_with_plugins): def test_sent_at_field(self, kafka_produce):
now = timezone.now() now = timezone.now()
tomorrow = now + timedelta(days=1, hours=2) tomorrow = now + timedelta(days=1, hours=2)
tomorrow_sent_at = now + timedelta(days=1, hours=2, minutes=10) tomorrow_sent_at = now + timedelta(days=1, hours=2, minutes=10)
@ -677,11 +681,10 @@ class TestCapture(BaseTest):
}, },
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
arguments.pop("now") # can't compare fakedate sent_at = datetime.fromisoformat(arguments["sent_at"])
# right time sent as sent_at to process_event # right time sent as sent_at to process_event
timediff = arguments["sent_at"].timestamp() - tomorrow_sent_at.timestamp() timediff = sent_at.timestamp() - tomorrow_sent_at.timestamp()
self.assertLess(abs(timediff), 1) self.assertLess(abs(timediff), 1)
self.assertEqual(arguments["data"]["timestamp"], tomorrow.isoformat()) self.assertEqual(arguments["data"]["timestamp"], tomorrow.isoformat())
@ -757,8 +760,8 @@ class TestCapture(BaseTest):
self.assertEqual(statsd_incr_first_call.args[0], "invalid_event") self.assertEqual(statsd_incr_first_call.args[0], "invalid_event")
self.assertEqual(statsd_incr_first_call.kwargs, {"tags": {"error": "missing_event_name"}}) self.assertEqual(statsd_incr_first_call.kwargs, {"tags": {"error": "missing_event_name"}})
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_add_feature_flags_if_missing(self, patch_process_event_with_plugins) -> None: def test_add_feature_flags_if_missing(self, kafka_produce) -> None:
self.assertListEqual(self.team.event_properties_numerical, []) self.assertListEqual(self.team.event_properties_numerical, [])
FeatureFlag.objects.create(team=self.team, created_by=self.user, key="test-ff", rollout_percentage=100) FeatureFlag.objects.create(team=self.team, created_by=self.user, key="test-ff", rollout_percentage=100)
self.client.post( self.client.post(
@ -768,11 +771,11 @@ class TestCapture(BaseTest):
"api_key": self.team.api_token, "api_key": self.team.api_token,
}, },
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(arguments["data"]["properties"]["$active_feature_flags"], ["test-ff"]) self.assertEqual(arguments["data"]["properties"]["$active_feature_flags"], ["test-ff"])
@patch("posthog.api.capture.celery_app.send_task") @patch("ee.kafka_client.client._KafkaProducer.produce")
def test_add_feature_flags_with_overrides_if_missing(self, patch_process_event_with_plugins) -> None: def test_add_feature_flags_with_overrides_if_missing(self, kafka_produce) -> None:
feature_flag_instance = FeatureFlag.objects.create( feature_flag_instance = FeatureFlag.objects.create(
team=self.team, created_by=self.user, key="test-ff", rollout_percentage=0 team=self.team, created_by=self.user, key="test-ff", rollout_percentage=0
) )
@ -791,7 +794,7 @@ class TestCapture(BaseTest):
"api_key": self.team.api_token, "api_key": self.team.api_token,
}, },
) )
arguments = self._to_arguments(patch_process_event_with_plugins) arguments = self._to_arguments(kafka_produce)
self.assertEqual(arguments["data"]["properties"]["$feature/test-ff"], True) self.assertEqual(arguments["data"]["properties"]["$feature/test-ff"], True)
self.assertEqual(arguments["data"]["properties"]["$active_feature_flags"], ["test-ff"]) self.assertEqual(arguments["data"]["properties"]["$active_feature_flags"], ["test-ff"])
@ -847,27 +850,3 @@ class TestCapture(BaseTest):
"attr": None, "attr": None,
}, },
) )
# On CH deployments the events sent would be added to a Kafka dead letter queue
# On Postgres deployments we return a 503: Service Unavailable, and capture an
# exception in Sentry
@patch("statshog.defaults.django.statsd.incr")
@patch("sentry_sdk.capture_exception")
@patch("posthog.models.Team.objects.get_team_from_token", side_effect=mocked_get_team_from_token)
def test_fetch_team_failure(self, get_team_from_token, capture_exception, statsd_incr):
response = self.client.post(
"/track/",
data={
"data": json.dumps(
{"event": "some event", "properties": {"distinct_id": "valid id", "token": self.team.api_token,},},
),
"api_key": self.team.api_token,
},
)
# self.assertEqual(capture_exception.call_count, 1)
self.assertEqual(response.status_code, status.HTTP_503_SERVICE_UNAVAILABLE)
self.assertEqual(response.json()["code"], "fetch_team_fail")
self.assertEqual(get_team_from_token.call_args.args[0], "token123")
self.assertEqual(statsd_incr.call_args.args[0], "posthog_cloud_raw_endpoint_exception")

View File

@ -13,7 +13,7 @@ from posthog.test.base import APIBaseTest
class TestCohort(APIBaseTest): class TestCohort(APIBaseTest):
@patch("posthog.api.cohort.report_user_action") @patch("posthog.api.cohort.report_user_action")
@patch("posthog.tasks.calculate_cohort.calculate_cohort.delay") @patch("posthog.tasks.calculate_cohort.calculate_cohort_ch.delay")
def test_creating_update_and_calculating(self, patch_calculate_cohort, patch_capture): def test_creating_update_and_calculating(self, patch_calculate_cohort, patch_capture):
self.team.app_urls = ["http://somewebsite.com"] self.team.app_urls = ["http://somewebsite.com"]
self.team.save() self.team.save()
@ -141,7 +141,7 @@ User ID,
self.assertEqual(Cohort.objects.get(pk=response.json()["id"]).name, "test2") self.assertEqual(Cohort.objects.get(pk=response.json()["id"]).name, "test2")
@patch("posthog.tasks.calculate_cohort.calculate_cohort_from_list.delay") @patch("posthog.tasks.calculate_cohort.calculate_cohort_from_list.delay")
@patch("posthog.tasks.calculate_cohort.calculate_cohort.delay") @patch("posthog.tasks.calculate_cohort.calculate_cohort_ch.delay")
def test_static_cohort_to_dynamic_cohort(self, patch_calculate_cohort, patch_calculate_cohort_from_list): def test_static_cohort_to_dynamic_cohort(self, patch_calculate_cohort, patch_calculate_cohort_from_list):
self.team.app_urls = ["http://somewebsite.com"] self.team.app_urls = ["http://somewebsite.com"]
self.team.save() self.team.save()
@ -189,10 +189,8 @@ email@example.org,
) )
response = self.client.get(f"/api/projects/{self.team.id}/cohorts").json() response = self.client.get(f"/api/projects/{self.team.id}/cohorts").json()
self.assertEqual(len(response["results"]), 1) self.assertEqual(len(response["results"]), 1)
self.assertEqual(response["results"][0]["name"], "whatever") self.assertEqual(response["results"][0]["name"], "whatever")
self.assertEqual(response["results"][0]["count"], 1)
self.assertEqual(response["results"][0]["created_by"]["id"], self.user.id) self.assertEqual(response["results"][0]["created_by"]["id"], self.user.id)

View File

@ -92,7 +92,3 @@ def factory_test_element(create_event: Callable) -> Callable:
self.assertEqual(len(response), 1) self.assertEqual(len(response), 1)
return TestElement return TestElement
class TestElement(factory_test_element(Event.objects.create)): # type: ignore
pass

View File

@ -372,17 +372,15 @@ def factory_test_event_api(event_factory, person_factory, _):
) )
page2 = self.client.get(response["next"]).json() page2 = self.client.get(response["next"]).json()
from posthog.utils import is_clickhouse_enabled
if is_clickhouse_enabled(): from ee.clickhouse.client import sync_execute
from ee.clickhouse.client import sync_execute
self.assertEqual( self.assertEqual(
sync_execute( sync_execute("select count(*) from events where team_id = %(team_id)s", {"team_id": self.team.pk})[
"select count(*) from events where team_id = %(team_id)s", {"team_id": self.team.pk} 0
)[0][0], ][0],
250, 250,
) )
self.assertEqual(len(page2["results"]), 100) self.assertEqual(len(page2["results"]), 100)
self.assertEqual( self.assertEqual(
@ -428,17 +426,15 @@ def factory_test_event_api(event_factory, person_factory, _):
self.assertIn(f"after={after}", unquote(response["next"])) self.assertIn(f"after={after}", unquote(response["next"]))
page2 = self.client.get(response["next"]).json() page2 = self.client.get(response["next"]).json()
from posthog.utils import is_clickhouse_enabled
if is_clickhouse_enabled(): from ee.clickhouse.client import sync_execute
from ee.clickhouse.client import sync_execute
self.assertEqual( self.assertEqual(
sync_execute( sync_execute("select count(*) from events where team_id = %(team_id)s", {"team_id": self.team.pk})[
"select count(*) from events where team_id = %(team_id)s", {"team_id": self.team.pk} 0
)[0][0], ][0],
25, 25,
) )
self.assertEqual(len(page2["results"]), 10) self.assertEqual(len(page2["results"]), 10)
self.assertIn(f"before=", unquote(page2["next"])) self.assertIn(f"before=", unquote(page2["next"]))
@ -647,16 +643,3 @@ def factory_test_event_api(event_factory, person_factory, _):
self.assertEqual(response_invalid_token.status_code, 401) self.assertEqual(response_invalid_token.status_code, 401)
return TestEvents return TestEvents
def _create_action(**kwargs):
team = kwargs.pop("team")
name = kwargs.pop("name")
action = Action.objects.create(team=team, name=name)
ActionStep.objects.create(action=action, event=name)
action.calculate_events()
return action
class TestEvent(factory_test_event_api(Event.objects.create, Person.objects.create, _create_action)): # type: ignore
pass

View File

@ -20,7 +20,6 @@ from posthog.models import (
from posthog.models.organization import OrganizationMembership from posthog.models.organization import OrganizationMembership
from posthog.tasks.update_cache import update_dashboard_item_cache from posthog.tasks.update_cache import update_dashboard_item_cache
from posthog.test.base import APIBaseTest, QueryMatchingTest, snapshot_postgres_queries from posthog.test.base import APIBaseTest, QueryMatchingTest, snapshot_postgres_queries
from posthog.utils import is_clickhouse_enabled
def insight_test_factory(event_factory, person_factory): def insight_test_factory(event_factory, person_factory):
@ -501,14 +500,11 @@ def insight_test_factory(event_factory, person_factory):
).json() ).json()
# clickhouse funnels don't have a loading system # clickhouse funnels don't have a loading system
if is_clickhouse_enabled(): self.assertEqual(len(response["result"]), 2)
self.assertEqual(len(response["result"]), 2) self.assertEqual(response["result"][0]["name"], "user signed up")
self.assertEqual(response["result"][0]["name"], "user signed up") self.assertEqual(response["result"][0]["count"], 1)
self.assertEqual(response["result"][0]["count"], 1) self.assertEqual(response["result"][1]["name"], "user did things")
self.assertEqual(response["result"][1]["name"], "user did things") self.assertEqual(response["result"][1]["count"], 1)
self.assertEqual(response["result"][1]["count"], 1)
else:
self.assertEqual(response["result"]["loading"], True)
# Tests backwards-compatibility when we changed GET to POST | GET # Tests backwards-compatibility when we changed GET to POST | GET
def test_insight_funnels_basic_get(self): def test_insight_funnels_basic_get(self):
@ -519,12 +515,9 @@ def insight_test_factory(event_factory, person_factory):
).json() ).json()
# clickhouse funnels don't have a loading system # clickhouse funnels don't have a loading system
if is_clickhouse_enabled(): self.assertEqual(len(response["result"]), 2)
self.assertEqual(len(response["result"]), 2) self.assertEqual(response["result"][0]["name"], "user signed up")
self.assertEqual(response["result"][0]["name"], "user signed up") self.assertEqual(response["result"][1]["name"], "user did things")
self.assertEqual(response["result"][1]["name"], "user did things")
else:
self.assertEqual(response["result"]["loading"], True)
def test_insight_retention_basic(self): def test_insight_retention_basic(self):
person_factory(team=self.team, distinct_ids=["person1"], properties={"email": "person1@test.com"}) person_factory(team=self.team, distinct_ids=["person1"], properties={"email": "person1@test.com"})
@ -580,7 +573,3 @@ def insight_test_factory(event_factory, person_factory):
self.assertEqual(response_invalid_token.status_code, 401) self.assertEqual(response_invalid_token.status_code, 401)
return TestInsight return TestInsight
class TestInsight(insight_test_factory(Event.objects.create, Person.objects.create)): # type: ignore
pass

View File

@ -319,9 +319,3 @@ def factory_test_person(event_factory, person_factory, get_events):
self.assertDictContainsSubset({"id": cohort3.id, "count": 1, "name": cohort3.name}, response["results"][1]) self.assertDictContainsSubset({"id": cohort3.id, "count": 1, "name": cohort3.name}, response["results"][1])
return TestPerson return TestPerson
class TestPerson(
factory_test_person(Event.objects.create, Person.objects.create, Event.objects.filter) # type: ignore
):
pass

View File

@ -24,7 +24,7 @@ class TestPreflight(APIBaseTest):
For security purposes, the information contained in an unauthenticated preflight request is minimal. For security purposes, the information contained in an unauthenticated preflight request is minimal.
""" """
self.client.logout() self.client.logout()
with self.settings(PRIMARY_DB=AnalyticsDBMS.POSTGRES, MULTI_TENANCY=False): with self.settings(PRIMARY_DB=AnalyticsDBMS.CLICKHOUSE, MULTI_TENANCY=False):
response = self.client.get("/_preflight/") response = self.client.get("/_preflight/")
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
@ -39,7 +39,7 @@ class TestPreflight(APIBaseTest):
"initiated": True, "initiated": True,
"cloud": False, "cloud": False,
"demo": False, "demo": False,
"realm": "hosted", "realm": "hosted-clickhouse",
"available_social_auth_providers": { "available_social_auth_providers": {
"google-oauth2": False, "google-oauth2": False,
"github": False, "github": False,
@ -53,7 +53,7 @@ class TestPreflight(APIBaseTest):
def test_preflight_request(self): def test_preflight_request(self):
with self.settings( with self.settings(
PRIMARY_DB=AnalyticsDBMS.POSTGRES, PRIMARY_DB=AnalyticsDBMS.CLICKHOUSE,
MULTI_TENANCY=False, MULTI_TENANCY=False,
INSTANCE_PREFERENCES=self.instance_preferences(debug_queries=True), INSTANCE_PREFERENCES=self.instance_preferences(debug_queries=True),
): ):
@ -73,10 +73,8 @@ class TestPreflight(APIBaseTest):
"initiated": True, "initiated": True,
"cloud": False, "cloud": False,
"demo": False, "demo": False,
"realm": "hosted", "realm": "hosted-clickhouse",
"ee_available": settings.EE_AVAILABLE, "db_backend": "clickhouse",
"is_clickhouse_enabled": False,
"db_backend": "postgres",
"available_social_auth_providers": { "available_social_auth_providers": {
"google-oauth2": False, "google-oauth2": False,
"github": False, "github": False,
@ -148,8 +146,6 @@ class TestPreflight(APIBaseTest):
"cloud": True, "cloud": True,
"demo": False, "demo": False,
"realm": "cloud", "realm": "cloud",
"ee_available": True,
"is_clickhouse_enabled": True,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_social_auth_providers": { "available_social_auth_providers": {
"google-oauth2": False, "google-oauth2": False,
@ -197,8 +193,6 @@ class TestPreflight(APIBaseTest):
"cloud": True, "cloud": True,
"demo": False, "demo": False,
"realm": "cloud", "realm": "cloud",
"ee_available": True,
"is_clickhouse_enabled": True,
"db_backend": "clickhouse", "db_backend": "clickhouse",
"available_social_auth_providers": { "available_social_auth_providers": {
"google-oauth2": True, "google-oauth2": True,

View File

@ -14,8 +14,6 @@ from posthog.api.test.test_event_definition import (
create_team, create_team,
create_user, create_user,
) )
from posthog.constants import TREND_FILTER_TYPE_EVENTS
from posthog.utils import is_clickhouse_enabled
def identify( def identify(
@ -33,16 +31,10 @@ def identify(
""" """
properties = properties or {} properties = properties or {}
if is_clickhouse_enabled(): from ee.clickhouse.models.person import Person, PersonDistinctId
from ee.clickhouse.models.person import Person, PersonDistinctId
person = Person.objects.create(team_id=team_id, properties=properties) person = Person.objects.create(team_id=team_id, properties=properties)
PersonDistinctId.objects.create(distinct_id=distinct_id, team_id=team_id, person_id=person.id) PersonDistinctId.objects.create(distinct_id=distinct_id, team_id=team_id, person_id=person.id)
else:
from posthog.models.person import Person, PersonDistinctId
person = Person.objects.create(team_id=team_id, properties=properties)
PersonDistinctId.objects.create(distinct_id=distinct_id, team_id=team_id, person_id=person.id)
capture_event( capture_event(
event=EventData( event=EventData(
@ -89,95 +81,3 @@ def get_retention(
"properties": json.dumps(properties or []), "properties": json.dumps(properties or []),
}, },
) )
@pytest.mark.django_db
@freeze_time("2021-08-03")
def test_insight_retention_missing_persons_gh_5443(client: Client):
"""
This is a regression test for GH-5443.
The scenario here is that, an api request is being made for person retention, specifically for:
1. a "Week" period is being requested
2. events just over a week from the first event for a user
"""
organization = create_organization(name="test org")
team = create_team(organization=organization)
user = create_user("user", "pass", organization)
identify(distinct_id="abc", team_id=team.id)
#  This event will be the first event for the Person wrt the retention
#  period
capture_event(
event=EventData(
event="event_name", team_id=team.id, distinct_id="abc", timestamp=datetime(2021, 3, 29), properties={},
)
)
# Create an event for just over a week from the initial identify event
capture_event(
event=EventData(
event="event_name", team_id=team.id, distinct_id="abc", timestamp=datetime(2021, 4, 5), properties={},
)
)
client.force_login(user)
# These params are taken from
# https://sentry.io/organizations/posthog/issues/2516393859/events/df790b8837a54051a140aa1fee51adfc/?project=1899813
response = get_retention(
client=client,
events=[
{
"id": "$pageview",
"math": None,
"name": "$pageview",
"type": "events",
"order": 0,
"properties": [],
"math_property": None,
}
],
date_from="-90d",
date_to="2021-03-31T18:22:50.579Z",
display="ActionsTable",
selected_interval=10,
total_intervals=11,
insight="RETENTION",
period="Week",
retention_type="retention_first_time",
target_entity={"id": "event_name", "name": "event_name", "type": "events", "order": 0},
returning_entity={
"id": "event_name",
"math": None,
"name": "event_name",
"type": "events",
"order": None,
"properties": [],
"math_property": None,
},
)
assert response.status_code == 200, response.content
data = response.json()
# NOTE: prior to the fix for GH-5443, this test would fail by returning an
# empty list. To "fix" I have make the generation of "appearances" more
# forgiving of getting too much data from the clickhouse query.
assert data["result"] == [
{
"appearances": [1],
"person": {
"created_at": "2021-08-03T00:00:00Z",
"distinct_ids": ["abc"],
"id": ANY,
"name": "abc",
"properties": {},
"uuid": ANY,
},
},
]

View File

@ -365,7 +365,3 @@ def factory_test_session_recordings_api(session_recording_event_factory):
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
return TestSessionRecordings return TestSessionRecordings
class TestSessionRecordingsAPI(factory_test_session_recordings_api(SessionRecordingEvent.objects.create)): # type: ignore
pass

View File

@ -32,7 +32,6 @@ class TestSignupAPI(APIBaseTest):
pass pass
@pytest.mark.skip_on_multitenancy @pytest.mark.skip_on_multitenancy
@patch("posthog.api.organization.settings.EE_AVAILABLE", False)
@patch("posthoganalytics.capture") @patch("posthoganalytics.capture")
def test_api_sign_up(self, mock_capture): def test_api_sign_up(self, mock_capture):
@ -563,7 +562,6 @@ class TestInviteSignup(APIBaseTest):
# Signup (using invite) # Signup (using invite)
@patch("posthoganalytics.capture") @patch("posthoganalytics.capture")
@patch("posthog.api.organization.settings.EE_AVAILABLE", True)
def test_api_invite_sign_up(self, mock_capture): def test_api_invite_sign_up(self, mock_capture):
invite: OrganizationInvite = OrganizationInvite.objects.create( invite: OrganizationInvite = OrganizationInvite.objects.create(
target_email="test+99@posthog.com", organization=self.organization, target_email="test+99@posthog.com", organization=self.organization,
@ -620,7 +618,6 @@ class TestInviteSignup(APIBaseTest):
self.assertTrue(user.check_password("test_password")) self.assertTrue(user.check_password("test_password"))
@pytest.mark.ee @pytest.mark.ee
@patch("posthog.api.organization.settings.EE_AVAILABLE", True)
def test_api_invite_sign_up_where_there_are_no_default_non_private_projects(self): def test_api_invite_sign_up_where_there_are_no_default_non_private_projects(self):
self.client.logout() self.client.logout()
invite: OrganizationInvite = OrganizationInvite.objects.create( invite: OrganizationInvite = OrganizationInvite.objects.create(
@ -645,7 +642,6 @@ class TestInviteSignup(APIBaseTest):
) # User is not assigned to a project, as there are no non-private projects ) # User is not assigned to a project, as there are no non-private projects
self.assertEqual(user.team, None) self.assertEqual(user.team, None)
@patch("posthog.api.organization.settings.EE_AVAILABLE", True)
def test_api_invite_sign_up_where_default_project_is_private(self): def test_api_invite_sign_up_where_default_project_is_private(self):
self.client.logout() self.client.logout()
self.team.access_control = True self.team.access_control = True
@ -664,7 +660,6 @@ class TestInviteSignup(APIBaseTest):
self.assertEqual(user.current_team, team) self.assertEqual(user.current_team, team)
self.assertEqual(user.team, team) self.assertEqual(user.team, team)
@patch("posthog.api.organization.settings.EE_AVAILABLE", False)
def test_api_invite_sign_up_member_joined_email_is_not_sent_for_initial_member(self): def test_api_invite_sign_up_member_joined_email_is_not_sent_for_initial_member(self):
invite: OrganizationInvite = OrganizationInvite.objects.create( invite: OrganizationInvite = OrganizationInvite.objects.create(
target_email="test+100@posthog.com", organization=self.organization, target_email="test+100@posthog.com", organization=self.organization,
@ -679,7 +674,6 @@ class TestInviteSignup(APIBaseTest):
self.assertEqual(len(mail.outbox), 0) self.assertEqual(len(mail.outbox), 0)
@patch("posthog.api.organization.settings.EE_AVAILABLE", False)
def test_api_invite_sign_up_member_joined_email_is_sent_for_next_members(self): def test_api_invite_sign_up_member_joined_email_is_sent_for_next_members(self):
initial_user = User.objects.create_and_join(self.organization, "test+420@posthog.com", None) initial_user = User.objects.create_and_join(self.organization, "test+420@posthog.com", None)
@ -697,7 +691,6 @@ class TestInviteSignup(APIBaseTest):
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertListEqual(mail.outbox[0].to, [initial_user.email]) self.assertListEqual(mail.outbox[0].to, [initial_user.email])
@patch("posthog.api.organization.settings.EE_AVAILABLE", False)
def test_api_invite_sign_up_member_joined_email_is_not_sent_if_disabled(self): def test_api_invite_sign_up_member_joined_email_is_not_sent_if_disabled(self):
self.organization.is_member_join_email_enabled = False self.organization.is_member_join_email_enabled = False
self.organization.save() self.organization.save()
@ -719,7 +712,6 @@ class TestInviteSignup(APIBaseTest):
@patch("posthoganalytics.identify") @patch("posthoganalytics.identify")
@patch("posthoganalytics.capture") @patch("posthoganalytics.capture")
@patch("posthog.api.organization.settings.EE_AVAILABLE", False)
def test_existing_user_can_sign_up_to_a_new_organization(self, mock_capture, mock_identify): def test_existing_user_can_sign_up_to_a_new_organization(self, mock_capture, mock_identify):
user = self._create_user("test+159@posthog.com", "test_password") user = self._create_user("test+159@posthog.com", "test_password")
new_org = Organization.objects.create(name="TestCo") new_org = Organization.objects.create(name="TestCo")

View File

@ -11,7 +11,6 @@ from posthog.api.test.test_trends import NormalizedTrendResult, get_time_series_
from posthog.constants import ENTITY_ID, ENTITY_TYPE from posthog.constants import ENTITY_ID, ENTITY_TYPE
from posthog.models import Action, ActionStep, Event, Person from posthog.models import Action, ActionStep, Event, Person
from posthog.models.team import Team from posthog.models.team import Team
from posthog.queries.abstract_test.test_compare import AbstractCompareTest
from posthog.queries.stickiness import Stickiness from posthog.queries.stickiness import Stickiness
from posthog.test.base import APIBaseTest from posthog.test.base import APIBaseTest
from posthog.utils import encode_get_request_params from posthog.utils import encode_get_request_params
@ -44,7 +43,7 @@ def get_stickiness_people_ok(client: Client, team_id: int, request: Dict[str, An
# parameterize tests to reuse in EE # parameterize tests to reuse in EE
def stickiness_test_factory(stickiness, event_factory, person_factory, action_factory, get_earliest_timestamp): def stickiness_test_factory(stickiness, event_factory, person_factory, action_factory, get_earliest_timestamp):
class TestStickiness(APIBaseTest, AbstractCompareTest): class TestStickiness(APIBaseTest):
def _create_multiple_people(self, period=timedelta(days=1), event_properties=lambda index: {}): def _create_multiple_people(self, period=timedelta(days=1), event_properties=lambda index: {}):
base_time = datetime.fromisoformat("2020-01-01T12:00:00.000000") base_time = datetime.fromisoformat("2020-01-01T12:00:00.000000")
p1 = person_factory(team_id=self.team.id, distinct_ids=["person1"], properties={"name": "person1"}) p1 = person_factory(team_id=self.team.id, distinct_ids=["person1"], properties={"name": "person1"})
@ -463,17 +462,3 @@ def stickiness_test_factory(stickiness, event_factory, person_factory, action_fa
self.assertEqual(response[0]["data"][6], 0) self.assertEqual(response[0]["data"][6], 0)
return TestStickiness return TestStickiness
def _create_action(**kwargs):
team = kwargs.pop("team")
name = kwargs.pop("name")
event_name = kwargs.pop("event_name")
action = Action.objects.create(team=team, name=name)
ActionStep.objects.create(action=action, event=event_name)
action.calculate_events()
return action
class DjangoStickinessTest(stickiness_test_factory(Stickiness, Event.objects.create, Person.objects.create, _create_action, Event.objects.earliest_timestamp)): # type: ignore
pass

View File

@ -54,7 +54,7 @@ class TestUtils(BaseTest):
self.assertEqual(team, None) self.assertEqual(team, None)
self.assertEqual(db_error, "Exception('test exception')") self.assertEqual(db_error, "Exception('test exception')")
self.assertEqual(error_response.status_code, status.HTTP_503_SERVICE_UNAVAILABLE) # type: ignore self.assertEqual(error_response, None)
get_team_from_token_patcher.stop() get_team_from_token_patcher.stop()

View File

@ -25,7 +25,7 @@ from posthog.models.filters.filter import Filter
from posthog.models.filters.stickiness_filter import StickinessFilter from posthog.models.filters.stickiness_filter import StickinessFilter
from posthog.models.team import Team from posthog.models.team import Team
from posthog.models.user import User from posthog.models.user import User
from posthog.utils import cors_response, is_clickhouse_enabled, load_data_from_request from posthog.utils import cors_response, load_data_from_request
class PaginationMode(Enum): class PaginationMode(Enum):
@ -179,18 +179,6 @@ def get_team(request, data, token) -> Tuple[Optional[Team], Optional[str], Optio
db_error = getattr(e, "message", repr(e)) db_error = getattr(e, "message", repr(e))
if not is_clickhouse_enabled():
error_response = cors_response(
request,
generate_exception_response(
"capture",
"Unable to fetch team from database.",
type="server_error",
code="fetch_team_fail",
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
),
)
return None, db_error, error_response return None, db_error, error_response
if team is None: if team is None:

View File

@ -8,7 +8,6 @@ from semantic_version.base import Version
from posthog.async_migrations.definition import AsyncMigrationDefinition from posthog.async_migrations.definition import AsyncMigrationDefinition
from posthog.models.async_migration import AsyncMigration, get_all_completed_async_migrations from posthog.models.async_migration import AsyncMigration, get_all_completed_async_migrations
from posthog.settings import TEST from posthog.settings import TEST
from posthog.utils import is_clickhouse_enabled
from posthog.version import VERSION from posthog.version import VERSION
ALL_ASYNC_MIGRATIONS: Dict[str, AsyncMigrationDefinition] = {} ALL_ASYNC_MIGRATIONS: Dict[str, AsyncMigrationDefinition] = {}
@ -24,11 +23,10 @@ POSTHOG_VERSION = Version(VERSION)
ASYNC_MIGRATIONS_MODULE_PATH = "posthog.async_migrations.migrations" ASYNC_MIGRATIONS_MODULE_PATH = "posthog.async_migrations.migrations"
ASYNC_MIGRATIONS_EXAMPLE_MODULE_PATH = "posthog.async_migrations.examples" ASYNC_MIGRATIONS_EXAMPLE_MODULE_PATH = "posthog.async_migrations.examples"
if is_clickhouse_enabled(): all_migrations = import_submodules(ASYNC_MIGRATIONS_MODULE_PATH)
all_migrations = import_submodules(ASYNC_MIGRATIONS_MODULE_PATH)
for name, module in all_migrations.items(): for name, module in all_migrations.items():
ALL_ASYNC_MIGRATIONS[name] = module.Migration() ALL_ASYNC_MIGRATIONS[name] = module.Migration()
def setup_async_migrations(ignore_posthog_version: bool = False): def setup_async_migrations(ignore_posthog_version: bool = False):

View File

@ -12,7 +12,6 @@ from django.utils import timezone
from sentry_sdk.api import capture_exception from sentry_sdk.api import capture_exception
from posthog.redis import get_client from posthog.redis import get_client
from posthog.utils import is_clickhouse_enabled
# set the default Django settings module for the 'celery' program. # set the default Django settings module for the 'celery' program.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "posthog.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "posthog.settings")
@ -87,42 +86,39 @@ def setup_periodic_tasks(sender: Celery, **kwargs):
name="send event usage report", name="send event usage report",
) )
if is_clickhouse_enabled(): sender.add_periodic_task(120, clickhouse_lag.s(), name="clickhouse table lag")
sender.add_periodic_task(120, clickhouse_lag.s(), name="clickhouse table lag") sender.add_periodic_task(120, clickhouse_row_count.s(), name="clickhouse events table row count")
sender.add_periodic_task(120, clickhouse_row_count.s(), name="clickhouse events table row count") sender.add_periodic_task(120, clickhouse_part_count.s(), name="clickhouse table parts count")
sender.add_periodic_task(120, clickhouse_part_count.s(), name="clickhouse table parts count") sender.add_periodic_task(120, clickhouse_mutation_count.s(), name="clickhouse table mutations count")
sender.add_periodic_task(120, clickhouse_mutation_count.s(), name="clickhouse table mutations count")
sender.add_periodic_task(
crontab(hour=0, minute=randrange(0, 40)), clickhouse_send_license_usage.s()
) # every day at a random minute past midnight. Randomize to avoid overloading license.posthog.com
try:
from ee.settings import MATERIALIZE_COLUMNS_SCHEDULE_CRON
minute, hour, day_of_month, month_of_year, day_of_week = MATERIALIZE_COLUMNS_SCHEDULE_CRON.strip().split(" ")
sender.add_periodic_task( sender.add_periodic_task(
crontab(hour=0, minute=randrange(0, 40)), clickhouse_send_license_usage.s() crontab(
) # every day at a random minute past midnight. Randomize to avoid overloading license.posthog.com minute=minute,
try: hour=hour,
from ee.settings import MATERIALIZE_COLUMNS_SCHEDULE_CRON day_of_month=day_of_month,
month_of_year=month_of_year,
day_of_week=day_of_week,
),
clickhouse_materialize_columns.s(),
name="clickhouse materialize columns",
)
minute, hour, day_of_month, month_of_year, day_of_week = MATERIALIZE_COLUMNS_SCHEDULE_CRON.strip().split( sender.add_periodic_task(
" " crontab(hour="*/4", minute=0),
) clickhouse_mark_all_materialized.s(),
name="clickhouse mark all columns as materialized",
sender.add_periodic_task( )
crontab( except Exception as err:
minute=minute, capture_exception(err)
hour=hour, print(f"Scheduling materialized column task failed: {err}")
day_of_month=day_of_month,
month_of_year=month_of_year,
day_of_week=day_of_week,
),
clickhouse_materialize_columns.s(),
name="clickhouse materialize columns",
)
sender.add_periodic_task(
crontab(hour="*/4", minute=0),
clickhouse_mark_all_materialized.s(),
name="clickhouse mark all columns as materialized",
)
except Exception as err:
capture_exception(err)
print(f"Scheduling materialized column task failed: {err}")
sender.add_periodic_task(120, calculate_cohort.s(), name="recalculate cohorts") sender.add_periodic_task(120, calculate_cohort.s(), name="recalculate cohorts")
@ -137,18 +133,16 @@ def setup_periodic_tasks(sender: Celery, **kwargs):
# Set up clickhouse query instrumentation # Set up clickhouse query instrumentation
@task_prerun.connect @task_prerun.connect
def set_up_instrumentation(task_id, task, **kwargs): def set_up_instrumentation(task_id, task, **kwargs):
if is_clickhouse_enabled() and settings.EE_AVAILABLE: from ee.clickhouse import client
from ee.clickhouse import client
client._request_information = {"kind": "celery", "id": task.name} client._request_information = {"kind": "celery", "id": task.name}
@task_postrun.connect @task_postrun.connect
def teardown_instrumentation(task_id, task, **kwargs): def teardown_instrumentation(task_id, task, **kwargs):
if is_clickhouse_enabled() and settings.EE_AVAILABLE: from ee.clickhouse import client
from ee.clickhouse import client
client._request_information = None client._request_information = None
@app.task(ignore_result=True) @app.task(ignore_result=True)
@ -172,90 +166,71 @@ if settings.CLICKHOUSE_REPLICATION:
@app.task(ignore_result=True) @app.task(ignore_result=True)
def clickhouse_lag(): def clickhouse_lag():
if is_clickhouse_enabled() and settings.EE_AVAILABLE: from ee.clickhouse.client import sync_execute
from ee.clickhouse.client import sync_execute from posthog.internal_metrics import gauge
from posthog.internal_metrics import gauge
for table in CLICKHOUSE_TABLES: for table in CLICKHOUSE_TABLES:
try: try:
QUERY = ( QUERY = """select max(_timestamp) observed_ts, now() now_ts, now() - max(_timestamp) as lag from {table};"""
"""select max(_timestamp) observed_ts, now() now_ts, now() - max(_timestamp) as lag from {table};""" query = QUERY.format(table=table)
) lag = sync_execute(query)[0][2]
query = QUERY.format(table=table) gauge("posthog_celery_clickhouse__table_lag_seconds", lag, tags={"table": table})
lag = sync_execute(query)[0][2] except:
gauge("posthog_celery_clickhouse__table_lag_seconds", lag, tags={"table": table}) pass
except:
pass
else:
pass
@app.task(ignore_result=True) @app.task(ignore_result=True)
def clickhouse_row_count(): def clickhouse_row_count():
if is_clickhouse_enabled() and settings.EE_AVAILABLE: from ee.clickhouse.client import sync_execute
from ee.clickhouse.client import sync_execute from posthog.internal_metrics import gauge
from posthog.internal_metrics import gauge
for table in CLICKHOUSE_TABLES: for table in CLICKHOUSE_TABLES:
try: try:
QUERY = """select count(1) freq from {table};""" QUERY = """select count(1) freq from {table};"""
query = QUERY.format(table=table) query = QUERY.format(table=table)
rows = sync_execute(query)[0][0] rows = sync_execute(query)[0][0]
gauge(f"posthog_celery_clickhouse_table_row_count", rows, tags={"table": table}) gauge(f"posthog_celery_clickhouse_table_row_count", rows, tags={"table": table})
except: except:
pass pass
else:
pass
@app.task(ignore_result=True) @app.task(ignore_result=True)
def clickhouse_part_count(): def clickhouse_part_count():
if is_clickhouse_enabled() and settings.EE_AVAILABLE: from ee.clickhouse.client import sync_execute
from ee.clickhouse.client import sync_execute from posthog.internal_metrics import gauge
from posthog.internal_metrics import gauge
QUERY = """ QUERY = """
select table, count(1) freq select table, count(1) freq
from system.parts from system.parts
group by table group by table
order by freq desc; order by freq desc;
""" """
rows = sync_execute(QUERY) rows = sync_execute(QUERY)
for (table, parts) in rows: for (table, parts) in rows:
gauge(f"posthog_celery_clickhouse_table_parts_count", parts, tags={"table": table}) gauge(f"posthog_celery_clickhouse_table_parts_count", parts, tags={"table": table})
else:
pass
@app.task(ignore_result=True) @app.task(ignore_result=True)
def clickhouse_mutation_count(): def clickhouse_mutation_count():
if is_clickhouse_enabled() and settings.EE_AVAILABLE: from ee.clickhouse.client import sync_execute
from ee.clickhouse.client import sync_execute from posthog.internal_metrics import gauge
from posthog.internal_metrics import gauge
QUERY = """ QUERY = """
SELECT SELECT
table, table,
count(1) AS freq count(1) AS freq
FROM system.mutations FROM system.mutations
WHERE is_done = 0 WHERE is_done = 0
GROUP BY table GROUP BY table
ORDER BY freq DESC ORDER BY freq DESC
""" """
rows = sync_execute(QUERY) rows = sync_execute(QUERY)
for (table, muts) in rows: for (table, muts) in rows:
gauge(f"posthog_celery_clickhouse_table_mutations_count", muts, tags={"table": table}) gauge(f"posthog_celery_clickhouse_table_mutations_count", muts, tags={"table": table})
else:
pass
def recompute_materialized_columns_enabled() -> bool: def recompute_materialized_columns_enabled() -> bool:
if ( if getattr(config, "MATERIALIZED_COLUMNS_ENABLED") and getattr(config, "COMPUTE_MATERIALIZED_COLUMNS_ENABLED"):
is_clickhouse_enabled()
and settings.EE_AVAILABLE
and getattr(config, "MATERIALIZED_COLUMNS_ENABLED")
and getattr(config, "COMPUTE_MATERIALIZED_COLUMNS_ENABLED")
):
return True return True
return False return False
@ -278,7 +253,7 @@ def clickhouse_mark_all_materialized():
@app.task(ignore_result=True) @app.task(ignore_result=True)
def clickhouse_send_license_usage(): def clickhouse_send_license_usage():
if is_clickhouse_enabled() and not settings.MULTI_TENANCY: if not settings.MULTI_TENANCY:
from ee.tasks.send_license_usage import send_license_usage from ee.tasks.send_license_usage import send_license_usage
send_license_usage() send_license_usage()
@ -286,14 +261,9 @@ def clickhouse_send_license_usage():
@app.task(ignore_result=True) @app.task(ignore_result=True)
def send_org_usage_report(): def send_org_usage_report():
if is_clickhouse_enabled(): from ee.tasks.org_usage_report import send_all_org_usage_reports as send_reports_clickhouse
from ee.tasks.org_usage_report import send_all_org_usage_reports as send_reports_clickhouse
send_reports_clickhouse() send_reports_clickhouse()
else:
from posthog.tasks.org_usage_report import send_all_org_usage_reports as send_reports_postgres
send_reports_postgres()
@app.task(ignore_result=True) @app.task(ignore_result=True)
@ -332,13 +302,6 @@ def status_report():
status_report() status_report()
@app.task(ignore_result=True)
def calculate_event_action_mappings():
from posthog.tasks.calculate_action import calculate_actions_from_last_calculation
calculate_actions_from_last_calculation()
@app.task(ignore_result=True) @app.task(ignore_result=True)
def calculate_cohort(): def calculate_cohort():
from posthog.tasks.calculate_cohort import calculate_cohorts from posthog.tasks.calculate_cohort import calculate_cohorts

View File

@ -7,7 +7,7 @@ from posthog.demo.revenue_data_generator import RevenueDataGenerator
from posthog.demo.web_data_generator import WebDataGenerator from posthog.demo.web_data_generator import WebDataGenerator
from posthog.models import Organization, Team, User from posthog.models import Organization, Team, User
from posthog.models.event_definition import EventDefinition from posthog.models.event_definition import EventDefinition
from posthog.utils import is_clickhouse_enabled, render_template from posthog.utils import render_template
ORGANIZATION_NAME = "Hogflix" ORGANIZATION_NAME = "Hogflix"
TEAM_NAME = "Hogflix Demo App" TEAM_NAME = "Hogflix Demo App"
@ -29,12 +29,11 @@ def demo(request: Request):
user.save() user.save()
EventDefinition.objects.get_or_create(team=team, name="$pageview") EventDefinition.objects.get_or_create(team=team, name="$pageview")
if is_clickhouse_enabled(): # :TRICKY: Lazily backfill missing event data. from ee.clickhouse.models.event import get_events_by_team
from ee.clickhouse.models.event import get_events_by_team
result = get_events_by_team(team_id=team.pk) result = get_events_by_team(team_id=team.pk)
if not result: if not result:
create_demo_data(team, dashboards=False) create_demo_data(team, dashboards=False)
return render_template("demo.html", request=request, context={"api_token": team.api_token}) return render_template("demo.html", request=request, context={"api_token": team.api_token})

View File

@ -3,7 +3,6 @@ from typing import Dict, List
from posthog.models import Action, Event, Person, PersonDistinctId, Team from posthog.models import Action, Event, Person, PersonDistinctId, Team
from posthog.models.session_recording_event import SessionRecordingEvent from posthog.models.session_recording_event import SessionRecordingEvent
from posthog.models.utils import UUIDT from posthog.models.utils import UUIDT
from posthog.utils import is_clickhouse_enabled
class DataGenerator: class DataGenerator:
@ -39,18 +38,17 @@ class DataGenerator:
for person, distinct_id in zip(self.people, self.distinct_ids) for person, distinct_id in zip(self.people, self.distinct_ids)
] ]
PersonDistinctId.objects.bulk_create(pids) PersonDistinctId.objects.bulk_create(pids)
if is_clickhouse_enabled(): from ee.clickhouse.models.person import create_person, create_person_distinct_id
from ee.clickhouse.models.person import create_person, create_person_distinct_id
for person in self.people: for person in self.people:
create_person( create_person(
uuid=str(person.uuid), uuid=str(person.uuid),
team_id=person.team.pk, team_id=person.team.pk,
properties=person.properties, properties=person.properties,
is_identified=person.is_identified, is_identified=person.is_identified,
) )
for pid in pids: for pid in pids:
create_person_distinct_id(pid.team.pk, pid.distinct_id, str(pid.person.uuid)) # use dummy number for id create_person_distinct_id(pid.team.pk, pid.distinct_id, str(pid.person.uuid)) # use dummy number for id
def make_person(self, index): def make_person(self, index):
return Person(team=self.team, properties={"is_demo": True}) return Person(team=self.team, properties={"is_demo": True})
@ -68,16 +66,10 @@ class DataGenerator:
pass pass
def bulk_import_events(self): def bulk_import_events(self):
if is_clickhouse_enabled(): from ee.clickhouse.demo import bulk_create_events, bulk_create_session_recording_events
from ee.clickhouse.demo import bulk_create_events, bulk_create_session_recording_events
bulk_create_events(self.events, team=self.team) bulk_create_events(self.events, team=self.team)
bulk_create_session_recording_events(self.snapshots, team_id=self.team.pk) bulk_create_session_recording_events(self.snapshots, team_id=self.team.pk)
else:
Event.objects.bulk_create([Event(**kw, team=self.team) for kw in self.events])
SessionRecordingEvent.objects.bulk_create(
[SessionRecordingEvent(**kw, team=self.team) for kw in self.snapshots]
)
def add_if_not_contained(self, array, value): def add_if_not_contained(self, array, value):
if value not in array: if value not in array:

View File

@ -11,7 +11,6 @@ from django.utils import timezone
from sentry_sdk import capture_exception from sentry_sdk import capture_exception
from posthog.models.utils import sane_repr from posthog.models.utils import sane_repr
from posthog.utils import is_clickhouse_enabled
from .action import Action from .action import Action
from .event import Event from .event import Event
@ -103,16 +102,11 @@ class Cohort(models.Model):
"deleted": self.deleted, "deleted": self.deleted,
} }
def calculate_people(self, use_clickhouse=is_clickhouse_enabled()): def calculate_people(self):
if self.is_static: if self.is_static:
return return
try: try:
if not use_clickhouse: persons_query = self._clickhouse_persons_query()
self.is_calculating = True
self.save()
persons_query = self._postgres_persons_query()
else:
persons_query = self._clickhouse_persons_query()
try: try:
sql, params = persons_query.distinct("pk").only("pk").query.sql_with_params() sql, params = persons_query.distinct("pk").only("pk").query.sql_with_params()
@ -131,34 +125,24 @@ class Cohort(models.Model):
cursor = connection.cursor() cursor = connection.cursor()
with transaction.atomic(): with transaction.atomic():
cursor.execute(query, params) cursor.execute(query, params)
if not use_clickhouse:
self.last_calculation = timezone.now()
self.errors_calculating = 0
except Exception as err: except Exception as err:
if not use_clickhouse:
self.errors_calculating = F("errors_calculating") + 1
raise err raise err
finally:
if not use_clickhouse:
self.is_calculating = False
self.save()
def calculate_people_ch(self): def calculate_people_ch(self):
if is_clickhouse_enabled(): from ee.clickhouse.models.cohort import recalculate_cohortpeople
from ee.clickhouse.models.cohort import recalculate_cohortpeople from posthog.tasks.calculate_cohort import calculate_cohort
from posthog.tasks.calculate_cohort import calculate_cohort
try: try:
recalculate_cohortpeople(self) recalculate_cohortpeople(self)
calculate_cohort(self.id) calculate_cohort(self.id)
self.last_calculation = timezone.now() self.last_calculation = timezone.now()
self.errors_calculating = 0 self.errors_calculating = 0
except Exception as e: except Exception as e:
self.errors_calculating = F("errors_calculating") + 1 self.errors_calculating = F("errors_calculating") + 1
raise e raise e
finally: finally:
self.is_calculating = False self.is_calculating = False
self.save() self.save()
def insert_users_by_list(self, items: List[str]) -> None: def insert_users_by_list(self, items: List[str]) -> None:
""" """
@ -166,9 +150,8 @@ class Cohort(models.Model):
Important! Does not insert into clickhouse Important! Does not insert into clickhouse
""" """
batchsize = 1000 batchsize = 1000
use_clickhouse = is_clickhouse_enabled() from ee.clickhouse.models.cohort import insert_static_cohort
if use_clickhouse:
from ee.clickhouse.models.cohort import insert_static_cohort
try: try:
cursor = connection.cursor() cursor = connection.cursor()
for i in range(0, len(items), batchsize): for i in range(0, len(items), batchsize):
@ -178,8 +161,7 @@ class Cohort(models.Model):
.filter(Q(persondistinctid__team_id=self.team_id, persondistinctid__distinct_id__in=batch)) .filter(Q(persondistinctid__team_id=self.team_id, persondistinctid__distinct_id__in=batch))
.exclude(cohort__id=self.id) .exclude(cohort__id=self.id)
) )
if use_clickhouse: insert_static_cohort([p for p in persons_query.values_list("uuid", flat=True)], self.pk, self.team)
insert_static_cohort([p for p in persons_query.values_list("uuid", flat=True)], self.pk, self.team)
sql, params = persons_query.distinct("pk").only("pk").query.sql_with_params() sql, params = persons_query.distinct("pk").only("pk").query.sql_with_params()
query = UPDATE_QUERY.format( query = UPDATE_QUERY.format(
cohort_id=self.pk, cohort_id=self.pk,

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