Skip to content

Commit

Permalink
Merge branch 'master' into chore/cache-the-instance-status-page-for-s…
Browse files Browse the repository at this point in the history
…ixty-seconds
  • Loading branch information
pauldambra committed Sep 22, 2023
2 parents df236f0 + be05d73 commit ab90517
Show file tree
Hide file tree
Showing 136 changed files with 3,441 additions and 1,158 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@
!plugin-server/.prettierrc
!share/GeoLite2-City.mmdb
!hogvm/python
!unit.json
12 changes: 12 additions & 0 deletions .github/actions/build-n-cache-image/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,15 @@ runs:
platforms: linux/amd64,linux/arm64
env:
ACTIONS_ID_TOKEN_REQUEST_URL: ${{ inputs.actions-id-token-request-url }}

- name: Build unit image
id: build-unit
uses: depot/build-push-action@v1
with:
buildx-fallback: false # buildx is so slow it's better to just fail
load: ${{ inputs.load }}
file: production-unit.Dockerfile
tags: ${{ steps.emit.outputs.tag }}
platforms: linux/amd64
env:
ACTIONS_ID_TOKEN_REQUEST_URL: ${{ inputs.actions-id-token-request-url }}
12 changes: 11 additions & 1 deletion .github/workflows/container-images-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,19 @@ jobs:
with:
buildx-fallback: false # the fallback is so slow it's better to just fail
push: true
tags: posthog/posthog:latest,${{ steps.aws-ecr.outputs.registry }}/posthog-cloud:master
tags: posthog/posthog:${{ github.sha }},posthog/posthog:latest,${{ steps.aws-ecr.outputs.registry }}/posthog-cloud:master
platforms: linux/arm64,linux/amd64

- name: Build and push unit container image
id: build-unit
uses: depot/build-push-action@v1
with:
buildx-fallback: false # the fallback is so slow it's better to just fail
push: true
file: production-unit.Dockerfile
tags: ${{ steps.aws-ecr.outputs.registry }}/posthog-cloud:unit
platforms: linux/amd64

- name: get deployer token
id: deployer
uses: getsentry/action-github-app-token@v2
Expand Down
1 change: 1 addition & 0 deletions .storybook/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const LOADER_SELECTORS = [
'.LemonSkeleton',
'.LemonTableLoader',
'[aria-busy="true"]',
'[aria-label="Content is loading..."]',
'.SessionRecordingPlayer--buffering',
'.Lettermark--unknown',
]
Expand Down
1 change: 1 addition & 0 deletions bin/docker-server
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ exec gunicorn posthog.wsgi \
--worker-tmp-dir /dev/shm \
--workers=2 \
--threads=8 \
--backlog=${GUNICORN_BACKLOG:-1000} \
--worker-class=gthread \
${STATSD_HOST:+--statsd-host $STATSD_HOST:$STATSD_PORT} \
--limit-request-line=16384 $@
13 changes: 13 additions & 0 deletions bin/docker-server-unit
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
set -e

# To ensure we are able to expose metrics from multiple processes, we need to
# provide a directory for `prometheus_client` to store a shared registry.
export PROMETHEUS_MULTIPROC_DIR=$(mktemp -d)
chmod -R 777 $PROMETHEUS_MULTIPROC_DIR
trap 'rm -rf "$PROMETHEUS_MULTIPROC_DIR"' EXIT

export PROMETHEUS_METRICS_EXPORT_PORT=8001
export STATSD_PORT=${STATSD_PORT:-8125}

exec /usr/local/bin/docker-entrypoint.sh unitd --no-daemon
34 changes: 31 additions & 3 deletions ee/session_recordings/session_recording_extensions.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# EE extended functions for SessionRecording model

import gzip
import json
from datetime import timedelta
from typing import Optional
from datetime import timedelta, datetime
from typing import Optional, cast

import structlog
from django.utils import timezone
Expand All @@ -26,6 +26,34 @@

