Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
EDsCODE committed Sep 4, 2024
2 parents fb942c4 + 04ef403 commit 8544c14
Show file tree
Hide file tree
Showing 329 changed files with 5,789 additions and 3,115 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
- Analyze data with ready-made visualizations, or do it yourself with SQL
- Only capture properties on the people you want to track, save money when you don't
- Gather insights by capturing session replays, console logs, and network monitoring
- Improve your product with A/B testing that automatically analyzes performance
- Improve your product with Experiments that automatically analyze performance
- Safely roll out features to select users or cohorts with feature flags
- Send out fully customizable surveys to specific cohorts of users
- Connect to external services and manage data flows with PostHog CDP
Expand Down Expand Up @@ -81,7 +81,7 @@ PostHog brings all the tools and data you need to build better products.
- **Session replays:** [Watch videos](https://posthog.com/docs/features/session-recording) of your users' behavior, with fine-grained filters and privacy controls, as well as network monitoring and captured console logs
- **Heatmaps:** See where users click and get a visual representation of their behaviour with the [PostHog Toolbar](https://posthog.com/docs/features/toolbar)
- **Feature flags:** Test and manage the rollout of [new features](https://posthog.com/docs/feature-flags/installation) to specific users and groups, or deploy flags as kill-switches
- **A/B and multivariate experimentation:** run simple or complex changes as [experiments](https://posthog.com/manual/experimentation) and get automatic significance calculations
- **Experiments:** run simple or complex changes as [experiments](https://posthog.com/manual/experimentation) and get automatic significance calculations
- **Correlation analysis:** Discover what events and properties [correlate](https://posthog.com/manual/correlation) with success and failure
- **Surveys:** Collect qualitative feedback from your users using fully customizable [surveys](https://posthog.com/docs/surveys/installation)

Expand Down
7 changes: 7 additions & 0 deletions bin/upgrade-hobby
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ else
exit
fi

if [ "$REGISTRY_URL" == "" ]
then
export REGISTRY_URL="posthog/posthog"
fi

export POSTHOG_APP_TAG="${POSTHOG_APP_TAG:-latest}"

echo "Checking for named postgres and clickhouse volumes to avoid data loss when upgrading from < 1.39"
if docker volume ls | grep -Pzoq 'clickhouse-data\n(.|\n)*postgres-data\n'
then
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/experiments.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('Experiments', () => {

it('create experiment', () => {
cy.visit('/experiments')
cy.get('[data-attr=top-bar-name]').should('contain', 'A/B testing')
cy.get('[data-attr=top-bar-name]').should('contain', 'Experiments')

// Name, flag key, description
cy.get('[data-attr=create-experiment]').first().click()
Expand Down
12 changes: 12 additions & 0 deletions docker-compose.hobby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ services:
service: redis
volumes:
- redis-data:/data

redis7:
extends:
file: docker-compose.base.yml
service: redis7
volumes:
- redis7-data:/data

clickhouse:
#
# Note: please keep the default version in sync across
Expand Down Expand Up @@ -112,9 +120,12 @@ services:
OBJECT_STORAGE_SECRET_ACCESS_KEY: 'object_storage_root_password'
OBJECT_STORAGE_ENDPOINT: http://objectstorage:19000
OBJECT_STORAGE_ENABLED: true
CDP_REDIS_HOST: redis7
CDP_REDIS_PORT: 6379
depends_on:
- db
- redis
- redis7
- clickhouse
- kafka
- objectstorage
Expand Down Expand Up @@ -215,4 +226,5 @@ volumes:
caddy-data:
caddy-config:
redis-data:
redis7-data:
kafka-data:
2 changes: 1 addition & 1 deletion ee/api/feature_flag_role_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class FeatureFlagRoleAccessViewSet(
permission_classes = [FeatureFlagRoleAccessPermissions]
serializer_class = FeatureFlagRoleAccessSerializer
queryset = FeatureFlagRoleAccess.objects.select_related("feature_flag")
filter_rewrite_rules = {"team_id": "feature_flag__team_id"}
filter_rewrite_rules = {"project_id": "feature_flag__team__project_id"}

def safely_get_queryset(self, queryset):
filters = self.request.GET.dict()
Expand Down
26 changes: 8 additions & 18 deletions ee/billing/quota_limiting.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def org_quota_limited_until(
if organization.never_drop_data or trust_score == 15:
return None

team_tokens = get_team_attribute_by_quota_resource(organization, resource)
team_tokens = get_team_attribute_by_quota_resource(organization)
team_being_limited = any(x in previously_quota_limited_team_tokens for x in team_tokens)

if team_being_limited:
Expand Down Expand Up @@ -237,7 +237,7 @@ def sync_org_quota_limits(organization: Organization):
previously_quota_limited_team_tokens = list_limited_team_attributes(
resource, QuotaLimitingCaches.QUOTA_LIMITER_CACHE_KEY
)
team_attributes = get_team_attribute_by_quota_resource(organization, resource)
team_attributes = get_team_attribute_by_quota_resource(organization)
result = org_quota_limited_until(organization, resource, previously_quota_limited_team_tokens)

if result:
Expand All @@ -264,24 +264,14 @@ def sync_org_quota_limits(organization: Organization):
remove_limited_team_tokens(resource, team_attributes, QuotaLimitingCaches.QUOTA_LIMITING_SUSPENDED_KEY)


def get_team_attribute_by_quota_resource(organization: Organization, resource: QuotaResource):
if resource in [QuotaResource.EVENTS, QuotaResource.RECORDINGS]:
team_tokens: list[str] = [x for x in list(organization.teams.values_list("api_token", flat=True)) if x]
def get_team_attribute_by_quota_resource(organization: Organization):
team_tokens: list[str] = [x for x in list(organization.teams.values_list("api_token", flat=True)) if x]

if not team_tokens:
capture_exception(Exception(f"quota_limiting: No team tokens found for organization: {organization.id}"))
return
if not team_tokens:
capture_exception(Exception(f"quota_limiting: No team tokens found for organization: {organization.id}"))
return

return team_tokens

if resource == QuotaResource.ROWS_SYNCED:
team_ids: list[str] = [x for x in list(organization.teams.values_list("id", flat=True)) if x]

if not team_ids:
capture_exception(Exception(f"quota_limiting: No team ids found for organization: {organization.id}"))
return

return team_ids
return team_tokens


def set_org_usage_summary(
Expand Down
2 changes: 1 addition & 1 deletion ee/billing/test/test_billing_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def create_default_products_response(**kwargs) -> dict[str, list[Product]]:
Product(
name="Product analytics",
headline="Product analytics with autocapture",
description="A comprehensive product analytics platform built to natively work with session replay, feature flags, A/B testing, and surveys.",
description="A comprehensive product analytics platform built to natively work with session replay, feature flags, experiments, and surveys.",
usage_key="events",
image_url="https://posthog.com/images/products/product-analytics/product-analytics.png",
docs_url="https://posthog.com/docs/product-analytics",
Expand Down
6 changes: 3 additions & 3 deletions ee/billing/test/test_quota_limiting.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def test_quota_limiting_feature_flag_enabled(self, patch_feature_enabled, patch_

patch_capture.reset_mock()
# Add this org to the redis cache.
team_tokens = get_team_attribute_by_quota_resource(self.organization, QuotaResource.EVENTS)
team_tokens = get_team_attribute_by_quota_resource(self.organization)
add_limited_team_tokens(
QuotaResource.EVENTS,
{x: 1612137599 for x in team_tokens},
Expand Down Expand Up @@ -715,7 +715,7 @@ def test_sync_org_quota_limits(self):
# rows_synced uses teams, not tokens
assert sorted(
list_limited_team_attributes(QuotaResource.ROWS_SYNCED, QuotaLimitingCaches.QUOTA_LIMITER_CACHE_KEY)
) == sorted(["1337", str(self.team.pk), str(other_team.pk)])
) == sorted(["1337", str(self.team.api_token), str(other_team.api_token)])

self.organization.usage["events"]["usage"] = 80
self.organization.usage["rows_synced"]["usage"] = 36
Expand Down Expand Up @@ -748,7 +748,7 @@ def test_sync_org_quota_limits(self):
list_limited_team_attributes(
QuotaResource.ROWS_SYNCED, QuotaLimitingCaches.QUOTA_LIMITING_SUSPENDED_KEY
)
) == sorted([str(self.team.pk), str(other_team.pk)])
) == sorted([str(self.team.api_token), str(other_team.api_token)])

self.organization.usage["events"]["usage"] = 80
self.organization.usage["rows_synced"]["usage"] = 36
Expand Down
6 changes: 3 additions & 3 deletions ee/clickhouse/queries/experiments/funnel_experiment_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ def calculate_results(

if len(test_variants) >= 10:
raise ValidationError(
"Can't calculate A/B test results for more than 10 variants",
"Can't calculate experiment results for more than 10 variants",
code="too_much_data",
)

if len(test_variants) < 1:
raise ValidationError(
"Can't calculate A/B test results for less than 2 variants",
"Can't calculate experiment results for less than 2 variants",
code="no_data",
)

Expand Down Expand Up @@ -311,7 +311,7 @@ def calculate_probability_of_winning_for_each(variants: list[Variant]) -> list[P
"""
if len(variants) > 10:
raise ValidationError(
"Can't calculate A/B test results for more than 10 variants",
"Can't calculate experiment results for more than 10 variants",
code="too_much_data",
)

Expand Down
8 changes: 4 additions & 4 deletions ee/clickhouse/queries/experiments/trend_experiment_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,13 @@ def calculate_results(control_variant: Variant, test_variants: list[Variant]) ->

if len(test_variants) >= 10:
raise ValidationError(
"Can't calculate A/B test results for more than 10 variants",
"Can't calculate experiment results for more than 10 variants",
code="too_much_data",
)

if len(test_variants) < 1:
raise ValidationError(
"Can't calculate A/B test results for less than 2 variants",
"Can't calculate experiment results for less than 2 variants",
code="no_data",
)

Expand Down Expand Up @@ -413,7 +413,7 @@ def calculate_probability_of_winning_for_each(variants: list[Variant]) -> list[P

if len(variants) > 10:
raise ValidationError(
"Can't calculate A/B test results for more than 10 variants",
"Can't calculate experiment results for more than 10 variants",
code="too_much_data",
)

Expand Down Expand Up @@ -447,7 +447,7 @@ def intermediate_poisson_term(count: int, iterator: int, relative_exposure: floa

def poisson_p_value(control_count, control_exposure, test_count, test_exposure):
"""
Calculates the p-value of the A/B test.
Calculates the p-value of the experiment.
Calculations from: https://www.evanmiller.org/statistical-formulas-for-programmers.html#count_test
"""
relative_exposure = test_exposure / (control_exposure + test_exposure)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 18 additions & 3 deletions frontend/src/layout/navigation-3000/components/TopBar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,14 @@
.TopBar3000__trail {
display: flex;
align-items: center;
height: 1rem;
margin-top: calc(0.25rem * (1 - var(--breadcrumbs-compaction-rate)));
overflow: visible;

.TopBar3000:not(.TopBar3000--compact) & {
// 1rem of trail height ensures nice tight spacing in the full or transitioning state,
// but we don't want it in the compact state, as it causes title edit buttons to be cut off at top&bottom
height: 1rem;
}
}

.TopBar3000__here {
Expand All @@ -65,7 +70,12 @@
font-size: 1rem;
font-weight: 700;
line-height: 1.2;
visibility: var(--breadcrumbs-title-large-visibility);

.TopBar3000--compact & {
// It wouldn't be necessary to set visibility, but for some reason without this positioning
// of breadcrumbs becomes borked when entering title editing mode
visibility: hidden;
}

> * {
position: absolute;
Expand All @@ -90,7 +100,12 @@
&.TopBar3000__breadcrumb--here {
flex-shrink: 1;
cursor: default;
visibility: var(--breadcrumbs-title-small-visibility);

.TopBar3000--full & {
// It wouldn't be necessary to set visibility, but for some reason without this positioning
// of breadcrumbs becomes borked when entering title editing mode
visibility: hidden;
}

> * {
opacity: 1;
Expand Down
16 changes: 6 additions & 10 deletions frontend/src/layout/navigation-3000/components/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,13 @@ export function TopBar(): JSX.Element | null {

return breadcrumbs.length ? (
<div
className="TopBar3000"
className={clsx(
'TopBar3000',
effectiveCompactionRate === 0 && 'TopBar3000--full',
effectiveCompactionRate === 1 && 'TopBar3000--compact'
)}
// eslint-disable-next-line react/forbid-dom-props
style={
{
'--breadcrumbs-compaction-rate': effectiveCompactionRate,
// It wouldn't be necessary to set visibility, but for some reason without this positioning
// of breadcrumbs becomes borked when entering title editing mode
'--breadcrumbs-title-large-visibility': effectiveCompactionRate === 1 ? 'hidden' : 'visible',
'--breadcrumbs-title-small-visibility': effectiveCompactionRate === 0 ? 'hidden' : 'visible',
} as React.CSSProperties
}
style={{ '--breadcrumbs-compaction-rate': effectiveCompactionRate } as React.CSSProperties}
>
<div className="TopBar3000__content">
{mobileLayout && (
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/layout/navigation-3000/navigationLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ export const navigation3000Logic = kea<navigation3000LogicType>([
},
{
identifier: Scene.Experiments,
label: 'A/B testing',
label: 'Experiments',
icon: <IconTestTube />,
logic: isUsingSidebar ? experimentsSidebarLogic : undefined,
to: isUsingSidebar ? undefined : urls.experiments(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export const dataManagementSidebarLogic = kea<dataManagementSidebarLogicType>([
menuItems: [
{
label: 'View recordings',
to: urls.replay(ReplayTabs.Recent, {
to: urls.replay(ReplayTabs.Home, {
filter_group: {
type: FilterLogicalOperator.And,
values: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const PRODUCTS = [
icon: <IconToggle className="text-success h-5 w-5" />,
},
{
name: 'A/B testing',
name: 'Experiments',
slug: 'experiments',
icon: <IconFlask className="text-purple h-5 w-5" />,
},
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/lib/colors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { captureException } from '@sentry/react'

import { LifecycleToggle } from '~/types'

import { LemonTagType } from './lemon-ui/LemonTag'
Expand Down Expand Up @@ -39,7 +41,9 @@ export const tagColors: LemonTagType[] = [
export function getColorVar(variable: string): string {
const colorValue = getComputedStyle(document.body).getPropertyValue('--' + variable)
if (!colorValue) {
throw new Error(`Couldn't find color variable --${variable}`)
captureException(new Error(`Couldn't find color variable --${variable}`))
// Fall back to black or white depending on the theme
return document.body.getAttribute('theme') === 'light' ? '#000' : '#fff'
}
return colorValue.trim()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@
outline: 1px solid var(--primary-3000);
}

&.react-draggable::after {
// During dashboard layout editing, we need an overlay to prevent accidental interaction with card content
position: absolute;
inset: 0;
z-index: var(--z-content-overlay);
content: '';
}

.ErrorBoundary {
width: 100%;
height: 100%;
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/lib/components/Cards/handles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export function ResizeHandle1D({ orientation }: { orientation: 'horizontal' | 'v
return (
<div className={clsx('handle', orientation)}>
<svg fill="none" height="24" viewBox="0 0 16 24" width="16" xmlns="http://www.w3.org/2000/svg">
<rect fill="#fff" height="23" rx="3.5" width="15" x=".5" y=".5" />
<g fill="#5375ff">
<rect fill="var(--bg-light)" height="23" rx="3.5" width="15" x=".5" y=".5" />
<g fill="var(--primary)">
<rect height="2" rx=".25" width="2" x="5" y="5" />
<rect height="2" rx=".25" width="2" x="9" y="5" />
<rect height="2" rx=".25" width="2" x="5" y="9" />
Expand All @@ -16,7 +16,7 @@ export function ResizeHandle1D({ orientation }: { orientation: 'horizontal' | 'v
<rect height="2" rx=".25" width="2" x="5" y="13" />
<rect height="2" rx=".25" width="2" x="5" y="17" />
</g>
<rect height="23" rx="3.5" stroke="#d9d9d9" width="15" x=".5" y=".5" />
<rect height="23" rx="3.5" stroke="var(--border)" width="15" x=".5" y=".5" />
</svg>
</div>
)
Expand All @@ -27,16 +27,16 @@ export function ResizeHandle2D(): JSX.Element {
return (
<div className="handle corner">
<svg fill="none" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg">
<rect fill="#fff" height="17" rx="3.5" width="17" x=".5" y=".5" />
<g fill="#5375ff">
<rect fill="var(--bg-light)" height="17" rx="3.5" width="17" x=".5" y=".5" />
<g fill="var(--primary)">
<rect height="2" rx=".25" width="2" x="8" y="8" />
<rect height="2" rx=".25" width="2" x="8" y="12" />
<rect height="2" rx=".25" width="2" x="12" y="4" />
<rect height="2" rx=".25" width="2" x="4" y="12" />
<rect height="2" rx=".25" width="2" x="12" y="8" />
<rect height="2" rx=".25" width="2" x="12" y="12" />
</g>
<rect height="17" rx="3.5" stroke="#d9d9d9" width="17" x=".5" y=".5" />
<rect height="17" rx="3.5" stroke="var(--border)" width="17" x=".5" y=".5" />
</svg>
</div>
)
Expand Down
Loading

0 comments on commit 8544c14

Please sign in to comment.