Skip to content

Commit

Permalink
Merge branch 'master' into dw-data-warehouse-experiment-filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
EDsCODE authored Mar 22, 2024
2 parents 35f90c1 + 36d1dd0 commit 0fd54db
Show file tree
Hide file tree
Showing 50 changed files with 1,863 additions and 616 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@
"x": 66,
"y": 556
}
},
{
"parentId": 209272202,
"wireframe": {
"id": 52129787123,
"type": "text"
}
}
],
"removes": [
Expand Down
162 changes: 162 additions & 0 deletions ee/frontend/mobile-replay/__snapshots__/transform.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,147 @@ exports[`replay/transform transform can convert images 1`] = `
]
`;

exports[`replay/transform transform can convert invalid text wireframe 1`] = `
[
{
"data": {
"height": 600,
"href": "",
"width": 300,
},
"timestamp": 1,
"type": 4,
},
{
"data": {
"initialOffset": {
"left": 0,
"top": 0,
},
"node": {
"childNodes": [
{
"id": 2,
"name": "html",
"publicId": "",
"systemId": "",
"type": 1,
},
{
"attributes": {
"data-rrweb-id": 3,
"style": "height: 100vh; width: 100vw;",
},
"childNodes": [
{
"attributes": {
"data-rrweb-id": 4,
},
"childNodes": [
{
"attributes": {
"type": "text/css",
},
"childNodes": [
{
"id": 102,
"textContent": "
body {
margin: unset;
}
input, button, select, textarea {
font: inherit;
margin: 0;
padding: 0;
border: 0;
outline: 0;
background: transparent;
padding-block: 0 !important;
}
.input:focus {
outline: none;
}
img {
border-style: none;
}
",
"type": 3,
},
],
"id": 101,
"tagName": "style",
"type": 2,
},
],
"id": 4,
"tagName": "head",
"type": 2,
},
{
"attributes": {
"data-rrweb-id": 5,
"style": "height: 100vh; width: 100vw;",
},
"childNodes": [
{
"attributes": {
"data-rrweb-id": 12345,
"style": "border-width: 4px;border-radius: 10px;border-color: #ee3ee4;border-style: solid;color: #ee3ee4;width: 100px;height: 30px;position: fixed;left: 11px;top: 12px;overflow:hidden;white-space:normal;",
},
"childNodes": [],
"id": 12345,
"tagName": "div",
"type": 2,
},
{
"attributes": {
"data-render-reason": "a fixed placeholder to contain the keyboard in the correct stacking position",
"data-rrweb-id": 9,
},
"childNodes": [],
"id": 9,
"tagName": "div",
"type": 2,
},
{
"attributes": {
"data-rrweb-id": 7,
},
"childNodes": [],
"id": 7,
"tagName": "div",
"type": 2,
},
{
"attributes": {
"data-rrweb-id": 11,
},
"childNodes": [],
"id": 11,
"tagName": "div",
"type": 2,
},
],
"id": 5,
"tagName": "body",
"type": 2,
},
],
"id": 3,
"tagName": "html",
"type": 2,
},
],
"id": 1,
"type": 0,
},
},
"timestamp": 1,
"type": 2,
},
]
`;

exports[`replay/transform transform can convert navigation bar 1`] = `
[
{
Expand Down Expand Up @@ -1453,6 +1594,20 @@ exports[`replay/transform transform incremental mutations de-duplicate the tree
},
"parentId": 52129787,
},
{
"nextId": null,
"node": {
"attributes": {
"data-rrweb-id": 52129787123,
"style": "position: fixed;left: 0px;top: 0px;overflow:hidden;white-space:normal;",
},
"childNodes": [],
"id": 52129787123,
"tagName": "div",
"type": 2,
},
"parentId": 209272202,
},
],
"attributes": [],
"removes": [
Expand Down Expand Up @@ -1689,6 +1844,13 @@ AAAAAAAAAAAAAAAAAAAAAAAAgCN/AW0xMqHnNQceAAAAAElFTkSuQmCC
"y": 556,
},
},
{
"parentId": 209272202,
"wireframe": {
"id": 52129787123,
"type": "text",
},
},
],
"removes": [
{
Expand Down
37 changes: 37 additions & 0 deletions ee/frontend/mobile-replay/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,43 @@ describe('replay/transform', () => {
expect(converted).toMatchSnapshot()
})

test('can convert invalid text wireframe', () => {
const converted = posthogEEModule.mobileReplay?.transformToWeb([
{
data: {
width: 300,
height: 600,
},
timestamp: 1,
type: 4,
},
{
type: 2,
data: {
wireframes: [
{
id: 12345,
type: 'text',
x: 11,
y: 12,
width: 100,
height: 30,
style: {
color: '#ee3ee4',
borderColor: '#ee3ee4',
borderWidth: '4',
borderRadius: '10px',
},
// text property is missing
},
],
},
timestamp: 1,
},
])
expect(converted).toMatchSnapshot()
})

test('can set background image to base64 png', () => {
const converted = posthogEEModule.mobileReplay?.transformToWeb([
{
Expand Down
26 changes: 17 additions & 9 deletions ee/frontend/mobile-replay/transformer/transformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ export function _isPositiveInteger(id: unknown): id is number {
return typeof id === 'number' && id > 0 && id % 1 === 0
}

function _isNullish(x: unknown): x is null | undefined {
return x === null || x === undefined
}

function isRemovedNodeMutation(x: addedNodeMutation | removedNodeMutation): x is removedNodeMutation {
return isObject(x) && 'id' in x
}
Expand Down Expand Up @@ -218,6 +222,17 @@ function makeTextElement(
// because we might have to style the text, we always wrap it in a div
// and apply styles to that
const id = context.idSequence.next().value

const childNodes = [...children]
if (!_isNullish(wireframe.text)) {
childNodes.unshift({
type: NodeType.Text,
textContent: wireframe.text,
// since the text node is wrapped, we assign it a synthetic id
id,
})
}

return {
result: {
type: NodeType.Element,
Expand All @@ -227,15 +242,7 @@ function makeTextElement(
'data-rrweb-id': wireframe.id,
},
id: wireframe.id,
childNodes: [
{
type: NodeType.Text,
textContent: wireframe.text,
// since the text node is wrapped, we assign it a synthetic id
id: id,
},
...children,
],
childNodes,
},
context,
}
Expand Down Expand Up @@ -983,6 +990,7 @@ function isMobileIncrementalSnapshotEvent(x: unknown): x is MobileIncrementalSna

function makeIncrementalAdd(add: MobileNodeMutation, context: ConversionContext): addedNodeMutation[] | null {
const converted = convertWireframe(add.wireframe, context)

if (!converted) {
return null
}
Expand Down
15 changes: 12 additions & 3 deletions ee/session_recordings/ai/error_clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pandas as pd
import numpy as np
from posthog.session_recordings.models.session_recording_event import SessionRecordingViewed
from datetime import date

CLUSTER_REPLAY_ERRORS_TIMING = Histogram(
"posthog_session_recordings_cluster_replay_errors",
Expand All @@ -30,7 +31,7 @@ def error_clustering(team: Team, user: User):
if not results:
return []

df = pd.DataFrame(results, columns=["session_id", "input", "embeddings"])
df = pd.DataFrame(results, columns=["session_id", "error", "embeddings", "timestamp"])

df["cluster"] = cluster_embeddings(df["embeddings"].tolist())

Expand All @@ -42,7 +43,7 @@ def error_clustering(team: Team, user: User):
def fetch_error_embeddings(team_id: int):
query = """
SELECT
session_id, input, embeddings
session_id, input, embeddings, generation_timestamp
FROM
session_replay_embeddings
WHERE
Expand Down Expand Up @@ -76,13 +77,21 @@ def construct_response(df: pd.DataFrame, team: Team, user: User):
clusters = []
for cluster, rows in df.groupby("cluster"):
session_ids = rows["session_id"].unique()
sample = rows.sample(n=1)[["session_id", "input"]].rename(columns={"input": "error"}).to_dict("records")[0]
sample = rows.sample(n=1)[["session_id", "error"]].to_dict("records")[0]

date_series = (
df.groupby([df["timestamp"].dt.date])
.size()
.reindex(pd.date_range(end=date.today(), periods=7), fill_value=0)
)
sparkline = dict(zip(date_series.index.astype(str), date_series))
clusters.append(
{
"cluster": cluster,
"sample": sample.get("error"),
"session_ids": np.random.choice(session_ids, size=DBSCAN_MIN_SAMPLES - 1),
"occurrences": rows.size,
"sparkline": sparkline,
"unique_sessions": len(session_ids),
"viewed": len(np.intersect1d(session_ids, viewed_session_ids, assume_unique=True)),
}
Expand Down
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-other-signup--cloud--light.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-other-signup--self-hosted--light.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.
2 changes: 1 addition & 1 deletion frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2567,7 +2567,7 @@
"type": "string"
},
"personsOnEventsMode": {
"enum": ["disabled", "v1_enabled", "v1_mixed", "v2_enabled"],
"enum": ["disabled", "v1_enabled", "v1_mixed", "v2_enabled", "v3_enabled"],
"type": "string"
}
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export interface DataNode extends Node {

/** HogQL Query Options are automatically set per team. However, they can be overriden in the query. */
export interface HogQLQueryModifiers {
personsOnEventsMode?: 'disabled' | 'v1_enabled' | 'v1_mixed' | 'v2_enabled'
personsOnEventsMode?: 'disabled' | 'v1_enabled' | 'v1_mixed' | 'v2_enabled' | 'v3_enabled'
personsArgMaxVersion?: 'auto' | 'v1' | 'v2'
inCohortVia?: 'auto' | 'leftjoin' | 'subquery' | 'leftjoin_conjoined'
materializationMode?: 'auto' | 'legacy_null_as_string' | 'legacy_null_as_null' | 'disabled'
Expand Down
8 changes: 2 additions & 6 deletions frontend/src/scenes/authentication/signup/SignupContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,8 @@ export function SignupContainer(): JSX.Element | null {
const { user } = useValues(userLogic)

const footerHighlights = {
cloud: ['Hosted & managed by PostHog', 'Pay per event, cancel anytime', 'Community, Slack & email support'],
selfHosted: [
'Fully featured product, unlimited events',
'Data in your own infrastructure',
'Community, Slack & email support',
],
cloud: ['Hosted & managed by PostHog', 'Pay per event, cancel anytime', 'Fast and reliable support'],
selfHosted: ['Fully featured product, unlimited events', 'Data in your own infrastructure', 'Community forum'],
}

return !user ? (
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/scenes/batch_exports/BatchExportEditForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,15 @@ export function BatchExportsEditFields({
]}
/>
</LemonField>

<LemonField name="file_format" label="Format" className="flex-1">
<LemonSelect
options={[
{ value: 'JSONLines', label: 'JSON lines' },
{ value: 'Parquet', label: 'Apache Parquet' },
]}
/>
</LemonField>
</div>

<div className="flex gap-4">
Expand Down
Loading

0 comments on commit 0fd54db

Please sign in to comment.