MINIMUM_AGE_FOR_RECORDING = timedelta(hours=24)

# TODO rename this...
def save_recording_with_new_content(recording: SessionRecording, content: str) -> str:
if not settings.OBJECT_STORAGE_ENABLED:
return ""

logger.info(
"re-saving recording file into 2023-08-01 LTS storage format",
recording_id=recording.session_id,
team_id=recording.team_id,
)

target_prefix = recording.build_object_storage_path("2023-08-01")

start = int(cast(datetime, recording.start_time).timestamp() * 1000)
end = int(cast(datetime, recording.end_time).timestamp() * 1000)
new_path = f"{target_prefix}/{start}-{end}"

zipped_content = gzip.compress(content.encode("utf-8"))
object_storage.write(
new_path, zipped_content, extras={"ContentType": "application/json", "ContentEncoding": "gzip"}
)

recording.storage_version = "2023-08-01"
recording.object_storage_path = target_prefix
recording.save()

return new_path


def persist_recording(recording_id: str, team_id: int) -> None:
"""Persist a recording to the S3"""
Expand Down
43 changes: 41 additions & 2 deletions ee/session_recordings/test/test_session_recording_extensions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import gzip
from datetime import timedelta, datetime, timezone
from secrets import token_urlsafe
from unittest.mock import patch
from unittest.mock import patch, MagicMock
from uuid import uuid4

from boto3 import resource
from botocore.config import Config
from freezegun import freeze_time

from ee.session_recordings.session_recording_extensions import load_persisted_recording, persist_recording
from ee.session_recordings.session_recording_extensions import (
load_persisted_recording,
persist_recording,
save_recording_with_new_content,
)
from posthog.session_recordings.models.session_recording import SessionRecording
from posthog.session_recordings.models.session_recording_playlist import SessionRecordingPlaylist
from posthog.session_recordings.models.session_recording_playlist_item import SessionRecordingPlaylistItem
Expand Down Expand Up @@ -232,3 +237,37 @@ def test_persist_tracks_correct_to_posthog(self, mock_capture):
"total_time_ms",
]:
assert mock_capture.call_args_list[0][0][2][x] > 0

@patch("ee.session_recordings.session_recording_extensions.object_storage.write")
def test_can_save_content_to_new_location(self, mock_write: MagicMock):
with self.settings(OBJECT_STORAGE_SESSION_RECORDING_BLOB_INGESTION_FOLDER=TEST_BUCKET):
session_id = f"{uuid4()}"

recording = SessionRecording.objects.create(
team=self.team,
session_id=session_id,
start_time=datetime.fromtimestamp(12345),
end_time=datetime.fromtimestamp(12346),
object_storage_path="some_starting_value",
# None, but that would trigger the persistence behavior, and we don't want that
storage_version="None",
)

new_key = save_recording_with_new_content(recording, "the new content")

recording.refresh_from_db()

expected_path = f"session_recordings_lts/team_id/{self.team.pk}/session_id/{recording.session_id}/data"
assert new_key == f"{expected_path}/12345000-12346000"

assert recording.object_storage_path == expected_path
assert recording.storage_version == "2023-08-01"

mock_write.assert_called_with(
f"{expected_path}/12345000-12346000",
gzip.compress("the new content".encode("utf-8")),
extras={
"ContentEncoding": "gzip",
"ContentType": "application/json",
},
)
Binary file modified frontend/__snapshots__/filters-action-filter--bordered.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__/filters-action-filter--funnel-like.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__/filters-action-filter--single-filter.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__/filters-action-filter--sortable.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__/filters-action-filter--standard.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-b.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-i.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.
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-line-edit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-line.png
Binary file modified frontend/__snapshots__/scenes-app-surveys--new-survey.png
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { LemonSnack } from 'lib/lemon-ui/LemonSnack/LemonSnack'
import clsx from 'clsx'
import { useState } from 'react'

