Skip to content

Commit

Permalink
Merge branch 'PostHog:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Arun-chaitanya authored Jul 26, 2023
2 parents d60f811 + 79c48e9 commit 7471be0
Show file tree
Hide file tree
Showing 190 changed files with 5,354 additions and 3,652 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/performance_issue_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ labels: performance
## Environment

- [ ] PostHog Cloud
- [ ] self-hosted PostHog, version/commit: _please provide_
- [ ] PostHog self-hosted with Kubernetes (deprecated, see ["Sunsetting Kubernetes support"](https://posthog.com/blog/sunsetting-helm-support-posthog)), version/commit: [please provide]

## Additional context

Expand Down
3 changes: 2 additions & 1 deletion .run/PostHog.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<env name="SESSION_RECORDING_KAFKA_HOSTS" value="localhost" />
<env name="SESSION_RECORDING_KAFKA_MAX_REQUEST_SIZE_BYTES" value="524288" />
<env name="SKIP_SERVICE_VERSION_REQUIREMENTS" value="1" />
<env name="PYDEVD_USE_CYTHON" value="NO" />
</envs>
<option name="SDK_HOME" value="$PROJECT_DIR$/env/bin/python" />
<option name="SDK_NAME" value="Python 3.10 (posthog)" />
Expand Down Expand Up @@ -46,4 +47,4 @@
<option name="customRunCommand" value="" />
<method v="2" />
</configuration>
</component>
</component>
4 changes: 1 addition & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Changelog

Updates to the PostHog project can be found at [https://posthog.com/blog/categories/product-updates](https://posthog.com/blog/categories/product-updates). Each release of PostHog self-hosted is accompanied by an "Array" blog post which details all relevant changes and any deprecation or warning notices.

Find the latest Array blog post in the [Product updates](https://posthog.com/blog/categories/product-updates) section of our blog.
Updates to the PostHog project can be found on [https://posthog.com/changelog](our changelog).
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ You can deploy a hobby instance in one line on Linux with Docker (recommended 4G

Open source deployments should scale to approximately 100k events per month, after which we recommend migrating to a PostHog Cloud instance. See our [docs for more info and limitations](https://posthog.com/docs/self-host/open-source/deployment).

PostHog has [sunset support for self-hosted K8s deployments](https://posthog.com/blog/sunsetting-helm-support-posthog).

## Features
![ui-demo](https://user-images.githubusercontent.com/85295485/144591577-fe97e4a5-5631-4a60-a684-45caf421507f.gif)
<p align="center">Want to find out more? <a href="https://posthog.com/book-a-demo">Request a demo!</a>
Expand Down
3 changes: 0 additions & 3 deletions docker-compose.base.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#
# docker-compose base file used for local development, hobby deploys, and other compose use cases.
#
# If you are looking at self-hosted deployment options check
# https://posthog.com/docs/self-host
#

services:
db:
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.dev-full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# For more info, see:
# https://posthog.com/handbook/engineering/developing-locally
#
# If you are looking at self-hosted deployment options check
# https://posthog.com/docs/self-host
# PostHog has sunset support for self-hosted K8s deployments.
# See: https://posthog.com/blog/sunsetting-helm-support-posthog
#

services:
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# For more info, see:
# https://posthog.com/handbook/engineering/developing-locally
#
# If you are looking at self-hosted deployment options check
# https://posthog.com/docs/self-host
# PostHog has sunset support for self-hosted K8s deployments.
# See: https://posthog.com/blog/sunsetting-helm-support-posthog
#

services:
Expand Down
3 changes: 3 additions & 0 deletions docker-compose.hobby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# Please take a look at https://posthog.com/docs/self-host/deploy/hobby
# for more info.
#
# PostHog has sunset support for self-hosted K8s deployments.
# See: https://posthog.com/blog/sunsetting-helm-support-posthog
#

services:
db:
Expand Down
2 changes: 1 addition & 1 deletion ee/api/test/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class LicensedTestMixin:

def license_required_response(
self,
message: str = "This feature is part of the premium PostHog offering. To use it, get a self-hosted license: https://license.posthog.com",
message: str = "This feature is part of the premium PostHog offering. Self-hosted licenses are no longer available for purchase. Please contact sales@posthog.com to discuss options.",
) -> Dict[str, Optional[str]]:
return {"type": "server_error", "code": "payment_required", "detail": message, "attr": None}

Expand Down
4 changes: 2 additions & 2 deletions ee/api/test/test_event_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def test_update_event_without_license(self):
f"/api/projects/@current/event_definitions/{str(event.id)}", data={"description": "test"}
)
self.assertEqual(response.status_code, status.HTTP_402_PAYMENT_REQUIRED)
self.assertIn("This feature is part of the premium PostHog offering.", response.json()["detail"])
self.assertIn("Self-hosted licenses are no longer available for purchase.", response.json()["detail"])

def test_with_expired_license(self):
super(LicenseManager, cast(LicenseManager, License.objects)).create(
Expand All @@ -222,7 +222,7 @@ def test_with_expired_license(self):
f"/api/projects/@current/event_definitions/{str(event.id)}", data={"description": "test"}
)
self.assertEqual(response.status_code, status.HTTP_402_PAYMENT_REQUIRED)
self.assertIn("This feature is part of the premium PostHog offering.", response.json()["detail"])
self.assertIn("Self-hosted licenses are no longer available for purchase.", response.json()["detail"])

def test_can_get_event_verification_data(self):
super(LicenseManager, cast(LicenseManager, License.objects)).create(
Expand Down
8 changes: 4 additions & 4 deletions ee/api/test/test_property_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,15 @@ def test_update_property_description_without_license(self):
f"/api/projects/@current/property_definitions/{str(property.id)}/", data={"description": "test"}
)
self.assertEqual(response.status_code, status.HTTP_402_PAYMENT_REQUIRED)
self.assertIn("This feature is part of the premium PostHog offering.", response.json()["detail"])
self.assertIn("Self-hosted licenses are no longer available for purchase.", response.json()["detail"])

def test_update_property_tags_without_license(self):
property = EnterprisePropertyDefinition.objects.create(team=self.team, name="enterprise property")
response = self.client.patch(
f"/api/projects/@current/property_definitions/{str(property.id)}/", data={"tags": ["test"]}
)
self.assertEqual(response.status_code, status.HTTP_402_PAYMENT_REQUIRED)
self.assertIn("This feature is part of the premium PostHog offering.", response.json()["detail"])
self.assertIn("Self-hosted licenses are no longer available for purchase.", response.json()["detail"])

def test_can_update_property_type_without_license(self):
property = EnterprisePropertyDefinition.objects.create(team=self.team, name="enterprise property")
Expand All @@ -239,7 +239,7 @@ def test_cannot_update_more_than_property_type_without_license(self):
data={"property_type": "DateTime", "tags": ["test"]},
)
self.assertEqual(response.status_code, status.HTTP_402_PAYMENT_REQUIRED)
self.assertIn("This feature is part of the premium PostHog offering.", response.json()["detail"])
self.assertIn("Self-hosted licenses are no longer available for purchase.", response.json()["detail"])

def test_with_expired_license(self):
super(LicenseManager, cast(LicenseManager, License.objects)).create(
Expand All @@ -250,7 +250,7 @@ def test_with_expired_license(self):
f"/api/projects/@current/property_definitions/{str(property.id)}/", data={"description": "test"}
)
self.assertEqual(response.status_code, status.HTTP_402_PAYMENT_REQUIRED)
self.assertIn("This feature is part of the premium PostHog offering.", response.json()["detail"])
self.assertIn("Self-hosted licenses are no longer available for purchase.", response.json()["detail"])

def test_filter_property_definitions(self):
super(LicenseManager, cast(LicenseManager, License.objects)).create(
Expand Down
4 changes: 2 additions & 2 deletions ee/billing/quota_limiting.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from posthog.models.team.team import Team
from posthog.redis import get_client
from posthog.tasks.usage_report import (
get_teams_with_event_count_in_period,
get_teams_with_billable_event_count_in_period,
get_teams_with_recording_count_in_period,
convert_team_usage_rows_to_dict,
)
Expand Down Expand Up @@ -147,7 +147,7 @@ def update_all_org_billing_quotas(dry_run: bool = False) -> Dict[str, Dict[str,
# Clickhouse is good at counting things so we count across all teams rather than doing it one by one
all_data = dict(
teams_with_event_count_in_period=convert_team_usage_rows_to_dict(
get_teams_with_event_count_in_period(period_start, period_end)
get_teams_with_billable_event_count_in_period(period_start, period_end)
),
teams_with_recording_count_in_period=convert_team_usage_rows_to_dict(
get_teams_with_recording_count_in_period(period_start, period_end)
Expand Down
Binary file modified frontend/__snapshots__/filters-taxonomic-filter--actions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-icons--shelf-s.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-lemon-button--loading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-lemon-row--loading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-spinner--as-overlay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-spinner--default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-spinner--in-buttons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed frontend/__snapshots__/lemon-ui-spinner--monocolor.png
Binary file not shown.
Binary file modified frontend/__snapshots__/lemon-ui-spinner--sizes.png
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.
Binary file modified frontend/__snapshots__/scenes-app-dashboards--create-template.png
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.
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.
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-area-edit.png
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.
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-bar-edit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-line-edit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-number-edit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-pie-edit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-table-edit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-value-edit.png
Binary file modified frontend/__snapshots__/scenes-other-preflight--preflight.png
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function Breadcrumbs(): JSX.Element | null {
{/* TODO: These buttons below are hardcoded right now, scene-based system coming in the next PR */}
<LemonButton className="Breadcrumbs3000__more" icon={<IconEllipsisVertical />} size="small" />
<div className="Breadcrumbs3000__actions">
<FlaggedFeature flag={FEATURE_FLAGS.NOTEBOOKS} match={true}>
<FlaggedFeature flag={FEATURE_FLAGS.NOTEBOOKS}>
<NotebookButton />
</FlaggedFeature>
<NewInsightButton dataAttr="project-home-new-insight" />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/layout/navigation-3000/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ function SidebarSearchBar({
// Show a loading spinner when search term is being debounced or just loading data
prefix={
(localSearchTerm || searchTerm) && (localSearchTerm !== searchTerm || isLoading) ? (
<Spinner monocolor />
<Spinner textColored />
) : null
}
placeholder="Search..."
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/layout/navigation/TopBar/SitePopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ export function SitePopoverOverlay(): JSX.Element {
<InstanceSettings />
</SitePopoverSection>
)}
<FlaggedFeature flag={FEATURE_FLAGS.EARLY_ACCESS_FEATURE_SITE_BUTTON} match>
<FlaggedFeature flag={FEATURE_FLAGS.EARLY_ACCESS_FEATURE_SITE_BUTTON}>
<SitePopoverSection>
<FeaturePreviewsButton />
</SitePopoverSection>
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,17 @@ const api = {
.withAction('snapshots')
.withQueryString(toParams({ source: 'blob', blob_key: blobKey, version: '2' }))
.getResponse()

try {
const textLines = await response.text()

if (textLines) {
return textLines.split('\n')
}
} catch (e) {
// Must be gzipped
}

const contentBuffer = new Uint8Array(await response.arrayBuffer())
return strFromU8(decompressSync(contentBuffer)).trim().split('\n')
},
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/lib/components/FlaggedFeature.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@ import { featureFlagLogic } from 'lib/logic/featureFlagLogic'

export type PostHogFeatureProps = {
flag: FeatureFlagKey
/** What specific state or variant of feature flag needs to be active. */
match?: string | boolean
/** Rendered when the flag state/variant matches. */
children: React.ReactNode | ((payload: any) => React.ReactNode)
/** Rendered when the flag state/variant doesn't match. */
fallback?: React.ReactNode
}

export function FlaggedFeature({ flag, match, children }: PostHogFeatureProps): JSX.Element | null {
export function FlaggedFeature({ flag, match, children, fallback }: PostHogFeatureProps): JSX.Element | null {
const { featureFlags } = useValues(featureFlagLogic)

const flagValue = featureFlags[flag] || false
const doesFlagMatch = match === undefined ? !!flagValue : flagValue === match

if (match === undefined || flagValue === match) {
if (doesFlagMatch) {
return typeof children === 'function' ? children(flagValue) : children
} else if (fallback) {
return <>{fallback}</>
}

return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ export function HedgehogBuddy({
</div>
))}

<FlaggedFeature flag={FEATURE_FLAGS.HEDGEHOG_MODE_DEBUG} match>
<FlaggedFeature flag={FEATURE_FLAGS.HEDGEHOG_MODE_DEBUG}>
<>
<LemonDivider />
<div className="flex gap-2 my-2 overflow-y-auto">
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ export const FEATURE_FLAGS = {
ARTIFICIAL_HOG: 'artificial-hog', // owner: @Twixes
REFERRAL_SOURCE_SELECT: 'referral-source-select', // owner: @raquelmsmith
SESSION_RECORDING_PLAYER_PREVIEW: 'session-recording-player-preview', // owner: #team-monitoring
SESSION_RECORDING_TEST_ACCOUNTS_FILTER: 'session-recording-test-accounts-filter', // owner: #team-monitoring
SESSION_RECORDING_SHOW_FILTERS_BY_DEFAULT: 'session-recording-show-filters-by-default', // owner: #team-monitoring
} as const
export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]

Expand Down
14 changes: 9 additions & 5 deletions frontend/src/lib/lemon-ui/LemonButton/LemonButton.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@
user-select: none;
-webkit-appearance: none !important; // Important as this gets overridden by Ant styles...

&[aria-disabled='true'] {
opacity: var(--opacity-disabled);
cursor: not-allowed;
}

.LemonButton__content {
flex: 1;
line-height: initial;
display: flex;
align-items: center;
}

&[aria-disabled='true']:not(.LemonButton--loading) {
cursor: not-allowed;
opacity: var(--opacity-disabled);
}

&.LemonButton--loading {
cursor: default;
}

&.LemonButton--full-width {
width: 100%;
padding-left: 0.5rem;
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib/lemon-ui/LemonButton/LemonButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const LemonButton: React.FunctionComponent<LemonButtonProps & React.RefAt
}
}
if (loading) {
icon = <Spinner monocolor />
icon = <Spinner textColored />
disabled = true // Cannot interact with a loading button
}

Expand Down Expand Up @@ -160,6 +160,7 @@ export const LemonButton: React.FunctionComponent<LemonButtonProps & React.RefAt
'LemonButton',
`LemonButton--${type}`,
`LemonButton--status-${status}`,
loading && `LemonButton--loading`,
noPadding && `LemonButton--no-padding`,
size && `LemonButton--${size}`,
active && 'LemonButton--active',
Expand Down
17 changes: 6 additions & 11 deletions frontend/src/lib/lemon-ui/LemonInput/LemonInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface LemonInputPropsBase
transparentBackground?: boolean
/** Size of the element. Default: `'medium'`. */
size?: 'small' | 'medium'
onPressEnter?: (event: React.KeyboardEvent<HTMLInputElement>) => void
'data-attr'?: string
'aria-label'?: string
}
Expand All @@ -50,7 +51,6 @@ export interface LemonInputPropsText extends LemonInputPropsBase {
value?: string
defaultValue?: string
onChange?: (newValue: string) => void
onPressEnter?: (newValue: string) => void
}

export interface LemonInputPropsNumber
Expand All @@ -60,7 +60,6 @@ export interface LemonInputPropsNumber
value?: number
defaultValue?: number
onChange?: (newValue: number | undefined) => void
onPressEnter?: (newValue: number | undefined) => void
}

export type LemonInputProps = LemonInputPropsText | LemonInputPropsNumber
Expand Down Expand Up @@ -152,15 +151,6 @@ export const LemonInput = React.forwardRef<HTMLInputElement, LemonInputProps>(fu
className
)}
aria-disabled={textProps.disabled}
onKeyDown={(event) => {
if (onPressEnter && event.key === 'Enter') {
if (type === 'number') {
onPressEnter(value ?? 0)
} else {
onPressEnter(value?.toString() ?? '')
}
}
}}
onClick={() => focus()}
>
{prefix}
Expand All @@ -186,6 +176,11 @@ export const LemonInput = React.forwardRef<HTMLInputElement, LemonInputProps>(fu
setFocused(false)
onBlur?.(event)
}}
onKeyDown={(event) => {
if (onPressEnter && event.key === 'Enter') {
onPressEnter(event)
}
}}
{...textProps}
/>
{suffix}
Expand Down
Loading

0 comments on commit 7471be0

Please sign in to comment.