import { DndContext, closestCenter } from '@dnd-kit/core'
import { DndContext, PointerSensor, closestCenter, useSensor, useSensors } from '@dnd-kit/core'
import { useSortable, SortableContext, horizontalListSortingStrategy } from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { restrictToHorizontalAxis } from '@dnd-kit/modifiers'
import { restrictToHorizontalAxis, restrictToParentElement } from '@dnd-kit/modifiers'

export interface PersonPropertySelectProps {
addText: string
Expand Down Expand Up @@ -53,6 +53,7 @@ export const PersonPropertySelect = ({
sortable = false,
}: PersonPropertySelectProps): JSX.Element => {
const [open, setOpen] = useState<boolean>(false)
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 1 } }))

const handleChange = (name: string): void => {
onChange(Array.from(new Set(selectedProperties.concat([name]))))
Expand All @@ -71,35 +72,38 @@ export const PersonPropertySelect = ({

return (
<div className="flex items-center flex-wrap gap-2">
<DndContext
onDragEnd={({ active, over }) => {
if (over && active.id !== over.id) {
handleSort({
oldIndex: selectedProperties.indexOf(active.id.toString()),
newIndex: selectedProperties.indexOf(over.id.toString()),
})
}
}}
collisionDetection={closestCenter}
modifiers={[restrictToHorizontalAxis]}
>
<SortableContext
disabled={!sortable}
items={selectedProperties}
strategy={horizontalListSortingStrategy}
{selectedProperties.length > 0 && (
<DndContext
onDragEnd={({ active, over }) => {
if (over && active.id !== over.id) {
handleSort({
oldIndex: selectedProperties.indexOf(active.id.toString()),
newIndex: selectedProperties.indexOf(over.id.toString()),
})
}
}}
sensors={sensors}
collisionDetection={closestCenter}
modifiers={[restrictToHorizontalAxis, restrictToParentElement]}
>
<div className="flex items-center gap-2">
{selectedProperties.map((value) => (
<SortableProperty
key={`item-${value}`}
name={value}
onRemove={handleRemove}
sortable={sortable}
/>
))}
</div>
</SortableContext>
</DndContext>
<SortableContext
disabled={!sortable}
items={selectedProperties}
strategy={horizontalListSortingStrategy}
>
<div className="flex items-center gap-2">
{selectedProperties.map((value) => (
<SortableProperty
key={`item-${value}`}
name={value}
onRemove={handleRemove}
sortable={sortable}
/>
))}
</div>
</SortableContext>
</DndContext>
)}

<Popover
visible={open}
Expand Down
51 changes: 20 additions & 31 deletions frontend/src/lib/components/TZLabel/index.scss
Original file line number Diff line number Diff line change
@@ -1,38 +1,27 @@
.tz-label {
white-space: nowrap;
.TZLabelPopover {
.TZLabelPopover__row {
display: flex;
margin-top: 0.5rem;

&.tz-label--hoverable {
border-bottom: 1px dotted var(--border-bold);
cursor: default;
}
}
> :nth-child(1) {
font-weight: bold;
color: var(--primary-alt);
margin-right: 6px;
}

.tz-label-popover {
.divider {
margin-right: -4px;
margin-left: -4px;
border-bottom: 1px solid var(--border-light);
}
.timezones {
.timezone {
display: flex;
margin-top: 8px;
.name {
font-weight: bold;
color: var(--primary-alt);
margin-right: 6px;
}
> :nth-child(2) {
color: var(--muted);
margin-right: 16px;
flex-grow: 1;
font-style: italic;
}

.scope {
color: var(--muted);
margin-right: 16px;
flex-grow: 1;
font-style: italic;
}
> :nth-child(3) {
min-width: 10rem;
text-align: right;

.time {
min-width: 170px;
text-align: right;
.TZLabelPopover--seconds & {
min-width: 12rem;
}
}
}
Expand Down
Loading

0 comments on commit ab90517

Please sign in to comment.